从数据洞察到模型调优:用Seaborn和Sklearn完整走一遍房价预测项目
从数据洞察到模型调优:用Seaborn和Sklearn完整走一遍房价预测项目
房价预测一直是数据科学领域的经典案例。不同于简单的代码实现,一个完整的预测项目需要经历数据理解、可视化分析、特征筛选、模型构建与比较、超参数调优和模型评估的全流程。本文将带你用Python的Seaborn和Sklearn库,完整走一遍这个流程,重点讲解每一步的意图和实现方法。
1. 项目准备与数据理解
在开始任何数据分析项目前,理解数据的基本结构和特征含义至关重要。波士顿房价数据集包含506个样本,每个样本有13个特征和1个目标变量(房价中位数)。
关键特征解析:
- RM:平均每居民房数(通常与房价正相关)
- LSTAT:人口中地位较低人群的百分数(通常与房价负相关)
- PTRATIO:城镇师生比例(反映教育资源情况)
- CRIM:城镇人均犯罪率(影响区域安全性)
import pandas as pd import seaborn as sns import matplotlib.pyplot as plt # 加载数据 boston = pd.read_csv('housing.csv') boston.columns = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV'] # 查看数据概览 print(boston.info()) print(boston.describe())提示:数据探索阶段要特别关注缺失值和异常值,它们会直接影响后续建模效果。
2. 数据可视化与特征分析
可视化是理解数据分布和特征间关系的有力工具。我们将使用Seaborn库创建多种图表来深入分析数据。
2.1 特征与目标变量的关系
# 绘制关键特征与房价的散点图 plt.figure(figsize=(15,5)) plt.subplot(1,3,1) sns.regplot(x='RM', y='MEDV', data=boston, scatter_kws={'alpha':0.3}) plt.subplot(1,3,2) sns.regplot(x='LSTAT', y='MEDV', data=boston, scatter_kws={'alpha':0.3}) plt.subplot(1,3,3) sns.regplot(x='PTRATIO', y='MEDV', data=boston, scatter_kws={'alpha':0.3}) plt.tight_layout() plt.show()2.2 特征间相关性分析
热力图能直观展示特征间的相关性,帮助我们识别高度相关的特征,避免多重共线性问题。
# 计算并绘制相关性热力图 corr_matrix = boston.corr() plt.figure(figsize=(12,8)) sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm') plt.title('特征相关性热力图') plt.show()关键观察:
- RM与MEDV呈现强正相关(0.7)
- LSTAT与MEDV呈现强负相关(-0.74)
- RAD和TAX高度相关(0.91),可能需要特征选择
3. 特征工程与数据预处理
良好的特征工程往往比模型选择更能提升预测性能。这一阶段包括特征选择、转换和标准化。
3.1 特征选择
基于相关性分析,我们选择与房价相关性绝对值大于0.5的特征:
selected_features = corr_matrix['MEDV'][abs(corr_matrix['MEDV']) > 0.5].index selected_features = selected_features.drop('MEDV') # 移除目标变量 print('选择的特征:', list(selected_features))3.2 数据标准化
不同特征的量纲差异会影响模型性能,特别是正则化模型如岭回归和Lasso。
from sklearn.preprocessing import StandardScaler # 划分特征和目标变量 X = boston[selected_features] y = boston['MEDV'] # 标准化特征 scaler = StandardScaler() X_scaled = scaler.fit_transform(X)4. 模型构建与比较
我们将比较三种线性模型:普通最小二乘回归、岭回归和Lasso回归,评估它们在房价预测上的表现。
4.1 数据分割
from sklearn.model_selection import train_test_split # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split( X_scaled, y, test_size=0.2, random_state=42)4.2 模型训练与评估
from sklearn.linear_model import LinearRegression, Ridge, Lasso from sklearn.metrics import mean_squared_error, r2_score models = { 'Linear Regression': LinearRegression(), 'Ridge Regression': Ridge(alpha=1.0), 'Lasso Regression': Lasso(alpha=1.0) } results = [] for name, model in models.items(): model.fit(X_train, y_train) y_pred = model.predict(X_test) mse = mean_squared_error(y_test, y_pred) rmse = np.sqrt(mse) r2 = r2_score(y_test, y_pred) results.append([name, mse, rmse, r2]) # 展示结果 results_df = pd.DataFrame(results, columns=['Model', 'MSE', 'RMSE', 'R2']) print(results_df)模型比较表:
| 模型 | MSE | RMSE | R2 |
|---|---|---|---|
| 线性回归 | 23.18 | 4.81 | 0.72 |
| 岭回归 | 24.88 | 4.99 | 0.70 |
| Lasso回归 | 28.94 | 5.38 | 0.65 |
5. 模型调优与验证
正则化参数α的选择对岭回归和Lasso的性能有重要影响。我们将使用交叉验证来寻找最优参数。
5.1 岭回归参数调优
from sklearn.model_selection import GridSearchCV # 定义参数网格 param_grid = {'alpha': [0.001, 0.01, 0.1, 1, 10, 100]} # 网格搜索 ridge = Ridge() grid_search = GridSearchCV(ridge, param_grid, cv=5, scoring='neg_mean_squared_error') grid_search.fit(X_train, y_train) # 最佳参数 print('最佳alpha:', grid_search.best_params_) print('最佳分数:', -grid_search.best_score_)5.2 调优后的模型评估
# 使用最佳参数重新训练 best_ridge = grid_search.best_estimator_ y_pred = best_ridge.predict(X_test) # 评估指标 ridge_mse = mean_squared_error(y_test, y_pred) ridge_rmse = np.sqrt(ridge_mse) ridge_r2 = r2_score(y_test, y_pred) print(f'调优后岭回归性能: RMSE={ridge_rmse:.2f}, R2={ridge_r2:.2f}')5.3 特征重要性分析
Lasso回归因其特性可以进行特征选择,让我们看看哪些特征被模型认为最重要。
# 训练Lasso模型 lasso = Lasso(alpha=0.01) lasso.fit(X_train, y_train) # 特征重要性 feature_importance = pd.DataFrame({ 'Feature': selected_features, 'Coefficient': lasso.coef_ }).sort_values('Coefficient', key=abs, ascending=False) print(feature_importance)特征重要性排序:
- LSTAT(人口中地位较低人群比例)
- RM(平均每居民房数)
- PTRATIO(城镇师生比例)
- DIS(与就业中心的距离)
6. 模型诊断与改进建议
在完成初步建模后,我们需要诊断模型是否存在问题,并探索可能的改进方向。
6.1 残差分析
# 计算残差 residuals = y_test - y_pred # 绘制残差图 plt.figure(figsize=(10,5)) plt.scatter(y_pred, residuals) plt.axhline(y=0, color='r', linestyle='--') plt.xlabel('预测值') plt.ylabel('残差') plt.title('残差图') plt.show()注意:理想的残差图应该随机分布在0附近,没有明显的模式。如果出现漏斗形或其他模式,可能需要对数据进行转换或考虑非线性模型。
6.2 可能的改进方向
- 非线性特征:尝试添加特征的平方项或交互项
- 其他模型:测试决策树、随机森林等非线性模型
- 异常值处理:识别并处理可能影响模型的极端值
- 更多特征:收集或构造更多相关特征
# 示例:添加多项式特征 from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures(degree=2, include_bias=False) X_poly = poly.fit_transform(X_scaled) # 重新训练模型 X_train_poly, X_test_poly, y_train, y_test = train_test_split( X_poly, y, test_size=0.2, random_state=42) ridge_poly = Ridge(alpha=1.0) ridge_poly.fit(X_train_poly, y_train) y_pred_poly = ridge_poly.predict(X_test_poly) print('多项式特征R2:', r2_score(y_test, y_pred_poly))在实际项目中,我发现特征��程的质量往往比模型选择更能影响最终效果。特别是在处理房价这种受多种因素影响的复杂问题时,深入理解业务背景和特征含义至关重要。
