Scikit-learn 1.5.0 波士顿房价预测:7种回归模型深度评测与实战指南
房价预测一直是机器学习领域最经典的回归问题之一。波士顿房价数据集作为学术界和工业界广泛使用的基准数据集,为我们提供了研究不同回归算法性能的绝佳机会。本文将使用Scikit-learn 1.5.0版本,系统评测7种主流回归模型在该数据集上的表现,并深入分析它们的优缺点及适用场景。
1. 环境准备与数据加载
在开始建模之前,我们需要准备好Python环境和必要的数据科学工具包。Scikit-learn 1.5.0带来了多项性能优化和新特性,特别是在线性模型和决策树算法上的改进值得关注。
首先安装必要库(如果尚未安装):
pip install scikit-learn==1.5.0 pandas numpy matplotlib seaborn加载数据集并进行初步探索:
from sklearn.datasets import load_boston import pandas as pd import numpy as np # 加载数据集 boston = load_boston() df = pd.DataFrame(boston.data, columns=boston.feature_names) df['MEDV'] = boston.target # 添加目标变量 # 查看数据概览 print(df.info()) print(df.describe())波士顿房价数据集包含506个样本,每个样本有13个特征和1个目标变量(房价中位数)。关键特征包括:
- CRIM:城镇人均犯罪率
- RM:住宅平均房间数
- LSTAT:低收入人群比例
- PTRATIO:学生-教师比例
- DIS:到就业中心的加权距离
注意:在较新版本的Scikit-learn中,出于伦理考虑,波士顿房价数据集已被移除。我们可以从OpenML或其他数据源获取相同数据集,或使用
fetch_openml('boston', version=1)加载。
2. 数据预处理与特征工程
高质量的数据预处理往往能显著提升模型性能。我们采用以下步骤:
2.1 数据清洗与划分
from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # 检查缺失值 print("缺失值统计:\n", df.isnull().sum()) # 划分特征和目标 X = df.drop('MEDV', axis=1) y = df['MEDV'] # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) # 特征标准化 scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)2.2 特征相关性分析
了解特征与目标变量的关系对模型选择至关重要:
import seaborn as sns import matplotlib.pyplot as plt # 计算相关系数矩阵 corr_matrix = df.corr() # 绘制热力图 plt.figure(figsize=(12, 8)) sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0) plt.title("特征相关性热力图") plt.show() # 目标变量相关性排序 print(corr_matrix['MEDV'].sort_values(ascending=False))关键发现:
- RM(房间数量)与房价呈强正相关(0.7)
- LSTAT(低收入人群比例)与房价呈强负相关(-0.74)
- PTRATIO(学生-教师比)与房价呈中等负相关(-0.51)
3. 回归模型构建与评测
我们将评测以下7种回归模型,使用R²分数作为主要评估指标,并分析训练集与测试集的性能差异以识别过拟合。
3.1 线性回归模型
from sklearn.linear_model import LinearRegression from sklearn.metrics import r2_score lr = LinearRegression() lr.fit(X_train_scaled, y_train) # 评估 y_pred_train = lr.predict(X_train_scaled) y_pred_test = lr.predict(X_test_scaled) print(f"线性回归 - 训练集R²: {r2_score(y_train, y_pred_train):.4f}") print(f"线性回归 - 测试集R²: {r2_score(y_test, y_pred_test):.4f}")性能分析:
- 训练集R²:0.7436
- 测试集R²:0.6688
- 特点:简单快速,但可能存在欠拟合
3.2 正则化回归模型
正则化方法通过添加惩罚项防止过拟合,我们比较三种变体:
from sklearn.linear_model import Ridge, Lasso, ElasticNet # 岭回归 ridge = Ridge(alpha=1.0) ridge.fit(X_train_scaled, y_train) # Lasso回归 lasso = Lasso(alpha=0.1) lasso.fit(X_train_scaled, y_train) # 弹性网络 elastic = ElasticNet(alpha=0.1, l1_ratio=0.5) elastic.fit(X_train_scaled, y_train) # 收集结果 models = [ridge, lasso, elastic] names = ['岭回归', 'Lasso回归', '弹性网络'] results = {} for name, model in zip(names, models): y_pred_train = model.predict(X_train_scaled) y_pred_test = model.predict(X_test_scaled) results[name] = { 'train_r2': r2_score(y_train, y_pred_train), 'test_r2': r2_score(y_test, y_pred_test) }正则化模型对比表:
| 模型 | 训练集R² | 测试集R² | 特点 |
|---|---|---|---|
| 岭回归 | 0.7435 | 0.6691 | 平衡所有特征 |
| Lasso回归 | 0.7152 | 0.6783 | 自动特征选择 |
| 弹性网络 | 0.7221 | 0.6725 | 结合L1/L2优点 |
3.3 决策树回归
from sklearn.tree import DecisionTreeRegressor tree = DecisionTreeRegressor(max_depth=5, random_state=42) tree.fit(X_train_scaled, y_train) y_pred_train = tree.predict(X_train_scaled) y_pred_test = tree.predict(X_test_scaled) print(f"决策树 - 训练集R²: {r2_score(y_train, y_pred_train):.4f}") print(f"决策树 - 测试集R²: {r2_score(y_test, y_pred_test):.4f}")性能分析:
- 训练集R²:0.9012
- 测试集R²:0.7834
- 特点:容易过拟合,需谨慎调参
3.4 随机森林回归
from sklearn.ensemble import RandomForestRegressor rf = RandomForestRegressor( n_estimators=100, max_depth=7, random_state=42 ) rf.fit(X_train_scaled, y_train) y_pred_train = rf.predict(X_train_scaled) y_pred_test = rf.predict(X_test_scaled) print(f"随机森林 - 训练集R²: {r2_score(y_train, y_pred_train):.4f}") print(f"随机森林 - 测试集R²: {r2_score(y_test, y_pred_test):.4f}")性能分析:
- 训练集R²:0.9128
- 测试集R²:0.8516
- 特点:表现优异,但解释性较差
3.5 梯度提升树回归
from sklearn.ensemble import GradientBoostingRegressor gbr = GradientBoostingRegressor( n_estimators=200, learning_rate=0.1, max_depth=3, random_state=42 ) gbr.fit(X_train_scaled, y_train) y_pred_train = gbr.predict(X_train_scaled) y_pred_test = gbr.predict(X_test_scaled) print(f"梯度提升树 - 训练集R²: {r2_score(y_train, y_pred_train):.4f}") print(f"梯度提升树 - 测试集R²: {r2_score(y_test, y_pred_test):.4f}")性能分析:
- 训练集R²:0.9521
- 测试集R²:0.8734
- 特点:当前表现最佳模型
4. 模型对比与过拟合分析
将所有模型结果汇总对比:
# 添加之前未包含的模型结果 results.update({ '线性回归': { 'train_r2': r2_score(y_train, lr.predict(X_train_scaled)), 'test_r2': r2_score(y_test, lr.predict(X_test_scaled)) }, '决策树': { 'train_r2': r2_score(y_train, tree.predict(X_train_scaled)), 'test_r2': r2_score(y_test, tree.predict(X_test_scaled)) }, '随机森林': { 'train_r2': r2_score(y_train, rf.predict(X_train_scaled)), 'test_r2': r2_score(y_test, rf.predict(X_test_scaled)) }, '梯度提升树': { 'train_r2': r2_score(y_train, gbr.predict(X_train_scaled)), 'test_r2': r2_score(y_test, gbr.predict(X_test_scaled)) } }) # 创建对比DataFrame comparison = pd.DataFrame(results).T comparison['过拟合程度'] = comparison['train_r2'] - comparison['test_r2'] comparison.sort_values('test_r2', ascending=False, inplace=True)模型综合对比表:
| 模型 | 训练集R² | 测试集R² | 过拟合程度 | 排名 |
|---|---|---|---|---|
| 梯度提升树 | 0.9521 | 0.8734 | 0.0787 | 1 |
| 随机森林 | 0.9128 | 0.8516 | 0.0612 | 2 |
| 决策树 | 0.9012 | 0.7834 | 0.1178 | 3 |
| Lasso回归 | 0.7152 | 0.6783 | 0.0369 | 4 |
| 弹性网络 | 0.7221 | 0.6725 | 0.0496 | 5 |
| 岭回归 | 0.7435 | 0.6691 | 0.0744 | 6 |
| 线性回归 | 0.7436 | 0.6688 | 0.0748 | 7 |
关键发现:
- 梯度提升树综合表现最佳,测试集R²达到0.873
- 线性模型普遍表现较差,但Lasso回归因其特征选择能力略胜一筹
- 决策树过拟合最严重(差异0.118),需严格控制深度
- 集成方法(随机森林、梯度提升)在保持较低过拟合程度的同时获得最高精度
5. 模型优化与调参实战
以表现最好的梯度提升树为例,演示如何进行超参数优化:
from sklearn.model_selection import GridSearchCV param_grid = { 'n_estimators': [100, 200, 300], 'learning_rate': [0.01, 0.05, 0.1], 'max_depth': [3, 5, 7], 'min_samples_split': [2, 5, 10] } gbr = GradientBoostingRegressor(random_state=42) grid_search = GridSearchCV( estimator=gbr, param_grid=param_grid, cv=5, scoring='r2', n_jobs=-1 ) grid_search.fit(X_train_scaled, y_train) print("最佳参数:", grid_search.best_params_) print("最佳分数:", grid_search.best_score_) # 使用最佳模型评估 best_gbr = grid_search.best_estimator_ y_pred_test = best_gbr.predict(X_test_scaled) print(f"优化后测试集R²: {r2_score(y_test, y_pred_test):.4f}")调参后模型性能提升至0.8921,证明系统化调参的价值。对于生产环境,还可以考虑:
- 更精细的特征工程(如交互特征、多项式特征)
- 集成不同模型的堆叠(Stacking)方法
- 使用交叉验证更可靠地评估模型
- 引入早停机制防止过拟合
6. 模型解释与业务洞察
机器学习模型不仅要准确,还需要可解释。我们使用SHAP值分析最佳模型:
import shap # 创建解释器 explainer = shap.TreeExplainer(best_gbr) shap_values = explainer.shap_values(X_test_scaled) # 绘制特征重要性 shap.summary_plot(shap_values, X_test_scaled, feature_names=boston.feature_names)关键业务洞察:
- LSTAT(低收入人群比例)是最重要的负向预测因子
- RM(房间数量)是最重要的正向预测因子
- DIS(到就业中心距离)对房价有非线性影响
- PTRATIO(学生-教师比)超过一定阈值后对房价负面影响加剧
这些发现与房地产常识一致,验证了模型的可信度。决策者可以据此:
- 重点监控影响房价的关键指标
- 制定更有针对性的区域发展政策
- 识别被低估或高估的房产
7. 完整代码实现与部署建议
以下是整合所有步骤的完整代码框架:
# 1. 环境准备 import numpy as np import pandas as pd from sklearn.datasets import fetch_openml from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.preprocessing import StandardScaler from sklearn.ensemble import GradientBoostingRegressor from sklearn.metrics import r2_score import shap # 2. 数据加载与预处理 boston = fetch_openml(name='boston', version=1) df = pd.DataFrame(boston.data, columns=boston.feature_names) df['MEDV'] = boston.target X = df.drop('MEDV', axis=1) y = df['MEDV'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) # 3. 模型训练与调优 param_grid = { 'n_estimators': [100, 200, 300], 'learning_rate': [0.01, 0.05, 0.1], 'max_depth': [3, 5, 7] } gbr = GradientBoostingRegressor(random_state=42) grid_search = GridSearchCV(gbr, param_grid, cv=5, scoring='r2', n_jobs=-1) grid_search.fit(X_train_scaled, y_train) # 4. 模型评估 best_model = grid_search.best_estimator_ y_pred = best_model.predict(X_test_scaled) print(f"最终测试集R²: {r2_score(y_test, y_pred):.4f}") # 5. 模型解释 explainer = shap.TreeExplainer(best_model) shap_values = explainer.shap_values(X_test_scaled) shap.summary_plot(shap_values, X_test_scaled, feature_names=boston.feature_names)部署建议:
- 使用
joblib或pickle保存训练好的模型和标准化器 - 创建API服务封装预测逻辑
- 实现监控系统跟踪模型性能衰减
- 定期用新数据重新训练模型
- 考虑开发交互式可视化工具辅助决策