第76课:实战:房价预测——特征工程与模型训练
1. 学习目标
完成本课学习后,你将能够:
- 掌握对原始数据进行预处理和特征工程的完整流程。
- 理解并应用关键的特征工程技术,如缺失值处理、类别特征编码和特征缩放。
- 使用Scikit-learn库选择合适的回归模型,进行训练和初步调优。
- 评估模型性能,并理解均方误差(MSE)、均方根误差(RMSE)和R²等回归评估指标的含义。
2. 核心概念
特征工程:为模型准备“食材”
如果说原始数据是“食材”,那么特征工程就是“预处理和烹饪”过程,目的是提取和构造对预测最有价值的特征。
- 处理缺失值:就像填补食材的空缺,可以用平均值、中位数或最常见值填充,或删除缺失严重的特征/样本。
- 类别特征编码:模型只认识数字。对于“房屋类型”这样的文字类别,需要将其转换为数值,如使用独热编码(One-Hot Encoding)。
- 特征缩放:不同特征的“量纲”(如面积单位是平方米,价格是万元)差异巨大。标准化或归一化可以让模型训练更稳定、高效。
- 创建新特征:根据领域知识组合现有特征。例如,将“房间数”和“卫生间数”相加得到“总房间数”。
模型训练:选择“厨师”并开始烹饪
- 选择模型:回归问题常用模型包括线性回归、决策树、随机森林、梯度提升树(如XGBoost)等。从简单模型开始是好习惯。
- 划分数据集:将数据分为训练集(用于学习)和测试集(用于评估),以检验模型的泛化能力。
- 训练与预测:用训练集数据“教会”模型,然后用模型对测试集进行预测。
- 模型评估:对比预测值和真实值,计算评估指标。
均方根误差 (RMSE)表示平均预测误差的大小,R² 分数表示模型解释数据变异性的比例(越接近1越好)。
3. 代码示例
以下是一个完整的房价预测流程代码示例,使用经典的加州房价数据集。
# 步骤0: 导入必要的库
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
# 步骤1: 加载数据(以加州房价数据为例,这里使用sklearn内置数据集)
from sklearn.datasets import fetch_california_housing
data = fetch_california_housing()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = pd.Series(data.target, name='MedHouseVal') # 目标:房价中位数
print("原始数据形状:", X.shape)
print("前几行特征:\n", X.head())
# 步骤2: 数据预处理和特征工程
# 2.1 识别特征类型
numerical_features = ['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude']
# 此数据集没有明显的类别特征,我们假设 `AveRooms` 等已经是数值型。
# 如果有类别特征,如 `OceanProximity`, 则需要单独处理。
# 2.2 创建预处理管道
# 数值特征管道:填充缺失值 -> 标准化
numerical_pipeline = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')), # 用中位数填充缺失值
('scaler', StandardScaler()) # 特征缩放
])
# 类别特征管道(本例暂无,作为示例)
# categorical_pipeline = Pipeline(steps=[
# ('imputer', SimpleImputer(strategy='most_frequent')),
# ('onehot', OneHotEncoder(handle_unknown='ignore'))
# ])
# 组合所有预处理步骤
preprocessor = ColumnTransformer(
transformers=[
('num', numerical_pipeline, numerical_features)
# ('cat', categorical_pipeline, categorical_features) # 如果有类别特征则加入
])
# 步骤3: 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"训练集大小: {X_train.shape}, 测试集大小: {X_test.shape}")
# 步骤4: 构建模型管道(将预处理器和模型结合)
# 使用随机森林回归器
model_pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('regressor', RandomForestRegressor(n_estimators=100, random_state=42))
])
# 步骤5: 训练模型
print("正在训练模型...")
model_pipeline.fit(X_train, y_train)
print("模型训练完成!")
# 步骤6: 在测试集上预测并评估
y_pred = model_pipeline.predict(X_test)
# 计算评估指标
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_test, y_pred)
print("\n模型评估结果:")
print(f"均方误差 (MSE): {mse:.4f}")
print(f"均方根误差 (RMSE): {rmse:.4f} (表示平均预测误差约为 ${rmse*100000:.0f} 美元)")
print(f"R² 分数: {r2:.4f}")
# 步骤7: 查看特征重要性(仅适用于树模型)
if hasattr(model_pipeline.named_steps['regressor'], 'feature_importances_'):
importances = model_pipeline.named_steps['regressor'].feature_importances_
feature_importance_df = pd.DataFrame({
'Feature': numerical_features,
'Importance': importances
}).sort_values(by='Importance', ascending=False)
print("\n特征重要性排名:")
print(feature_importance_df)
4. 实践练习
练习1:基础预处理
在上述代码基础上,假设Population列有5%的缺失值。
- 修改数值管道中的填充策略,分别尝试使用
mean(均值)、median(中位数)和constant(常数0)进行填充。 - 比较三种策略下模型的RMSE和R²分数有何变化。
练习2:创建新特征
- 在
preprocessor之前,手动创建一个新特征RoomsPerHousehold(AveRooms/AveOccup)。 - 将新特征加入
numerical_features列表,重新运行整个训练和评估流程。 - 观察模型性能(RMSE, R²)和新特征的重要性排名。
练习3:模型对比
- 将模型从
RandomForestRegressor切换为LinearRegression和GradientBoostingRegressor(来自sklearn.ensemble)。 - 仅改变
model_pipeline中的regressor步骤,保持其他步骤不变,重新训练和评估。 - 对比三个模型的RMSE和R²分数。哪个模型表现最好?你认为为什么?
5. 常见错误
- 忽略数据探索导致错误的预处理:在未分析数据分布的情况下就选择填充策略(如对严重偏态的特征使用均值填充)。正确做法:先可视化数据分布。
- 盲目使用独热编码:对具有高基数(大量类别)的特征使用独热编码,会导致特征维度爆炸,训练变慢且可能过拟合。考虑:目标编码(Target Encoding)或嵌入。
- 在测试集上拟合预处理器:这是数据泄露!必须使用
Pipeline或确保只在训练集上fit预处理器,然后用它来transform测试集。 - 忽略特征缩放对某些模型的影响:线性回归、SVM等基于距离的模型受特征缩放影响很大。树模型(随机森林、XGBoost)通常不受影响。
- 过度关注训练集性能:模型在训练集上R²=0.99,在测试集上只有0.6,这通常意味着过拟合。应始终以测试集(或验证集)性能为主要评判标准。
6. 小结
本节课我们完成了房价预测项目的核心实战部分:
- 特征工程是成功的关键:通过处理缺失值、编码类别特征、缩放特征和创造新特征,显著提升了模型的“理解能力”。
- Pipeline让流程更健壮:使用
Pipeline和ColumnTransformer可以避免数据泄露,使代码更清晰、可复用。 - 模型选择与评估:我们实现了完整的训练-评估循环。
RMSE给出了直观的误差解释,R²衡量了模型的整体拟合优度。 - 实践出真知:通过练习中的参数调整、特征创造和模型对比,你将更深入地理解每个决策如何影响最终结果。
下一步:在后续课程中,我们将学习如何进一步调优模型超参数(如使用网格搜索),以及将训练好的模型部署为API服务。
练习编辑器
rust
Loading...