引言
2007 年,一个名叫 David Cournapeau 的研究者在 Google Summer of Code 项目中启动了一个不起眼的 Python 库——Scikit-learn。当时没有人能预见到,这个项目将彻底改变机器学习的面貌。在此之前,使用机器学习算法意味着你要么自己从零实现,要么使用晦涩难懂的学术软件包。Scikit-learn 统一了所有算法的接口:fit()、predict()、score()——三行代码就能跑通一个模型。
机器学习从来不只是算法。从数据到部署的完整流程中,工程实践往往比算法选择更重要。业界有一个广为流传的经验法则:数据科学家 80% 的时间花在数据清洗和准备上,只有 20% 的时间用于建模。这个法则至今依然成立。
数据:机器学习的燃料
"垃圾进,垃圾出"
数据对机器学习的意义,就像燃料对引擎的意义——再好的引擎,灌进劣质燃料也跑不动。这句古老的计算机格言在机器学习时代被赋予了全新的分量。
AI 系统 = 数据 + 算法 + 算力
算法决定了方法论的上限
数据决定了模型能达到的实际水平
算力决定了训练的可行性
在实践中:数据工作的耗时占比通常是 60-80%数据的维度
| 维度 | 说明 | 影响 |
|---|---|---|
| 数量 | 数据样本的多少 | 太少 → 欠拟合/过拟合 |
| 质量 | 标签是否准确、特征是否有效 | 垃圾进,垃圾出(GIGO) |
| 多样性 | 数据是否覆盖各种场景 | 偏差 → 模型在特定群体上表现差 |
| 平衡性 | 各类别的样本数量是否均衡 | 不平衡 → 模型偏向多数类 |
数据预处理步骤
原始数据
│
├── 1. 数据清洗
│ 处理缺失值、异常值、重复数据
│
├── 2. 数据转换
│ 数值归一化、类别编码、文本分词
│
├── 3. 特征构造
│ 从原始数据中创建新特征
│
└── 4. 数据划分
训练集 / 验证集 / 测试集
为什么要划分?
训练集:训练模型参数
验证集:调超参数、选择模型
测试集:最终评估(只用一次)特征工程
Netflix Prize:特征工程的百万美元课堂
2006 年,Netflix 发起了一场震惊业界的竞赛:谁能把推荐系统的准确率提高 10%,就能拿走 100 万美元奖金。来自全球的团队激烈角逐了整整三年。最终的获胜团队用了什么秘诀?不是更花哨的算法——而是更精巧的特征工程。他们把用户观影时间、评分的时间间隔、电影的发行年份等看似无关的信息转化为强有力的特征,才最终达成了目标。
这场竞赛给整个行业上了一课:在传统机器学习中,特征工程是决定模型性能的最关键因素。
什么是特征工程?
特征工程是将原始数据转化为模型能更好利用的形式的过程。
原始数据 → 特征工程 → 特征向量 → 模型
例子:
原始数据:一封邮件的文本
特征工程:
├── 词频统计(TF-IDF)
├── 是否包含特定关键词
├── 邮件长度
├── 发件人是否在通讯录
└── 链接数量
特征向量:[0.3, 1, 256, 0, 3]常见特征工程技术
| 技术 | 说明 | 适用场景 |
|---|---|---|
| 标准化 | 将特征缩放到均值为 0、方差为 1 | 数值特征,距离敏感算法 |
| 归一化 | 将特征缩放到 [0,1] | 神经网络输入 |
| One-Hot 编码 | 将类别转为二进制向量 | 类别特征 |
| 文本向量化 | TF-IDF、词袋模型 | 文本数据 |
| 特征交叉 | 将两个特征组合 | 发现交互效应 |
| 特征选择 | 去除无用特征 | 降维、减少噪声 |
特征工程 vs 深度学习
传统机器学习:
人类手动设计特征 → 模型学习特征到标签的映射
深度学习:
原始数据 → 模型自动学习特征表示 → 输出
深度学习的「端到端」学习减少了对人工特征工程的依赖,
但并不意味着特征工程消失了——数据预处理和增强仍然重要。模型评估
分类指标
评估模型是机器学习工程中最容易被忽视、却又最关键的环节。一个看似"准确率 99%"的模型,可能在真实场景中毫无用处。
| 指标 | 公式 | 含义 |
|---|---|---|
| 准确率(Accuracy) | 正确预测数 / 总数 | 整体正确率 |
| 精确率(Precision) | TP / (TP+FP) | 预测为正的样本中,真正为正的比例 |
| 召回率(Recall) | TP / (TP+FN) | 真正为正的样本中,被找出来的比例 |
| F1 分数 | 2×P×R/(P+R) | 精确率和召回率的调和平均 |
混淆矩阵:
预测为正 预测为负
实际为正 TP FN
实际为负 FP TN为什么准确率不够?
一个疾病检测场景:
1000 人中只有 10 人患病
模型永远预测「没病」:
准确率 = 990/1000 = 99%!
但这个模型完全没用——它一个病人都没检出。
此时需要看召回率:召回率 = 0/10 = 0%交叉验证
5 折交叉验证:
第 1 轮:[验证] [训练] [训练] [训练] [训练]
第 2 轮:[训练] [验证] [训练] [训练] [训练]
第 3 轮:[训练] [训练] [验证] [训练] [训练]
第 4 轮:[训练] [训练] [训练] [验证] [训练]
第 5 轮:[训练] [训练] [训练] [训练] [验证]
最终得分 = 5 轮得分的平均值
好处:更可靠地评估模型性能,减少数据划分的随机性影响回归指标
| 指标 | 含义 |
|---|---|
| MAE(平均绝对误差) | 预测值与真实值之差的绝对值的平均 |
| MSE(均方误差) | 预测值与真实值之差的平方的平均 |
| RMSE(均方根误差) | MSE 的平方根,与原始数据同量纲 |
| R² | 模型解释的方差比例,1 为完美 |
正则化:防止过拟合
L1 正则化(Lasso)
损失函数 = 原始损失 + λ × Σ|wᵢ|
效果:使部分权重变为 0 → 自动特征选择L2 正则化(Ridge)
损失函数 = 原始损失 + λ × Σwᵢ²
效果:使所有权重趋向较小的值 → 防止某个特征权重过大Dropout(深度学习专用)
训练时:随机「关闭」一部分神经元(设为 0)
正常网络: Dropout 网络:
○ ──→ ● ○ ──→ ●
○ ──→ ● ○ ──→ ○ ← 被关闭
○ ──→ ● ○ ──→ ●
效果:防止神经元过度依赖彼此 → 类似隐式集成的效果机器学习工具链
从 Weka 到 Scikit-learn 的民主化之路
在 Scikit-learn 出现之前,机器学习的工具生态是高度碎片化的。Wka 提供了图形界面但灵活性不足,LibSVM 只做一件事但做得极好,MATLAB 昂贵且封闭。2007 年 Scikit-learn 的出现,第一次让任何人都能用几行 Python 代码实现专业的机器学习流程。
2000 年代的工具
| 工具 | 用途 | 时间 |
|---|---|---|
| Weka | 通用机器学习 GUI | 1997 |
| LibSVM | SVM 实现 | 2000 |
| Scikit-learn | Python 机器学习库 | 2007 |
| MATLAB | 科学计算 | 更早 |
Scikit-learn 的影响
Scikit-learn(2007 年首次发布)统一了机器学习的 API:
# 所有模型都遵循同样的接口
model = SomeAlgorithm(参数)
model.fit(X_train, y_train) # 训练
y_pred = model.predict(X_test) # 预测
score = model.score(X_test, y_test) # 评估这种统一的接口设计极大地降低了机器学习的入门门槛。它不仅是一个工具库,更是一种工程哲学:好的 API 设计可以让复杂的技术变得平易近人。
本节小结
| 概念 | 要点 |
|---|---|
| 数据 | 数据量、质量、多样性决定模型上限 |
| 特征工程 | 传统 ML 最关键的环节,深度学习部分自动化了这一步 |
| 模型评估 | 准确率不够,需要精确率、召回率、交叉验证等 |
| 正则化 | L1/L2/Dropout,防止模型过拟合 |
| 工具链 | Scikit-learn 统一了 API,降低了入门门槛 |
思考题
- 为什么说「80% 的机器学习工作是数据相关工作」?如果给你一个预测房价的任务,你会花多少时间在数据上?
- 在深度学习时代,特征工程是否变得不重要了?为什么?
- 如果你的模型在测试集上表现很好但在真实环境中表现很差,可能的原因有哪些?
延伸阅读
- Müller, A.C. & Guido, S. (2016). Introduction to Machine Learning with Python — 以 Scikit-learn 为核心的实践指南
- Zheng, A. & Casari, A. (2018). Feature Engineering for Machine Learning — 特征工程的系统方法论