76·实战项目进阶

实战:房价预测——特征工程与模型训练

projectregression

第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%的缺失值。

  1. 修改数值管道中的填充策略,分别尝试使用mean(均值)、median(中位数)和constant(常数0)进行填充。
  2. 比较三种策略下模型的RMSE和R²分数有何变化。

练习2:创建新特征

  1. preprocessor之前,手动创建一个新特征RoomsPerHouseholdAveRooms/AveOccup)。
  2. 将新特征加入numerical_features列表,重新运行整个训练和评估流程。
  3. 观察模型性能(RMSE, R²)和新特征的重要性排名。

练习3:模型对比

  1. 将模型从RandomForestRegressor切换为LinearRegressionGradientBoostingRegressor(来自sklearn.ensemble)。
  2. 仅改变model_pipeline中的regressor步骤,保持其他步骤不变,重新训练和评估。
  3. 对比三个模型的RMSE和R²分数。哪个模型表现最好?你认为为什么?

5. 常见错误

  1. 忽略数据探索导致错误的预处理:在未分析数据分布的情况下就选择填充策略(如对严重偏态的特征使用均值填充)。正确做法:先可视化数据分布。
  2. 盲目使用独热编码:对具有高基数(大量类别)的特征使用独热编码,会导致特征维度爆炸,训练变慢且可能过拟合。考虑:目标编码(Target Encoding)或嵌入。
  3. 在测试集上拟合预处理器:这是数据泄露!必须使用Pipeline或确保只在训练集上fit预处理器,然后用它来transform测试集。
  4. 忽略特征缩放对某些模型的影响:线性回归、SVM等基于距离的模型受特征缩放影响很大。树模型(随机森林、XGBoost)通常不受影响。
  5. 过度关注训练集性能:模型在训练集上R²=0.99,在测试集上只有0.6,这通常意味着过拟合。应始终以测试集(或验证集)性能为主要评判标准。

6. 小结

本节课我们完成了房价预测项目的核心实战部分:

  • 特征工程是成功的关键:通过处理缺失值、编码类别特征、缩放特征和创造新特征,显著提升了模型的“理解能力”。
  • Pipeline让流程更健壮:使用PipelineColumnTransformer可以避免数据泄露,使代码更清晰、可复用。
  • 模型选择与评估:我们实现了完整的训练-评估循环。RMSE给出了直观的误差解释,衡量了模型的整体拟合优度。
  • 实践出真知:通过练习中的参数调整、特征创造和模型对比,你将更深入地理解每个决策如何影响最终结果。

下一步:在后续课程中,我们将学习如何进一步调优模型超参数(如使用网格搜索),以及将训练好的模型部署为API服务。

练习编辑器

rust
Loading...

继续学习

完成本课后,建议继续学习下一课「实战:图像分类(CNN)完整项目」 以巩固所学知识。