我如何应用探索性数据分析、特征工程、Pipeline 和集成模型解决真实世界的机器学习问题——以及我一路学到的经验教训。


引言

在每个机器学习学习者的旅程中,总有一天仅靠观看教程和完成小型练习题已不再足够。

在花费数周时间理解统计学、探索性数据分析(EDA)、特征工程、预处理技术和经典机器学习算法之后,我想回答一个问题:

我能将所学的一切应用于一场真正的机器学习竞赛吗?

于是我决定参加 Kaggle 游乐场竞赛。

与课堂数据集不同,Kaggle 竞赛迫使你像机器学习工程师一样思考。你需要理解杂乱的数据、构建预处理管道、选择模型、评估性能、调试错误,并最终提交与数千名参赛者竞争的结果。

本文记录了我的完整旅程——从加载数据集到构建生产级预处理管道并训练多个集成模型。在此过程中,我还将分享遇到的挑战、有效的方法以及我将带入未来竞赛的经验教训。


为什么选择 Kaggle?

学习机器学习不仅仅是了解算法。

现实世界的机器学习需要回答以下问题:

  • 哪些特征有用?
  • 应如何处理缺失值?
  • 分类变量应该进行独热编码还是序数编码?
  • 哪些预处理步骤应放在 Pipeline 内部?
  • 不同集成模型之间的表现如何?

Kaggle 提供了一个让所有这些问题都变得重要的环境。

你不是构建一个仅在 notebook 中运行的模型,而是在现实约束下解决问题,并在未见过的数据上评估你的方案。


竞赛目标

本游乐场竞赛的目标是基于与健康和生活方式相关的数值和分类特征预测目标类别。

工作流程遵循许多真实世界机器学习项目使用的相同结构。

Raw Dataset
      │
      ▼
Exploratory Data Analysis
      │
      ▼
Missing Value Analysis
      │
      ▼
Feature Engineering
      │
      ▼
Preprocessing Pipeline
      │
      ▼
Model Training
      │
      ▼
Evaluation
      │
      ▼
Prediction
      │
      ▼
Kaggle Submission

Enter fullscreen mode Exit fullscreen mode

虽然工作流程看起来简单,但每个阶段都需要仔细决策。


理解数据集

第一步是使用 Pandas 加载训练集和测试集。

train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")

Enter fullscreen mode Exit fullscreen mode

在编写任何机器学习模型之前,我花时间理解了数据的结构。

我探索的一些问题包括:

  • 数据集包含多少行和列?
  • 哪些特征是数值型的?
  • 哪些特征是分类的?
  • 是否存在缺失值?
  • 每个特征的分布如何?
  • 是否存在明显的异常值?

跳过这一阶段通常会导致模型性能不佳,因为预处理决策完全取决于数据特征。


探索性数据分析(EDA)

EDA 成为本项目最有价值的部分之一。

我没有立即训练模型,而是想理解数据集的行为。

我将特征分为两大类:

数值特征

示例包括:

  • 睡眠时长
  • 心率
  • BMI
  • 热量消耗
  • 步数
  • 运动时长
  • 饮水量

分类特征

示例包括:

  • 饮食类型
  • 性别
  • 吸烟/饮酒
  • 体力活动水平
  • 睡眠质量
  • 压力水平

这种分类让应用不同的可视化技术变得更容易。


可视化数值特征

对于数值列,我使用以下方法探索数据:

  • 直方图
  • KDE 图
  • 箱线图

这些可视化帮助回答重要问题。

特征是否呈正态分布?

一些变量的分布接近正态,而另一些则表现出明显的偏度。

是否存在极端值?

箱线图显示多个数值特征中存在异常值。

数据是否对称?

结合偏度计算和 KDE 图更容易判断是否需要进行变换。

这些可视化让我能够基于证据做出决策,而非盲目预处理。


理解缺失值

我进行的首批分析之一是检查数据集中缺失值的百分比。

train.isnull().mean() * 100

Enter fullscreen mode Exit fullscreen mode

缺失值是真实世界数据集中最常见的问题之一。

忽略它们不可行,因为大多数机器学习算法无法用不完整的数据进行训练。

我决定不在此阶段用单一常量替换所有缺失值,而是稍后在 Pipeline 中使用合适的预处理技术。


探索分类特征

对于分类变量,我创建了计数图以了解每个类别的频率分布。

这些图回答了以下问题:

  • 哪种饮食类型出现频率最高?
  • 体力活动水平如何分布?
  • 性别是否影响某些生活方式变量?
  • 是否存在极罕见的类别?

我还使用分组可视化探索了不同分类变量之间的关系。

这帮助我在训练任何模型之前对数据集建立直觉。


建模前建立直觉

EDA 过程中一个教训变得非常清晰:

更好的理解往往带来更好的预处理。

机器学习不仅仅是选择强大的算法。

输入数据的质量对最终预测的质量有巨大影响。

因此我在进入特征工程之前花了大量时间探索数据。


特征工程

理解数据集后,下一步是为机器学习做准备。

首先将特征与目标变量分离。

X = train.drop(columns=["health_condition"])
y = train["health_condition"]

Enter fullscreen mode Exit fullscreen mode

这清晰区分了:

  • 输入特征(X
  • 目标标签(y

随后将训练数据拆分为训练集和验证集。

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42
)

Enter fullscreen mode Exit fullscreen mode

创建验证集让我能够在提交 Kaggle 之前评估模型性能。


为什么预处理很重要

不同特征类型需要不同的预处理策略。

例如:

特征类型 预处理
数值型 插补 + 缩放
有序分类 序数编码
无序分类 独热编码
目标变量 标签编码

应用错误的预处理技术可能会显著降低模型性能。

我希望找到一个更简洁且可复用的解决方案,而非手动转换每一列。

这正是 Scikit-learn Pipeline 发挥巨大作用的地方。


组织特征

我将特征分为逻辑组。

数值列

需要缩放和缺失值处理的连续数值变量。

有序分类

具有自然顺序的特征,例如活动或压力水平。

这些可以安全转换为有序数值。

无序分类

如性别或饮食类型等特征没有自然顺序。

分配任意数字可能会引入意外关系,因此独热编码是更好的选择。

这种分类使预处理管道更容易维护。


构建生产级预处理管道

我没有为每个模型重复编写预处理代码,而是使用了 Scikit-learn 的 PipelineColumnTransformer

这种方法提供了多个优势:

  • 代码更简洁
  • 降低数据泄露风险
  • 预处理一致
  • 更容易用多个模型进行实验
  • 生产就绪的工作流

Pipeline 会在模型训练前自动执行每个预处理步骤,而非手动逐个应用转换。

这是我相比早期机器学习项目做出的最大改进之一。


构建生产就绪的机器学习管道

本项目相比早期机器学习练习的最大改进之一,是从手动预处理转向构建可复用的 Pipeline。

我使用 Scikit-learn 构建了一个可复用的管道,而非为每个模型编写单独的预处理代码。

这种方法遵循生产机器学习系统使用的相同理念。

一切都在单个工作流中自动化,而非记住数十个预处理步骤。


设计预处理管道

不同特征类型需要不同的转换。

我的预处理工作流程如下:

Raw Dataset
      │
      ▼
Separate Numerical & Categorical Features
      │
      ├───────────────┐
      │               │
      ▼               ▼
 Numerical        Categorical
      │               │
KNN Imputer    Simple Imputer
      │               │
StandardScaler  Encoding
      │               │
      └──────┬────────┘
             ▼
     ColumnTransformer
             ▼
     Machine Learning Model

Enter fullscreen mode Exit fullscreen mode

Pipeline 会自动对每种特征类型应用正确的预处理,而非手动转换每一列。

这使代码更简洁、可复用且更不易出错。


处理缺失值

真实世界数据集中不可避免地存在缺失值。

我没有删除行并丢失宝贵信息,而是根据特征类型应用不同的插补策略。

对于数值特征,我使用了 KNN Imputer

KNN 插补的思路很简单。

它不是用均值或中位数填充缺失值,而是寻找最相似的观测值,并基于这些邻居估计缺失值。

对于分类特征,我使用了 Simple Imputer 并以最频繁类别填充。

这保留了分类数据的完整性,同时避免了不必要的数据丢失。


编码分类变量

机器学习模型无法直接理解文本。

因此,需要将分类变量转换为数值表示。

我将分类列分为两组。

有序特征

这些特征具有自然顺序。

示例包括活动水平或压力水平。

对于这些变量,我使用了 序数编码

Low      → 0
Medium   → 1
High     → 2

Enter fullscreen mode Exit fullscreen mode

由于这些类别具有有意义的顺序,序数编码保留了这种关系。


无序特征

某些特征没有自然顺序。

示例包括性别或饮食类型。

分配如

Male = 0
Female = 1

Enter fullscreen mode Exit fullscreen mode

这样的数字可能会无意中暗示数学关系。

相反,我应用了 独热编码,使每个类别都有自己的二进制列。

这防止模型假设不存在的顺序。


为什么使用 ColumnTransformer

如果没有 ColumnTransformer,预处理很快变得难以管理。

不同特征组需要不同的转换。

ColumnTransformer 允许所有转换在一个统一的预处理阶段完成,而非手动应用每个转换。

这使得实验变得容易得多,因为更改模型不再需要重写预处理代码。


构建可复用管道

创建预处理管道后,我将其与不同的机器学习算法结合。

我只需替换最终估计器,而非为每个模型编写单独的预处理代码。

概念上,每个管道都遵循以下结构:

Preprocessing
        │
        ▼
 Machine Learning Model
        │
        ▼
 Predictions

Enter fullscreen mode Exit fullscreen mode

这让我能够在保持预处理完全一致的情况下比较多个算法。


训练多个集成模型

我没有依赖单一算法,而是训练了多个集成模型来比较它们的性能。

模型包括:

  • Random Forest
  • XGBoost
  • CatBoost
  • LightGBM

每个模型都有自己的优势。


Random Forest

Random Forest 是我的基准集成模型。

其优势包括:

  • 性能稳健
  • 处理非线性关系
  • 抗过拟合
  • 可用于特征重要性

它为我提供了在尝试提升算法之前的一个强基准。


XGBoost

XGBoost 是竞争性机器学习中最流行的梯度提升库之一。

在我的实现中,我配置了以下参数:

  • 300 棵树
  • 学习率 0.05
  • 最大树深度
  • 子采样
  • 列采样
  • 基于直方图的树构建
  • GPU 加速

目标是在预测性能和计算效率之间取得平衡。


CatBoost

CatBoost 在处理包含分类变量的数据集时特别有效。

尽管我的预处理管道已经处理了编码,CatBoost 仍然提供了另一个强大的集成模型用于比较。

我使用 GPU 加速对其进行训练以减少计算时间。


LightGBM

LightGBM 专为效率而设计。

它使用基于直方图的学习和按叶子生长的树,使其在保持竞争性能的同时速度极快。

其高效扩展的能力使其成为 Kaggle 竞赛的热门选择。


评估模型性能

训练模型只是工作流程的一半。

下一步是评估其性能。

我使用多个评估指标比较模型,而非仅依赖准确率。

这些指标包括:

  • 准确率
  • 精确率
  • 召回率
  • F1 分数

每个指标都提供了对模型行为的不同洞察。

查看多个指标有助于避免仅使用准确率可能导致的误导性结论。


分类报告

为了更深入地了解性能,我为每个模型生成了分类报告。

这些报告显示:

  • 每个类别的精确率
  • 每个类别的召回率
  • F1 分数
  • 总体准确率
  • 宏平均
  • 加权平均

这些报告揭示了模型表现良好和表现不佳的地方,而非将其视为黑箱。


混淆矩阵

另一个有价值的可视化是混淆矩阵。

混淆矩阵不仅显示预测错误,还显示模型将哪些类别相互混淆。

这通常能揭示原始准确率无法发现的模式。

对于多分类问题,混淆矩阵提供了对模型弱点的宝贵洞察。


比较模型

我没有分别评估模型,而是创建了一个包含以下指标的比较表:

模型 准确率 精确率 召回率 F1 分数
XGBoost 对比 对比 对比 对比
CatBoost 对比 对比 对比 对比
LightGBM 对比 对比 对比 对比

比较表使识别不同算法之间的权衡变得容易得多。


我学到的经验教训

回顾这次竞赛,它教会我的远不止训练机器学习模型。

一些最重要的教训是:

理解数据比选择模型更重要。

强大的预处理管道通常比切换算法更能提升性能。

Pipeline 节省大量时间。

一切变得模块化和可复用,而非重复编写预处理代码。

评估不应依赖单一指标。

仅靠准确率很少能讲述完整故事。

集成方法很强大。

比较多个算法帮助我理解每种方法的优势和局限。


过程中的挑战

与每个真实项目一样,这次竞赛涉及多次调试。

我遇到了与以下方面相关的问题:

  • 预处理
  • 管道构建
  • 模型实验
  • 评估
  • 提交工作流

虽然这些挑战有时令人沮丧,但解决它们显著提升了我对完整机器学习生命周期的理解。

回想起来,那些调试会话与成功的模型训练一样教会了我很多。


超越 Kaggle 分数

关于 Kaggle 最大的误解之一是成功仅以排行榜位置衡量。

对我而言,真正的成就不仅仅是生成预测。

而是学会如何构建端到端的机器学习工作流。

这个项目要求我将之前单独学习的概念结合在一起:

  • 探索性数据分析
  • 数据清洗
  • 特征工程
  • 缺失值处理
  • 编码
  • 缩放
  • Pipeline
  • 集成学习
  • 模型评估

这些概念首次在一个项目中融合。


最终思考

这次竞赛标志着我机器学习旅程的重要里程碑。

在此项目之前,预处理技术、Pipeline、集成模型和评估指标是我单独学习的主题。

通过真正的 Kaggle 竞赛,我看到了这些部分如何组合在一起解决端到端的机器学习问题。

虽然还有很多要学——从高级特征工程、超参数优化到模型集成和部署——但这次经历让我有信心超越教程,并在实际环境中应用机器学习概念。

如果你刚开始 Kaggle 之旅,我最大的建议很简单:

不要首先追求排行榜。先追求理解。

在数据分析、预处理和实验方面的坚实基础,比记住模型参数更能带你走得更远。每场比赛都是学习、完善工作流并成为更好机器学习实践者的机会。

对我而言,这不仅仅是另一个 notebook——它是将数周学习转化为真实实践的项目。这正是 Kaggle 成为任何认真学习机器学习的人宝贵平台的原因。