与奥卡姆剃刀原理一致,从简单入手往往能带来最深刻的见解,尤其是在构建预测模型时。在这篇文章中,我们将使用埃姆斯住房数据集,首先找出那些自身就表现出色的关键特征。然后,我们将一步步地叠加这些见解,观察它们的组合效应如何增强我们准确预测的能力。随着深入研究,我们将利用序列特征选择器(SFS)的力量,筛选复杂性并突出最佳特征组合。这种系统方法将引导我们找到“最佳平衡点”——一个和谐的组合,其中选定的特征能在不过度加载不必要数据的情况下,最大限度地提高模型预测精度。
通过我的书《进阶数据科学》启动您的项目。它提供了带有可运行代码的自学教程。
让我们开始吧。

在具有数值特征的线性回归中寻找最佳点
图片来源:Joanna Kosinska。部分权利保留。
概述
这篇博文分为三部分;它们是:
- 从单一特征到集体影响
- 深入探索SFS:组合的力量
- 寻找预测的“最佳平衡点”
从个体优势到集体影响
我们的第一步是识别埃姆斯数据集中众多可用特征中,哪些自身就能作为强大的预测因子脱颖而出。我们转向简单的线性回归模型,每个模型都专门用于根据其对房价的预测能力确定的顶级独立特征之一。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# 加载必要的库和Ames数据集 from sklearn.model_selection import cross_val_score 来自 sklearn.linear_model 导入 LinearRegression import pandas as pd Ames = pd.read_csv("Ames.csv").select_dtypes(include=["int64", "float64"]) Ames.dropna(axis=1, inplace=True) X = Ames.drop("SalePrice", axis=1) y = Ames["SalePrice"] # 初始化线性回归模型 模型 = LinearRegression() # 准备收集特征分数 feature_scores = {} # 通过交叉验证评估每个特征 for feature in X.columns: X_single = X[[feature]] cv_scores = cross_val_score(model, X_single, y) feature_scores[feature] = cv_scores.mean() # 根据平均CV R²分数识别前5个特征 sorted_features = sorted(feature_scores.items(), key=lambda item: item[1], reverse=True) top_5 = sorted_features[0:5] # 显示前5个特征及其各自的性能 for feature, score in top_5: print(f"特征: {feature}, 平均CV R²: {score:.4f}") |
这将输出可在简单线性回归中单独使用的前5个特征
1 2 3 4 5 |
特征:OverallQual,平均CV R²:0.6183 特征:GrLivArea,平均CV R²:0.5127 特征:1stFlrSF,平均CV R²:0.3957 特征:YearBuilt,平均CV R²:0.2852 特征:FullBath,平均CV R²:0.2790 |
好奇心驱使我们进一步思考:如果我们把这些顶级特征组合成一个多元线性回归模型,它们的集体力量会超越各自的贡献吗?
1 2 3 4 5 6 7 8 9 10 11 |
# 提取前5个特征用于我们的多元线性回归 top_features = [feature for feature, score in top_5] # 用前5个特征构建模型 X_top = Ames[top_features] # 通过交叉验证评估模型 cv_scores_mlr = cross_val_score(model, X_top, y, cv=5, scoring="r2") mean_mlr_score = cv_scores_mlr.mean() print(f"多元线性回归模型的平均CV R²分数: {mean_mlr_score:.4f}") |
初步结果令人鼓舞;每个特征确实有其优势。然而,当它们组合成一个多元回归模型时,我们观察到一个“不错的”改进——这证明了房价预测的复杂性。
1 |
多元线性回归模型的平均CV R²分数:0.8003 |
这个结果暗示着尚未开发的潜力:是否有更具策略性的方法来选择和组合特征,以实现更高的预测准确性?
想开始学习进阶数据科学吗?
立即参加我的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
深入探索SFS:组合的力量
随着我们将序列特征选择器(SFS)的使用从n=1扩展到n=5,一个重要的概念开始发挥作用:组合的力量。让我们在上述代码的基础上进行说明。
1 2 3 4 5 6 7 8 9 10 11 |
# 执行n=5的序列特征选择器,并基于上述代码进行构建 from sklearn.feature_selection import SequentialFeatureSelector sfs = SequentialFeatureSelector(model, n_features_to_select=5) sfs.fit(X, y) selected_features = X.columns[sfs.get_support()].to_list() print(f"SFS选择的特征: {selected_features}") scores = cross_val_score(model, Ames[selected_features], y) print(f"使用SFS选择5个特征的平均CV R²分数: {scores.mean():.4f}") |
选择n=5并不仅仅意味着选择五个最佳独立特征。相反,它是关于识别那组在共同使用时能够优化模型预测能力的五个特征。
1 2 |
SFS选择的特征:['GrLivArea', 'OverallQual', 'YearBuilt', '1stFlrSF', 'KitchenAbvGr'] 使用SFS选择5个特征的平均CV R²分数:0.8056 |
将此结果与根据其独立预测能力选择的前五个特征进行比较时,结果尤其具有启发性。在SFS选择中,“FullBath”(未被SFS选择)被“KitchenAbvGr”取代。这种差异凸显了特征选择的一个基本原则:**组合才是关键**。SFS不仅寻找强大的独立预测因子;它还寻找能够协同作用的最佳特征。这可能意味着选择一个自身并不排在前列的特征,但当与其他特征组合时,它能提高模型的准确性。
如果你想知道为什么会这样,组合中选择的特征应该是互补的,而不是相互关联的。通过这种方式,每个新特征都为预测器提供了新的信息,而不是与已知信息重复。
寻找预测的“最佳平衡点”
通往最佳特征选择的旅程始于将我们的模型推向极限。通过最初考虑最大可能数量的特征,我们对模型性能如何随着每个特征的添加而演变有了全面的了解。这种可视化作为我们的起点,突出了模型可预测性的收益递减点,并指导我们找到“最佳平衡点”。让我们首先在整个特征集上运行序列特征选择器(SFS),绘制性能图以可视化每个添加项的影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# SFS从1个特征到最大特征的性能,基于上述代码进行构建 import matplotlib.pyplot as plt # 准备存储每个特征数量的平均CV R²分数 mean_scores = [] # 迭代从1个特征到可用最大特征数量的范围 for n_features_to_select in range(1, len(X.columns)): sfs = SequentialFeatureSelector(model, n_features_to_select=n_features_to_select) sfs.fit(X, y) selected_features = X.columns[sfs.get_support()] score = cross_val_score(model, X[selected_features], y, cv=5, scoring="r2").mean() mean_scores.append(score) # 绘制平均CV R²分数与所选特征数量的图表 plt.figure(figsize=(10, 6)) plt.plot(range(1, len(X.columns)), mean_scores, marker="o") plt.title("性能 vs. 所选特征数量") plt.xlabel("特征数量") plt.ylabel("平均CV R²分数") plt.grid(True) plt.show() |
下图展示了模型性能如何随着特征的增加而改善,但最终会趋于平稳,这表明收益递减。
从这个图中你可以看出,使用超过十个特征几乎没有什么好处。然而,使用三个或更少特征则不是最佳选择。你可以使用“肘部法则”来找到曲线的弯曲点,从而确定最佳特征数量。这是一个主观的决定。这张图表明5到9个特征看起来是合适的。
凭借我们初步探索的见解,我们将容忍度(`tol=0.005`)应用于特征选择过程。这有助于我们客观而稳健地确定最佳特征数量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# 应用容差为0.005的序列特征选择器,基于上述代码进行构建 sfs_tol = SequentialFeatureSelector(model, n_features_to_select="auto", tol=0.005) sfs_tol.fit(X, y) # 获取使用容差选择的特征数量 n_features_selected = sum(sfs_tol.get_support()) # 准备存储每个特征数量的平均CV R²分数 mean_scores_tol = [] # 迭代从1个特征到最佳平衡点的范围 for n_features_to_select in range(1, n_features_selected + 1): sfs = SequentialFeatureSelector(model, n_features_to_select=n_features_to_select) sfs.fit(X, y) selected_features = X.columns[sfs.get_support()] score = cross_val_score(model, X[selected_features], y, cv=5, scoring="r2").mean() mean_scores_tol.append(score) # 绘制平均CV R²分数与所选特征数量的图表 plt.figure(figsize=(10, 6)) plt.plot(range(1, n_features_selected + 1), mean_scores_tol, marker="o") plt.title("最佳平衡点:性能 vs. 所选特征数量") plt.xlabel("特征数量") plt.ylabel("平均CV R²分数") plt.grid(True) plt.show() |
这一战略举措使我们能够专注于那些提供最高预测能力的特征,最终选择了8个最佳特征。
我们现在可以通过展示SFS选择的特征来总结我们的发现。
1 2 3 4 5 |
# 打印选择的特征及其性能,基于上述代码进行构建 selected_features = X.columns[sfs_tol.get_support()] print(f"选择的特征数量: {n_features_selected}") print(f"选择的特征: {selected_features.tolist()}") print(f"使用SFS(容差=0.005)的平均CV R²分数: {mean_scores_tol[-1]:.4f}") |
1 2 3 |
选择的特征数量:8 选择的特征:['GrLivArea', 'LotArea', 'OverallQual', 'OverallCond', 'YearBuilt', '1stFlrSF', 'BedroomAbvGr', 'KitchenAbvGr'] 使用SFS(容差=0.005)的平均CV R²分数:0.8239 |
通过关注这8个特征,我们实现了一个在复杂性和高预测能力之间取得平衡的模型,展示了特征选择的精细方法的有效性。
进一步阅读
API
教程
- 序列特征选择 by Sebastian Raschka
Ames 住房数据集和数据字典
总结
通过这三部分文章,您已经踏上了一段旅程,从评估单个特征的预测能力到利用它们的组合力量来构建一个精炼模型。我们的探索表明,虽然更多的特征可以增强模型捕捉复杂模式的能力,但总会有一个点,额外的特征不再有助于改善预测。通过对序列特征选择器应用容差水平,您已经确定了一组最佳特征,这些特征使我们模型的性能达到顶峰,同时又不过度复杂化预测模型。这个被称为八个关键特征的“最佳平衡点”,是预测建模中简单性和复杂性战略融合的典型代表。
具体来说,你学到了:
- 从简单开始的艺术:从简单的线性回归模型开始,了解每个特征的独立预测价值,为更复杂的分析奠定基础。
- 选择中的协同作用:过渡到序列特征选择器强调了不仅仅是单个特征的强度,更重要的是它们有效组合时的协同影响。
- 最大化模型效能:通过设置容差的SFS寻找预测的最佳平衡点,教会我们特征选择中精度的价值,以最少的投入获得最大的成果。
您有任何问题吗?请在下面的评论中提出您的问题,我将尽力回答。
暂无评论。