84·实战项目高级

实战:表格数据竞赛技巧

projectcompetition

第84课 - 实战:表格数据竞赛技巧

学习目标

  1. 理解表格数据竞赛(如Kaggle竞赛)的完整流程与评估指标。
  2. 掌握在竞赛中快速提升模型性能的关键特征工程技巧。
  3. 学会应用高级模型训练与集成策略来赢得比赛。
  4. 培养系统化的实验管理与结果分析习惯。
  5. 了解竞赛中的团队协作与资源分享的基本规范。

核心概念

表格数据竞赛是机器学习入门实战的最佳场景之一。它的目标是在给定的结构化数据集上,构建一个预测性能尽可能高的模型,通常使用准确率(Accuracy)、AUC、F1分数或对数损失(Log Loss)等指标来排名。

1. 竞赛流程概述

一个典型的竞赛流程如下:

  • 问题定义:明确任务类型(分类、回归)和评估指标。
  • 探索性数据分析(EDA):理解数据分布、缺失值、异常值和特征相关性。
  • 数据预处理与特征工程:清洗数据,并创造性地构建对模型有帮助的新特征。
  • 模型选择与训练:选择合适的基线模型,并进行调参。
  • 模型集成:将多个模型的预测结果结合起来,获得更稳健的预测。
  • 提交与迭代:提交预测结果,根据排行榜反馈优化策略。

2. 特征工程:竞赛的灵魂

在竞赛中,好的特征工程往往比使用更复杂的模型更有效。

  • Target Encoding:对于高基数类别特征(如用户ID、邮政编码),直接将其替换为该类别下目标变量的均值(需注意防止数据泄露,使用交叉验证法)。
  • 特征交互:手动创建特征之间的组合,例如特征A / 特征B特征A * 特征B
  • 时间特征:对于时间序列数据,提取出年、月、日、星期几、是否为周末、是否为假日等。

3. 模型集成:制胜法宝

集成学习是竞赛冠军的标配,它能有效降低模型的方差,提高泛化能力。

  • Stacking/Blending:使用一个“元模型”来学习多个基模型预测结果的组合权重。
  • 加权平均:简单但有效,根据每个模型在验证集上的表现分配不同的权重进行平均。

4. 超参数优化与实验管理

  • 高效搜索:使用随机搜索(Random Search)或贝叶斯优化(如Optuna)代替网格搜索。
  • 版本控制:使用MLflowW&B (Weights & Biases)来记录每次实验的参数、指标和模型,便于回溯和比较。

代码示例

下面是一个完整的、模拟竞赛流程的端到端示例,我们将使用合成数据演示关键技巧。

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split, cross_val_predict
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.metrics import accuracy_score, log_loss
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier
from sklearn.linear_model import LogisticRegression
import warnings
warnings.filterwarnings('ignore')

# 1. 创建合成数据集
np.random.seed(42)
n_samples = 1000
data = pd.DataFrame({
    'age': np.random.randint(18, 70, n_samples),
    'income': np.random.normal(50000, 15000, n_samples),
    'city': np.random.choice(['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen'], n_samples),
    'has_car': np.random.choice([0, 1], n_samples, p=[0.6, 0.4]),
    'target': np.random.choice([0, 1], n_samples, p=[0.7, 0.3])  # 模拟二分类目标
})
# 人为制造一些关联性,让模型有得学
data.loc[data['city'] == 'Shanghai', 'target'] = np.random.choice([0,1], sum(data['city'] == 'Shanghai'), p=[0.5, 0.5])
data.loc[data['income'] > 60000, 'target'] = np.random.choice([0,1], sum(data['income'] > 60000), p=[0.4, 0.6])

print("原始数据样本:")
print(data.head())

# 2. 基础预处理
# 处理缺失值(本示例数据无缺失,展示思路)
# data['income'].fillna(data['income'].median(), inplace=True)

# 特征工程
# 2.1 Target Encoding (示例,需小心使用)
# 使用交叉验证方式计算目标编码,避免数据泄露
def target_encode_cv(df, cat_col, target_col, n_splits=5):
    df_encoded = df.copy()
    encoded_series = pd.Series(index=df.index, dtype=float)
    
    # 简单划分,实际应用中应使用交叉验证
    kf = KFold(n_splits=n_splits, shuffle=True, random_state=42)
    for train_idx, val_idx in kf.split(df):
        train_df, val_df = df.iloc[train_idx], df.iloc[val_idx]
        means = train_df.groupby(cat_col)[target_col].mean()
        encoded_series.iloc[val_idx] = val_df[cat_col].map(means).values
    
    # 用全局均值填充未见过的类别
    global_mean = df[target_col].mean()
    encoded_series.fillna(global_mean, inplace=True)
    return encoded_series

# 注意:在实际竞赛中,应使用专门的库或自己实现严谨的交叉编码
from sklearn.model_selection import KFold
data['city_encoded'] = target_encode_cv(data, 'city', 'target')

# 2.2 特征交互
data['income_per_age'] = data['income'] / data['age']

# 2.3 准备特征和目标
features = ['age', 'income', 'has_car', 'city_encoded', 'income_per_age']
X = data[features]
y = data['target']

# 3. 模型训练与集成
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 3.1 训练多个异构模型
model_gb = GradientBoostingClassifier(n_estimators=100, random_state=42)
model_rf = RandomForestClassifier(n_estimators=100, random_state=42)
model_lr = LogisticRegression(random_state=42, max_iter=1000)

model_gb.fit(X_train_scaled, y_train)
model_rf.fit(X_train_scaled, y_train)
model_lr.fit(X_train_scaled, y_train)

# 3.2 评估单个模型
preds_gb = model_gb.predict(X_test_scaled)
preds_rf = model_rf.predict(X_test_scaled)
preds_lr = model_lr.predict(X_test_scaled)

print("\n单个模型在测试集上的准确率:")
print(f"Gradient Boosting: {accuracy_score(y_test, preds_gb):.4f}")
print(f"Random Forest: {accuracy_score(y_test, preds_rf):.4f}")
print(f"Logistic Regression: {accuracy_score(y_test, preds_lr):.4f}")

# 3.3 简单加权平均集成(基于交叉验证分数)
# 假设通过交叉验证,我们知道GB表现最好,给更高权重
prob_gb = model_gb.predict_proba(X_test_scaled)[:, 1]
prob_rf = model_rf.predict_proba(X_test_scaled)[:, 1]
prob_lr = model_lr.predict_proba(X_test_scaled)[:, 1]

# 加权平均概率
weight_gb, weight_rf, weight_lr = 0.5, 0.3, 0.2
prob_ensemble = weight_gb * prob_gb + weight_rf * prob_rf + weight_lr * prob_lr
preds_ensemble = (prob_ensemble > 0.5).astype(int)

print(f"\n加权平均集成准确率: {accuracy_score(y_test, preds_ensemble):.4f}")

# 4. 生成提交文件(竞赛核心)
submission = pd.DataFrame({
    'Id': X_test.index,  # 在真实竞赛中,Id列通常是预先给定的
    'Target': preds_ensemble  # 或 prob_ensemble 用于概率输出
})
# submission.to_csv('submission.csv', index=False)
print("\n模拟提交文件内容:")
print(submission.head())

实践练习

练习1:特征工程探索

要求:在上述代码的基础上,尝试添加以下新特征,并观察提交(或测试集)分数的变化:

  1. age_group: 将年龄分箱为 [18, 30), [30, 50), [50, 70]
  2. income_age_ratio: income / age(已创建,可尝试其他组合)。 预期:报告哪个新特征对模型提升最明显。

练习2:调参与集成优化

要求

  1. GradientBoostingClassifier 使用 RandomizedSearchCV 寻找更优的 n_estimators, max_depth, learning_rate 参数。
  2. 将优化后的GB模型加入集成,并调整三个模型的权重,尝试找到最优的权重组合。 预期:输出优化后的模型参数和集成后的准确率,并与原始结果对比。

练习3:处理缺失值与类别特征(进阶)

要求:假设 income 列有10%的随机缺失值,city 列有一个新类别 'Unknown' 出现在测试集中。

  1. 使用合适的策略填充 income 的缺失值(如中位数、模型预测)。
  2. 修改 target_encode_cv 函数,使其能够稳健地处理未知类别。
  3. 比较直接丢弃缺失行与智能填充后模型性能的差异。 预期:展示处理缺失值前后的测试集分数变化。

常见错误

  1. 忽视特征工程,沉迷于调参:初学者常花大量时间调模型参数,却忽略了创建更有信息量的特征。记住,数据和特征决定了模型的上限,算法只是逼近这个上限
  2. 数据泄露:这是竞赛中的大忌。例如,在标准化时使用了整个数据集的均值方差,或在做Target Encoding时使用了验证集的目标值来计算编码。务必确保所有预处理步骤都仅基于训练数据。
  3. 过度调参导致过拟合排行榜:反复提交,根据公开排行榜的分数来调整模型,可能会使模型过度拟合于测试集的特定分布,导致最终名次下滑(因为私有排行榜可能不同)。应以本地交叉验证分数为主要指导。
  4. 集成模型过于同质:集成效果最好的模型通常是“好而不同”的。只集成多个结构相同(如都是GBDT)、参数相近的模型,提升有限。尝试集成树模型、线性模型、甚至神经网络。
  5. 不记录实验:没有记录每次尝试的特征、参数和结果,导致无法复现最好的模型,也无法从失败中学习。务必使用MLflow或笔记进行记录。

小结

  • 竞赛精髓:表格数据竞赛的核心在于通过精巧的特征工程挖掘数据潜力,并利用模型集成来获得稳定且强大的预测。
  • 特征工程第一:投入80%的时间在理解数据、清洗数据和创造新特征上。Target Encoding、特征交互、分箱等都是强大武器。
  • 系统实验:建立清晰的实验流程,从数据处理到模型训练,每一步都可配置、可复现、可记录。
  • 避免陷阱:时刻警惕数据泄露和过拟合排行榜,以本地的、稳健的验证策略为行动指南。
  • 协作与学习:竞赛是学习的极佳途径。多阅读获胜方案(Winning Solutions),学习他人的特征工程思路和模型技巧,并在遵守规则的前提下与他人协作。

掌握了这些技巧,你已经具备了在众多表格数据竞赛中一展身手、取得优异名次的能力。现在,就去Kaggle上寻找一个你感兴趣的竞赛开始实践吧!

练习编辑器

rust
Loading...

继续学习

完成本课后,建议继续学习下一课「实战:端到端机器学习项目全流程」 以巩固所学知识。