Kaggle 竞赛入门:从 Titanic 到 House Prices 的 5 步通用工作流
Kaggle竞赛入门:从Titanic到House Prices的5步通用工作流
第一次打开Kaggle网站时,我被那些复杂的竞赛和术语搞得晕头转向。作为一个刚接触机器学习的新手,我甚至不知道从哪里开始。直到参加了Titanic生存预测竞赛后,才逐渐摸索出一套适用于大多数结构化数据竞赛的通用流程。这套方法后来帮助我在House Prices竞赛中进入了前15%。今天,我将分享这个经过实战检验的五步工作流,无论你是想获得第一块Kaggle奖牌,还是希望提升机器学习实战能力,这套方法都能为你提供清晰的路线图。
1. 数据探索:发现隐藏在数字背后的故事
数据探索是任何机器学习项目的基石。在Titanic竞赛中,我花了整整两天时间只是观察数据,这个看似"浪费"的时间最终让我发现了影响生存率的几个关键因素。
1.1 基础统计分析
首先使用pandas的describe()方法快速了解数据分布:
import pandas as pd train_data = pd.read_csv('train.csv') print(train_data.describe())这个简单的操作会输出每列数值型数据的计数、均值、标准差、最小值、四分位数和最大值。在House Prices数据中,我立即发现LotArea(地块面积)的最大值(215245)远大于75%分位数(9478.5),这意味着存在极端异常值。
1.2 可视化探索
统计数字只能告诉我们部分故事,可视化则能揭示更深层的模式。使用seaborn绘制特征关系图:
import seaborn as sns import matplotlib.pyplot as plt # 绘制年龄与生存率的关系 sns.violinplot(x='Survived', y='Age', data=train_data) plt.show()在Titanic数据中,这个图清晰地显示儿童(年龄<10岁)的生存率明显高于其他年龄段。这个发现促使我创建了"IsChild"新特征,最终提升了模型表现。
提示:重点关注特征与目标变量的关系,而不仅仅是特征本身的分布。一个特征本身可能有异常值,但如果这些异常值与目标变量关系合理,就不一定是问题。
1.3 缺失值分析
缺失值处理不当会严重影响模型性能。使用以下代码快速识别缺失情况:
missing_values = train_data.isnull().sum() missing_values[missing_values > 0].sort_values(ascending=False)在House Prices数据中,PoolQC(游泳池质量)有99.5%的缺失值,这实际上传递了一个重要信息——大多数房子没有游泳池。我创建了"HasPool"二元特征(1表示有游泳池,0表示没有),比简单填充缺失值效果更好。
常见数据探索检查清单:
- 数值特征的分布形状(正态分布、偏态分布)
- 分类特征的基数(唯一值数量)
- 特征与目标变量的相关性
- 特征之间的多重共线性
- 时间序列数据中的趋势和季节性
2. 特征工程:将原始数据转化为模型语言
特征工程是Kaggle竞赛中区分高手与新手的核心技能。好的特征工程能让简单模型表现超过复杂算法。
2.1 处理缺失数据
不同情况的缺失值需要不同处理策略:
| 缺失情况 | 处理方式 | 适用场景 |
|---|---|---|
| <5%缺失 | 中位数/众数填充 | 大多数数值/分类特征 |
| 5-30%缺失 | 预测模型填充 | 重要特征 |
| >30%缺失 | 创建缺失指示器 | 信息性缺失 |
对于Titanic中的Age特征(约20%缺失),我使用随机森林预测缺失值:
from sklearn.ensemble import RandomForestRegressor # 分割有缺失和无缺失数据 age_missing = train_data[train_data['Age'].isnull()] age_not_missing = train_data[~train_data['Age'].isnull()] # 训练预测模型 age_model = RandomForestRegressor() age_model.fit(age_not_missing[['Pclass', 'SibSp', 'Parch']], age_not_missing['Age']) # 预测缺失值 predicted_ages = age_model.predict(age_missing[['Pclass', 'SibSp', 'Parch']])2.2 创建交互特征
特征间的交互效应常常包含重要信息。在House Prices竞赛中,我发现房屋总面积(地下室面积+一层面积+二层面积)比单独使用各层面积更能预测价格:
train_data['TotalSF'] = train_data['TotalBsmtSF'] + train_data['1stFlrSF'] + train_data['2ndFlrSF']另一个有效技巧是将分类变量与数值变量结合。例如,根据房屋类型(分类)分组计算平均面积(数值),然后将这个平均值作为新特征。
2.3 目标编码
对于高基数分类变量(如邻里名称),独热编码会导致维度爆炸。目标编码是更好的选择:
from category_encoders import TargetEncoder encoder = TargetEncoder() train_data['Neighborhood_encoded'] = encoder.fit_transform(train_data['Neighborhood'], train_data['SalePrice'])注意:目标编码可能导致数据泄露,必须在交叉验证循环内部进行,或者使用留出集计算编码。
3. 模型选择:从简单到复杂的智慧路径
初学者常犯的错误是直接使用复杂模型,而忽略了基础模型的强大基准作用。
3.1 建立基准模型
线性回归和随机森林是两个理想的起点:
from sklearn.linear_model import LinearRegression from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error # 线性回归基准 lr = LinearRegression() lr.fit(X_train, y_train) lr_pred = lr.predict(X_val) print(f"Linear Regression MAE: {mean_absolute_error(y_val, lr_pred)}") # 随机森林基准 rf = RandomForestRegressor(n_estimators=100, random_state=42) rf.fit(X_train, y_train) rf_pred = rf.predict(X_val) print(f"Random Forest MAE: {mean_absolute_error(y_val, rf_pred)}")在House Prices竞赛中,我的随机森林基准达到了0.145的MAE,这已经超过了当时50%的参赛者。
3.2 梯度提升树(GBDT)模型
当基准模型建立后,梯度提升树通常能带来显著提升。XGBoost和LightGBM是Kaggle竞赛中最受欢迎的选择:
import xgboost as xgb # 转换为DMatrix格式提高效率 dtrain = xgb.DMatrix(X_train, label=y_train) dval = xgb.DMatrix(X_val, label=y_val) params = { 'objective': 'reg:squarederror', 'learning_rate': 0.05, 'max_depth': 6, 'subsample': 0.8, 'colsample_bytree': 0.8, 'eval_metric': 'mae' } model = xgb.train(params, dtrain, num_boost_round=1000, early_stopping_rounds=50, evals=[(dval, 'validation')])模型选择决策树:
- 数据量小(<10K样本):随机森林或XGBoost
- 数据量大:LightGBM(训练更快)
- 结构化表格数据:梯度提升树
- 文本/图像数据:深度学习模型
4. 超参数调优:释放模型全部潜力
正确的调优方法能让模型性能提升10-30%。我习惯采用三阶段调优策略。
4.1 粗调:确定大致范围
使用随机搜索快速探索参数空间:
from sklearn.model_selection import RandomizedSearchCV param_dist = { 'n_estimators': [100, 200, 300, 400, 500], 'max_depth': [3, 6, 9, 12], 'learning_rate': [0.01, 0.05, 0.1, 0.2], 'subsample': [0.6, 0.8, 1.0], 'colsample_bytree': [0.6, 0.8, 1.0] } random_search = RandomizedSearchCV( estimator=xgb.XGBRegressor(), param_distributions=param_dist, n_iter=50, cv=3, scoring='neg_mean_absolute_error' ) random_search.fit(X_train, y_train)4.2 精调:缩小范围
根据粗调结果,在最优参数附近构建更密集的网格:
param_grid = { 'max_depth': [5, 6, 7], 'learning_rate': [0.04, 0.05, 0.06], 'subsample': [0.75, 0.8, 0.85], 'colsample_bytree': [0.75, 0.8, 0.85] } grid_search = GridSearchCV(estimator=xgb.XGBRegressor(n_estimators=300), param_grid=param_grid, cv=3, scoring='neg_mean_absolute_error') grid_search.fit(X_train, y_train)4.3 最终调整:学习率与迭代次数
确定其他参数后,降低学习率并增加迭代次数,通常能获得额外提升:
final_model = xgb.XGBRegressor( max_depth=6, learning_rate=0.01, subsample=0.8, colsample_bytree=0.8, n_estimators=5000 # 需要配合early_stopping使用 )提示:始终使用早停(early stopping)防止过拟合。在验证集性能不再提升时停止训练。
5. 模型集成:团结就是力量
单个模型再强大也有其局限性。集成多个模型能减少方差,提高鲁棒性。
5.1 简单平均法
这是最简单的集成方式,只需对多个模型的预测结果取平均:
predictions = (model1_pred * 0.4 + model2_pred * 0.3 + model3_pred * 0.3)在House Prices竞赛中,我将XGBoost、LightGBM和CatBoost的预测按4:3:3加权平均,MAE提升了0.005。
5.2 堆叠(Stacking)
更高级的集成方法是使用元模型学习如何组合基模型:
from sklearn.ensemble import StackingRegressor from sklearn.linear_model import RidgeCV estimators = [ ('xgb', xgb.XGBRegressor()), ('lgbm', lgb.LGBMRegressor()), ('cat', cb.CatBoostRegressor(verbose=False)) ] stacker = StackingRegressor( estimators=estimators, final_estimator=RidgeCV(), cv=5 ) stacker.fit(X_train, y_train)集成策略选择指南:
- 基模型多样性越高,集成效果通常越好
- 相关性低的模型组合比高度相关模型组合更有效
- 简单平均适合快速实现,堆叠适合追求极致性能
- 集成模型数量不是越多越好,3-5个优质模型通常足够
在最终提交前,我习惯在本地保留10%的数据作为"终极测试集",不用在任何开发阶段。只有当所有调优完成后,才用这个集合作最终验证,这能很好地模拟比赛中的私有排行榜表现。
