1. 项目概述
作为一名长期从事推荐系统开发的工程师,我发现在实际业务中,房价预测这类结构化数据的处理能力往往被低估。这次我想分享两个Kaggle经典项目——"预测房价"和"加州房价预测"的完整实现过程,这不仅是深度学习的入门练习,更是推荐系统中特征工程和模型调优的绝佳案例。
这两个项目都来自Kaggle平台,属于结构化数据预测的经典入门题目。虽然表面看是房价预测,但其中涉及的数据清洗、特征工程、模型选择和调参技巧,与推荐系统中的用户行为预测、商品CTR预估等任务高度相通。通过这两个项目的实践,我们能掌握从原始数据到最终预测的完整pipeline搭建能力。
2. 核心需求解析
2.1 项目背景与价值
Kaggle房价预测项目提供了真实的房屋交易数据,包含房屋面积、房龄、地理位置等80多个特征。我们的目标是建立一个能准确预测房屋售价的模型。这看似简单,实则包含了机器学习项目全流程:
- 数据探索与清洗(EDA)
- 特征工程与选择
- 模型选择与训练
- 超参数调优
- 结果分析与改进
对推荐系统开发者而言,这类结构化数据的处理经验可以直接迁移到用户特征处理、商品属性建模等场景。比如房屋的"邻近学校评分"特征,就类似于推荐系统中"用户最近浏览商品类别"这样的时序特征。
2.2 技术选型考量
在深度学习框架选择上,我推荐使用PyTorch而非TensorFlow,原因有三:
- PyTorch的动态计算图更利于调试,特别是在特征工程阶段需要频繁修改网络结构时
- PyTorch与Python生态集成更好,可以方便地结合pandas进行数据预处理
- 推荐系统领域的新论文实现大多采用PyTorch,保持技术栈统一有利于后续发展
对于模型结构,建议从简单的多层感知机(MLP)开始,逐步引入更复杂的结构。这种渐进式的方法能帮助我们更好地理解每个改进对最终效果的影响。
3. 数据准备与特征工程
3.1 数据探索分析
首先加载并观察数据特征:
import pandas as pd train_data = pd.read_csv('train.csv') test_data = pd.read_csv('test.csv') print(train_data.shape) # (1460, 81) print(test_data.shape) # (1459, 80)关键发现:
- 训练集1460条,测试集1459条
- 共80个特征+1个目标变量(SalePrice)
- 包含数值型和类别型特征混合
3.2 数据清洗策略
处理缺失值是首要任务。我采用分层处理策略:
- 对于缺失超过15%的特征直接删除
- 数值型特征用中位数填充
- 类别型特征用"None"作为新类别填充
- 时间相关特征用0填充(表示无记录)
# 计算缺失比例 missing = train_data.isnull().sum()/len(train_data) # 删除高缺失率特征 train_data.drop(missing[missing > 0.15].index, axis=1, inplace=True) # 填充数值特征 num_cols = train_data.select_dtypes(include=['int64','float64']).columns train_data[num_cols] = train_data[num_cols].fillna(train_data[num_cols].median()) # 填充类别特征 cat_cols = train_data.select_dtypes(include=['object']).columns train_data[cat_cols] = train_data[cat_cols].fillna('None')3.3 特征工程实战
有效的特征工程能显著提升模型性能。我主要采用以下方法:
- 数值特征标准化:
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() train_data[num_cols] = scaler.fit_transform(train_data[num_cols])- 类别特征编码:
- 基数低的用One-Hot
- 基数高的用均值编码(Mean Encoding)
- 特征组合:
- 面积相关特征相乘(如1层面积×2层面积)
- 时间特征组合(如建造年份×装修年份)
- 目标编码:
for col in high_cardinality_cols: means = train_data.groupby(col)['SalePrice'].mean() train_data[col+'_encoded'] = train_data[col].map(means)4. 模型构建与训练
4.1 基础MLP实现
我们先实现一个简单的3层MLP:
import torch import torch.nn as nn class HousePriceMLP(nn.Module): def __init__(self, input_dim): super().__init__() self.net = nn.Sequential( nn.Linear(input_dim, 256), nn.ReLU(), nn.Linear(256, 128), nn.ReLU(), nn.Linear(128, 1) ) def forward(self, x): return self.net(x)关键设计点:
- 输入维度需与特征数量一致
- 使用ReLU激活函数避免梯度消失
- 最后一层线性输出,因为这是回归问题
4.2 训练流程实现
完整的训练循环包含以下关键步骤:
- 数据准备:
from sklearn.model_selection import train_test_split X = train_data.drop('SalePrice', axis=1) y = train_data['SalePrice'] X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2) train_dataset = torch.utils.data.TensorDataset( torch.FloatTensor(X_train.values), torch.FloatTensor(y_train.values) ) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=32, shuffle=True)- 训练循环:
model = HousePriceMLP(X_train.shape[1]) criterion = nn.MSELoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) for epoch in range(100): for inputs, targets in train_loader: optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs.squeeze(), targets) loss.backward() optimizer.step()4.3 模型评估与改进
评估使用RMSLE(均方根对数误差)指标:
import numpy as np def rmsle(y_true, y_pred): log_true = np.log1p(y_true) log_pred = np.log1p(y_pred) return np.sqrt(np.mean((log_true - log_pred)**2))初始MLP的RMSLE约为0.18,我们可以通过以下方法改进:
- 添加BatchNorm层稳定训练:
self.net = nn.Sequential( nn.Linear(input_dim, 256), nn.BatchNorm1d(256), nn.ReLU(), ... )- 使用学习率调度器:
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau( optimizer, mode='min', factor=0.5, patience=3 )- 添加Dropout防止过拟合:
self.net = nn.Sequential( ..., nn.Dropout(0.3), ... )经过优化后,RMSLE可以降至0.15左右。
5. 高级技巧与实战经验
5.1 集成学习方法
单一模型性能有限,我推荐使用以下集成方法:
- 模型堆叠(Stacking):
- 第一层:训练多个异质模型(MLP、XGBoost、LightGBM)
- 第二层:用第一层的预测作为新特征训练元模型
- 交叉验证生成特征:
from sklearn.model_selection import KFold kf = KFold(n_splits=5) oof_preds = np.zeros(len(train_data)) for train_idx, val_idx in kf.split(train_data): # 训练并预测 ... oof_preds[val_idx] = model.predict(X_val) train_data['stack_feature'] = oof_preds5.2 超参数优化实战
我常用的超参数优化流程:
- 粗调范围:
param_grid = { 'lr': [1e-4, 1e-3, 1e-2], 'hidden_size': [64, 128, 256], 'dropout': [0.1, 0.3, 0.5] }- 使用Optuna精细调优:
import optuna def objective(trial): lr = trial.suggest_float('lr', 1e-5, 1e-2, log=True) hidden_size = trial.suggest_categorical('hidden_size', [64, 128, 256, 512]) dropout = trial.suggest_float('dropout', 0.1, 0.5) model = HousePriceMLP(input_dim, hidden_size, dropout) optimizer = torch.optim.Adam(model.parameters(), lr=lr) # 训练和验证 ... return val_loss5.3 部署与生产化考量
虽然这是比赛项目,但考虑生产环境很有必要:
- 特征管道封装:
from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer preprocessor = ColumnTransformer([ ('num', StandardScaler(), num_cols), ('cat', OneHotEncoder(), cat_cols) ]) pipeline = Pipeline([ ('preprocessor', preprocessor), ('model', HousePriceMLP()) ])- 模型轻量化:
- 量化训练(QAT)
- 知识蒸馏
- 监控指标:
- 预测值分布变化
- 特征重要性漂移
6. 常见问题与解决方案
6.1 数据相关问题
Q:如何处理极端离群值? A:我采用Turkey方法识别离群值:
Q1 = train_data['SalePrice'].quantile(0.25) Q3 = train_data['SalePrice'].quantile(0.75) IQR = Q3 - Q1 train_data = train_data[~((train_data['SalePrice'] < (Q1 - 1.5*IQR)) | (train_data['SalePrice'] > (Q3 + 1.5*IQR)))]Q:类别特征基数太高怎么办? A:对于超过50个类别的特征:
- 将低频类别合并为"其他"
- 使用目标编码代替One-Hot
- 考虑删除该特征
6.2 模型训练问题
Q:训练损失震荡严重? A:可能原因及解决方案:
- 学习率过高 → 减小lr或使用学习率预热
- Batch Size太小 → 增大到32或64
- 数据未打乱 → 检查DataLoader的shuffle参数
Q:验证集性能远差于训练集? A:典型过拟合,建议:
- 增加Dropout层
- 添加L2正则化
- 使用早停(Early Stopping)
- 增加训练数据量
6.3 比赛技巧
Q:如何提高Kaggle排名? A:除了模型优化外,还要注意:
- 充分利用比赛论坛的讨论(往往有数据泄露提示)
- 尝试不同的交叉验证策略(时间序列数据需用时序CV)
- 模型融合时注意多样性(不同结构的模型组合)
Q:特征工程中最易忽视的点? A:基于领域知识创造特征:
- 将"建造年份"转换为"房龄"
- 计算"每平方英尺价格"作为新特征
- 地理位置聚类(即使数据中没有经纬度,也可以用街道名称等替代)
7. 加州房价预测项目差异点
加州房价预测数据集与基本版的主要区别:
- 地理特征更丰富:
- 经纬度坐标
- 邻近海洋距离
- 气候区域划分
- 处理技巧差异:
# 计算海岸距离特征 def calc_coast_distance(row): return haversine( (row['latitude'], row['longitude']), nearest_coast_point ) train_data['coast_distance'] = train_data.apply(calc_coast_distance, axis=1)- 模型调整:
- 在MLP中添加地理位置嵌入层
- 使用空间自相关特征
- 考虑地理加权回归(GWR)方法
8. 项目总结与延伸思考
通过这两个房价预测项目,我总结了推荐系统开发的三个核心经验:
特征工程的质量决定模型上限。在推荐系统中,用户行为序列的特征构造同样关键。
模型结构要匹配数据特性。就像房价预测中地理位置的处理,推荐系统中也要针对用户兴趣漂移等特性设计专门模块。
评估指标要与业务目标一致。RMSLE对高价房误差惩罚较轻,类似地,推荐系统的评估也要考虑业务场景。
后续可以尝试将这里的特征工程方法应用到推荐系统的用户画像构建中,或者用图神经网络处理房屋之间的空间关系——这与社交推荐中的关系网络有异曲同工之妙。