线性回归模型是机器学习的基础。仅仅拟合一条直线并读取系数就能说明很多问题。但是,我们如何从这些模型中提取和解释系数,以了解它们对预测结果的影响呢?本文将通过探索各种场景来演示如何解释系数。我们将探讨对单个数值特征的分析,检查分类变量的作用,并揭示当这些特征组合时引入的复杂性。通过这次探索,我们旨在为您提供有效利用线性回归模型所需的技能,增强您在不同数据驱动领域中的分析能力。

解释线性回归模型中的系数
图片由 Zac Durant 拍摄。保留部分权利。
通过我的书《进阶数据科学》启动您的项目。它提供了带有可运行代码的自学教程。
让我们开始吧。
注意:本教程已更新,使用 scikit-learn 1.2+ 语法。如果您使用的是旧版本(<1.2),请在 OneHotEncoder 示例中将 sparse_output
替换为 sparse
。
概述
这篇博文分为三部分;它们是:
- 解释带单个数值特征的线性模型中的系数
- 解释带单个分类特征的线性模型中的系数
- 数值和分类特征组合的讨论
解释带单个数值特征的线性模型中的系数
在本节中,我们重点关注 Ames 住房数据集中的单个数值特征“GrLivArea”(地上居住面积,以平方英尺计),以了解其对“SalePrice”的直接影响。我们采用 K-折交叉验证来验证模型的性能并提取“GrLivArea”的系数。该系数估计了在所有其他因素保持不变的假设下,居住面积每增加一平方英尺,房价预计会增加多少。这是线性回归分析的一个基本方面,确保“GrLivArea”的影响与其他变量隔离。
以下是我们设置回归模型以实现此目的的方法:
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 30 31 |
# 设置以使用 K-Fold 获取 CV 模型性能和系数 import pandas as pd import numpy as np 来自 sklearn.linear_model 导入 LinearRegression from sklearn.model_selection import KFold Ames = pd.read_csv("Ames.csv") X = Ames[["GrLivArea"]].values # 获取二维矩阵 y = Ames["SalePrice"].values # 获取一维向量 模型 = LinearRegression() kf = KFold(n_splits=5) coefs = [] scores = [] # 手动执行 K-折交叉验证 for fold, (train_index, test_index) in enumerate(kf.split(X), start=1): # 将数据分割为训练集和测试集 X_train, X_test = X[train_index], X[test_index] y_train, y_test = y[train_index], y[test_index] # 拟合模型,获取折叠性能和系数 model.fit(X_train, y_train) scores.append(model.score(X_test, y_test)) coefs.append(model.coef_) mean_score = np.mean(scores) print(f"平均 CV R² = {mean_score:.4f}") mean_coefs = np.mean(coefs) print(f"平均系数 = {mean_coefs:.4f}") |
此代码块的输出提供了两个关键信息:跨折叠的平均 R² 分数和“GrLivArea”的平均系数。R² 分数让我们大致了解模型在不同子集上的数据拟合程度,指示模型的 Consistency(一致性)和可靠性。同时,平均系数量化了“GrLivArea”对所有验证折叠中“SalePrice”的平均影响。
1 2 |
平均 CV R² = 0.5127 平均系数 = 110.5214 |
“GrLivArea”的系数可以直接解释为每平方英尺的价格变化。具体来说,它表明“GrLivArea”每增加一平方英尺,房屋的售价预计将增加约 110.52 美元(不要与每平方英尺的价格混淆,因为该系数指的是边际价格)。相反,居住面积减少一平方英尺通常会使售价降低相同的金额。
想开始学习进阶数据科学吗?
立即参加我的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
解释带单个分类特征的线性模型中的系数
虽然像“GrLivArea”这样的数值特征可以直接用于我们的回归模型,但分类特征需要不同的方法。正确编码这些分类变量对于准确的模型训练和确保结果可解释至关重要。在本节中,我们将探讨独热编码——一种通过将分类变量转换为模型框架内可解释的格式来为线性回归准备分类变量的技术。我们将特别关注如何解释这些转换产生的系数,包括战略性地选择一个参考类别来简化这些解释。
在应用独热编码时选择合适的参考类别至关重要,因为它设定了与其他类别进行比较的基线。这个基线类别的平均值通常作为我们回归模型中的截距。让我们探索销售价格在不同社区的分布,以选择一个既可解释又具有意义的参考类别。
1 2 3 4 |
# 按平均销售价格对社区进行排名 Ames = pd.read_csv("Ames.csv") neighbor_stats = Ames.groupby("Neighborhood")["SalePrice"].agg(["count", "mean"]).sort_values(by="mean") print(neighbor_stats.round(0).astype(int)) |
此输出将通过突出显示平均价格最低和最高的社区,以及指示具有足够数据点(计数)以确保稳健统计分析的社区,来为我们的选择提供信息。
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 30 |
计数 平均值 社区 MeadowV 34 96836 BrDale 29 106095 IDOTRR 76 108103 BrkSide 103 126030 OldTown 213 126939 Edwards 165 133152 SWISU 42 133576 Landmrk 1 137000 Sawyer 139 137493 NPkVill 22 140743 Blueste 10 143590 NAmes 410 145087 Mitchel 104 162655 SawyerW 113 188102 Gilbert 143 189440 NWAmes 123 190372 Greens 8 193531 Blmngtn 23 196237 CollgCr 236 198133 Crawfor 92 202076 ClearCr 40 213981 Somerst 143 228762 Timber 54 242910 Veenker 23 251263 GrnHill 2 280000 StoneBr 43 305308 NridgHt 121 313662 NoRidge 67 326114 |
选择“MeadowV”作为我们的参考,设定了一个清晰的基线,解释其他社区的系数变得直接:它们显示了房屋价格比“MeadowV”贵多少。
在确定“MeadowV”为我们的参考社区后,我们现在准备对“Neighborhood”特征应用独热编码,明确排除“MeadowV”以将其设置为模型中的基线。此步骤确保所有后续社区系数都相对于“MeadowV”进行解释,从而对不同地区的房价进行清晰的比较分析。接下来的代码块将演示此编码过程,使用 K-折交叉验证拟合线性回归模型,并计算平均系数和 Y 截距。这些计算将有助于量化每个社区相对于我们基线的额外价值或不足,为市场评估提供可操作的见解。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# 在初始设置和上面的代码块基础上构建 # 导入 OneHotEncoder 以预处理分类特征 from sklearn.preprocessing import OneHotEncoder # “Neighborhood”的独热编码,注意:drop=["MeadowV"] # 适用于 scikit-learn >= 1.2 encoder = OneHotEncoder(sparse_output=False, drop=["MeadowV"]) # 适用于 scikit-learn < 1.2(已弃用) # encoder = OneHotEncoder(sparse=False, drop=["MeadowV"]) X = encoder.fit_transform(Ames[["Neighborhood"]]) y = Ames["SalePrice"].values # 设置 KFold 并初始化存储 kf = KFold(n_splits=5) scores = [] coefficients = [] intercept = [] # 执行 KFold 交叉验证 for train_index, test_index in kf.split(X): X_train, X_test = X[train_index], X[test_index] y_train, y_test = y[train_index], y[test_index] model = LinearRegression() model.fit(X_train, y_train) # 追加每个折叠的结果 scores.append(model.score(X_test, y_test)) coefficients.append(model.coef_) intercept.append(model.intercept_) mean_score = np.mean(scores) print(f"平均 CV R² = {mean_score:.4f}") mean_coefficients = np.mean(coefficients, axis=0) mean_intercept = np.mean(intercept) print(f"平均 Y 截距 = {mean_intercept:.0f}") # 从编码器中检索社区名称,调整已删除的类别 neighborhoods = encoder.categories_[0] if "MeadowV" in neighborhoods: neighborhoods = [name for name in neighborhoods if name != "MeadowV"] # 创建一个 DataFrame 以良好地显示社区及其平均系数 import pandas as pd coefficients_df = pd.DataFrame({ "Neighborhood": neighborhoods, "Average Coefficient": mean_coefficients.round(0).astype(int) }) # 打印或返回 DataFrame print(coefficients_df.sort_values(by="Average Coefficient").reset_index(drop=True)) |
无论我们独热编码时“删除”了哪个特征,平均 R² 都将保持一致,为 0.5408。
Y 截距提供了一个具体的定量基准。它代表了“MeadowV”的平均销售价格,形成了所有其他社区溢价或折扣的衡量基础价格水平。
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 30 31 |
平均 CV R² = 0.5408 平均 Y 截距 = 96827 社区 平均系数 0 BrDale 9221 1 IDOTRR 11335 2 BrkSide 29235 3 OldTown 30092 4 Landmrk 31729 5 Edwards 36305 6 SWISU 36848 7 Sawyer 40645 8 NPkVill 43988 9 Blueste 46388 10 NAmes 48274 11 Mitchel 65851 12 SawyerW 91252 13 Gilbert 92627 14 NWAmes 93521 15 Greens 96641 16 Blmngtn 99318 17 CollgCr 101342 18 Crawfor 105258 19 ClearCr 116993 20 Somerst 131844 21 Timber 146216 22 Veenker 155042 23 GrnHill 183173 24 StoneBr 208096 25 NridgHt 216605 26 NoRidge 229423 |
每个社区的系数,相对于“MeadowV”计算,揭示了其在房价中的溢价或亏损。通过将“MeadowV”设置为独热编码过程中的参考类别,其平均销售价格有效地成为我们模型的截距。然后,为其他社区计算的系数衡量了相对于“MeadowV”的预期销售价格差异。例如,如果某个社区的系数为正,则表明该社区的房屋价格比“MeadowV”的房屋价格高出系数的值,假设所有其他因素保持不变。这种安排使我们能够直接评估和比较不同社区对“SalePrice”的影响,从而清晰量化地理解每个社区的相对市场价值。
数值和分类特征组合的讨论
到目前为止,我们已经分别考察了数值和分类特征如何影响我们的预测。然而,现实世界的数据通常需要更复杂的模型,这些模型能够同时处理多种类型的数据,以捕捉市场内复杂的相互关系。为了实现这一点,熟悉像 ColumnTransformer
这样的工具至关重要,它允许同时处理不同数据类型,确保每个特征都为建模做好了最佳准备。现在让我们演示一个例子,我们将居住面积(“GrLivArea”)与社区分类结合起来,看看这些因素如何共同影响我们的模型性能。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# 导入必要的库 import pandas as pd import numpy as np from sklearn.model_selection import KFold 来自 sklearn.linear_model 导入 LinearRegression from sklearn.preprocessing import OneHotEncoder from sklearn.compose import ColumnTransformer # 加载数据 Ames = pd.read_csv("Ames.csv") # 选择特征和目标 features = Ames[["GrLivArea", "Neighborhood"]] target = Ames["SalePrice"] # 使用 ColumnTransformer 预处理特征 preprocessor = ColumnTransformer( transformers=[ ("num", "passthrough", ["GrLivArea"]), ("cat", OneHotEncoder(sparse_output=False, drop=["MeadowV"], handle_unknown="ignore"), ["Neighborhood"]) ]) # 拟合并转换特征 X_transformed = preprocessor.fit_transform(features) feature_names = ["GrLivArea"] + list(preprocessor.named_transformers_["cat"].get_feature_names_out()) # 初始化 KFold kf = KFold(n_splits=5) # 初始化变量以存储结果 coefficients_list = [] intercepts_list = [] scores = [] # 执行 KFold 交叉验证 for train_index, test_index in kf.split(X_transformed): X_train, X_test = X_transformed[train_index], X_transformed[test_index] y_train, y_test = target.iloc[train_index], target.iloc[test_index] # 初始化线性回归模型 model = LinearRegression() # 在训练数据上拟合模型 model.fit(X_train, y_train) # 存储系数和截距 coefficients_list.append(model.coef_) intercepts_list.append(model.intercept_) # 评估模型 scores.append(model.score(X_test, y_test)) # 计算分数、系数和截距的平均值 average_score = np.mean(scores) average_coefficients = np.mean(coefficients_list, axis=0) average_intercept = np.mean(intercepts_list) # 显示所有折叠的平均 R² 分数和 Y 截距 # Y 截距表示“MeadowV”中没有额外居住面积的基准销售价格 print(f"组合模型的平均 CV R² 分数: {average_score:.4f}") print(f"平均 Y 截距 = {average_intercept:.0f}") # 为系数创建一个 DataFrame df_coefficients = pd.DataFrame({ "Feature": feature_names, "Average Coefficient": average_coefficients }).sort_values(by="Average Coefficient").reset_index(drop=True) # 显示 DataFrame print("组合模型的系数:") print(df_coefficients) |
上面的代码应输出
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 30 31 32 33 |
组合模型的平均 CV R² 分数: 0.7375 平均 Y 截距 = 11786 组合模型的系数 特征 平均系数 0 Neighborhood_SWISU -3728.929853 1 Neighborhood_IDOTRR -1498.971239 2 GrLivArea 78.938757 3 Neighborhood_OldTown 2363.805796 4 Neighborhood_BrDale 6551.114637 5 Neighborhood_BrkSide 16521.117849 6 Neighborhood_Landmrk 16921.529665 7 Neighborhood_Edwards 17520.110407 8 Neighborhood_NPkVill 30034.541748 9 Neighborhood_NAmes 31717.960146 10 Neighborhood_Sawyer 32009.140024 11 Neighborhood_Blueste 39908.310031 12 Neighborhood_NWAmes 44409.237736 13 Neighborhood_Mitchel 48013.229999 14 Neighborhood_SawyerW 48204.606372 15 Neighborhood_Gilbert 49255.248193 16 Neighborhood_Crawfor 55701.500795 17 Neighborhood_ClearCr 61737.497483 18 Neighborhood_CollgCr 69781.161291 19 Neighborhood_Blmngtn 72456.245569 20 Neighborhood_Somerst 90020.562168 21 Neighborhood_Greens 90219.452164 22 Neighborhood_Timber 97021.781128 23 Neighborhood_Veenker 98829.786236 24 Neighborhood_NoRidge 120717.748175 25 Neighborhood_StoneBr 147811.849406 26 Neighborhood_NridgHt 150129.579392 27 Neighborhood_GrnHill 157858.199004 |
将“GrLivArea”和“Neighborhood”组合成一个模型显著提高了 R² 分数,从单独的 0.5127 和 0.5408 分数分别提高到 0.7375。这一显著增加表明,整合多种数据类型能更准确地反映影响房地产价格的复杂因素。
然而,这种整合给模型带来了新的复杂性。像“GrLivArea”和“Neighborhood”这样的特征之间的交互作用可以显著改变系数。例如,“GrLivArea”的系数从单特征模型中的 110.52 降低到组合模型中的 78.93。这一变化说明了居住面积的价值如何受到不同社区特征的影响。结合多个变量需要调整系数,以考虑预测变量之间重叠的方差,从而导致系数通常与单特征模型中的系数不同。
我们组合模型计算出的平均 Y 截距为 11,786 美元。这个值代表了“MeadowV”社区中一套房屋的预测销售价格,其基础居住面积(由“GrLivArea”考虑在内)调整为零。这个截距作为基本价格点,增强了我们对不同社区与“MeadowV”在成本方面进行比较的解释,一旦调整了居住面积的大小。因此,每个社区的系数都告诉我们相对于我们的基线“MeadowV”的额外成本或节省,为不同地区房产的相对价值提供了清晰可操作的见解。
进一步阅读
API
教程
- 解释回归系数 作者:Karen Grace-Martin
Ames 住房数据集和数据字典
总结
本文通过使用 Ames 住房数据集的清晰实用示例,指导您解释线性回归模型中的系数。我们探讨了不同类型的特征(数值和分类)如何影响模型的可预测性和清晰度。此外,我们还讨论了组合这些特征的挑战和好处,尤其是在解释的背景下。
具体来说,你学到了:
- 单个数值特征的直接影响:“GrLivArea”系数如何直接量化每增加一平方英尺“SalePrice”的增加,提供了一个简单模型中其预测值的清晰衡量。
- 处理分类变量:独热编码在处理“Neighborhood”等分类特征方面的重要性,说明了选择基线类别如何影响系数的解释,并为不同区域之间的比较奠定基础。
- 组合特征以增强模型性能:“GrLivArea”和“Neighborhood”的整合不仅提高了预测准确性(R² 分数),而且引入了影响每个特征系数解释的复杂性。这一部分强调了实现高预测准确性与保持模型可解释性之间的权衡,这对于在房地产市场中做出明智决策至关重要。
您有任何问题吗?请在下面的评论中提出您的问题,我将尽力回答。
修正这条线
encoder = OneHotEncoder(sparse=False, drop=[“MeadowV”]) 为 encoder = OneHotEncoder(sparse_output=False, drop=[“MeadowV”])
嗨,Pepeto……感谢您的反馈!