泛化与过拟合入门:训练集效果很好
文章目录
摘要:模型在训练集上损失很低,上线却翻车——这几乎是每个入门者都会撞上的墙。根因往往不是「没换更炫的算法」,而是没有在未见数据上检验泛化。本文讲清泛化(Generalization)、过拟合 / 欠拟合,以及为什么要把数据分成训练 / 验证 / 测试三份。贯穿汽车重量与油耗示例。适合读完特征工程系列的读者;本单元后续篇会继续讲数据特性、类别不平衡与损失曲线精读。
1. 先认清优先级:数据往往比算法更值钱
学完线性回归、逻辑回归、特征处理之后,很多人下一步会想:换个更复杂的模型会不会立刻变强?
项目里经验往往相反——数据集的质量与规模,通常比「更炫的算法」更能拉开差距。构造数据、清洗、特征工程,常常占掉项目大部分时间。算法当然重要,但若训练分布漂了、划分乱了、过拟合没拦住,再好的损失公式也白搭。

本篇开始进入「数据集、泛化与过拟合」单元。这一单元内容多,专栏会拆开写:
| 篇次 | 聚焦 |
|---|---|
| 本篇(18) | 泛化、过/欠拟合、训练/验证/测试三分法 |
| 后续篇 | 数据特性与标签、类别不平衡、划分细节 |
| 再后续 | 模型复杂度、L2 加深、损失曲线怎么读 |
第 07 篇已从 Log Loss 角度提过正则化;本篇把它放回 「新数据上好不好」 这一更大目标里。
2. 什么是泛化
机器学习的目标,不是把训练集背下来,而是在新样本上仍能做出靠谱预测。这种能力叫泛化(Generalization)。

专栏例子:用汽车重量预测 MPG 或「是否高效」。你真正关心的是:
- 下一辆没进训练集的车,预测是否靠谱?
- 不是:那 7 辆训练车能不能拟合到小数点后很多位?
| 概念 | 一句话 |
|---|---|
| 训练表现 | 模型在「已见过」样本上的对错 |
| 泛化表现 | 模型在「未见过」样本上的对错 |
| 目标 | 泛化要好,而不只是训练损失漂亮 |
没有泛化,模型只是一份「带权重的备忘录」。
3. 过拟合与欠拟合
3.1 过拟合:实验室满分,野外零分
过拟合(Overfitting) 指模型把训练集的细节、噪声也「记住」了,以致在新数据上预测变差。
直觉类比:考试只刷了同一套卷子的怪题,换一套正常卷就崩——不是不会,是背偏了。
在重量–MPG 散点上,可以想象三条拟合线:

| 类型 | 训练集 | 新数据 | 常见原因 |
|---|---|---|---|
| 欠拟合 | 差 | 也差 | 模型太简单、特征不够、训练不足 |
| 恰当拟合 | 较好 | 较好 | 复杂度与数据匹配 |
| 过拟合 | 极好 | 变差 | 模型过复杂、样本少、噪声被学进去 |
过拟合的两大主因可以记成:
- 训练数据不能代表真实世界(或代表不了验证/测试分布)
- 模型相对数据量过于复杂
3.2 欠拟合:连实验室都不过关
欠拟合(Underfitting) 连训练数据都拟合不好。例如硬用水平直线去拟合「越重越费油」的明显趋势——不是泛化问题,是表达能力或训练流程先坏了。
专栏早期若只用极简假设、训练轮次过少,也会出现欠拟合;过拟合则更常在特征很多、交叉很多、神经网络很深、样本很少时出现。
4. 如何发现过拟合:看泛化曲线
只看训练集损失会自我安慰。正确做法是同时盯训练集损失与验证集损失。两条曲线画在一起,常叫泛化曲线(Generalization Curve)。

典型过拟合信号:
- 前期:两条曲线一起下降
- 之后:训练损失继续降或持平,验证损失开始上升
验证损失最低点附近,往往是早停(Early Stopping)的候选位置——第 07 篇提过早停,本篇从「划分数据」角度再强调:没有验证集,你甚至看不到这条上升的红线。
5. 为什么要三分:训练 / 验证 / 测试
5.1 只用「训练 + 测试」的隐患
传统想法是切成两份:训练集学参数,测试集看效果。问题在于:如果你反复根据测试集分数去调学习率、加特征、改模型,测试集就慢慢变成「间接训练集」——像老师总对着期末原题讲评,分数虚高。
5.2 更好的做法:三份

| 子集 | 作用 | 使用频率 |
|---|---|---|
| 训练集 Training | 更新 w , b w,b w,b 等参数 | 每次迭代 |
| 验证集 Validation | 调超参、选特征、选模型版本 | 开发阶段可多次,但会「磨损」 |
| 测试集 Test | 最终验收,代理真实世界 | 尽量少碰,成熟后再测 |
比例没有唯一正确答案。数据够大时,常见是训练占大部分,验证与测试各留一小块;数据很少时,验证/测试也要够做有统计意义的比较,否则一次波动就误导决策。
5.3 好的验证/测试集要满足什么
- 够大:能看出稳定差异,不是碰运气
- 有代表性:分布应接近整体数据,也尽量接近线上真实情况
- 与训练集无重复样本:重复等于「开卷考试」
- 划分前充分打乱:否则时间序、来源序会造成分布错位
测试集再漂亮,若整份数据和真实业务差很远,上线仍可能翻车——那时该查的是数据是否过时、是否非平稳,而不是再把同一测试集刷一遍。

6. 泛化背后的三条数据假设
要让「用验证/测试近似真实世界」说得通,数据通常还需近似满足:
| 假设 | 含义 | 反例直觉 |
|---|---|---|
| 独立同分布(i.i.d.) | 样本彼此不互相决定,来自同一分布 | 同一封垃圾邮件复制几百行 |
| 平稳(Stationary) | 分布不随时间剧变 | 用十年前观影口味预测未来三年爆款 |
| 各划分同分布 | 训练/验证/测试统计特性相近 | 训练集全是夏日数据,测试全是冬日数据 |
汽车油耗若混入多年、多车型,划分前要打乱,并检查各集合重量、品牌比例是否离谱——否则「测试损失低」只说明你切到了相似切片,不代表能泛化到新车市。
这些假设的细讲、标签质量、类别不平衡,留给本单元后续篇。
7. 汽车示例:一次最小可行划分
把专栏熟悉的 7 辆车想象成「迷你数据集」(真实项目样本会多得多,这里只演示流程):
| 重量 | MPG | 用途建议 |
|---|---|---|
| 3.50 | 18 | 训练 |
| 3.69 | 15 | 训练 |
| 3.44 | 18 | 训练 |
| 3.43 | 16 | 训练 |
| 4.34 | 15 | 验证 |
| 4.42 | 14 | 测试 |
| 2.37 | 24 | 测试 |
7 条实在太少,验证/测试各 1~2 条没有统计意义——这恰恰说明:小样本时更要警惕「偶然分到简单题」。真实项目应保证验证与测试足够大,并报告多个指标(如第 10、11 篇的召回率、AUC),而不是只看一次损失。
若你用高次多项式把 4 个训练点拟合得几乎零误差,验证点却偏离很远,就是微型过拟合现场。
8. 动手:用划分发现「虚高」的训练分
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.pipeline import Pipeline
# 稍扩一点的合成重量-MPG:负相关 + 噪声
rng = np.random.default_rng(42)
weight = rng.uniform(2.2, 4.6, size=80)
mpg = 34 - 4.6 * weight + rng.normal(0, 1.2, size=80)
X = weight.reshape(-1, 1)
y = mpg
# 先切出测试集;再从剩余里切验证集
X_tv, X_test, y_tv, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
X_train, X_val, y_train, y_val = train_test_split(X_tv, y_tv, test_size=0.25, random_state=0)
# 此时约:训练 60% / 验证 20% / 测试 20%
def eval_degree(degree):
model = Pipeline([
("poly", PolynomialFeatures(degree=degree, include_bias=False)),
("lr", LinearRegression()),
])
model.fit(X_train, y_train)
return {
"degree": degree,
"train_mse": mean_squared_error(y_train, model.predict(X_train)),
"val_mse": mean_squared_error(y_val, model.predict(X_val)),
"test_mse": mean_squared_error(y_test, model.predict(X_test)),
}
for d in [1, 3, 8]:
print(eval_degree(d))
你会看到类似趋势:degree=1 训练与验证都还体面;degree=8 时训练 MSE 很低,验证 MSE 抬高——这就是用验证集抓住过拟合。测试集应在选定次数之后再看一次,而不是每次改 degree 都盯着测试分数调参。
9. 能力边界与常见误区
9.1 适用边界
- 本篇讲监督学习里最通用的三分法直觉;时间序列、推荐系统常有更专门的划分方式(按时间切、按用户切),下一篇会涉及「别乱打乱」的情形。
- 正则化、早停、降低特征交叉复杂度,都能抑制过拟合;细节第 07 篇已有入口,本单元后续会再对照损失曲线展开。
9.2 常见误区
| 误区 | 正解 |
|---|---|
| 训练准确率很高 = 模型很强 | 可能过拟合;要看验证/测试 |
| 有测试集就可以反复调参 | 把验证集与测试集职责分开 |
| 验证集越大越好 | 与训练样本是此消彼长;两边都要够用 |
| 打乱一次就万事大吉 | 还要查重复、分布是否一致、是否平稳 |
| 测试很好就一定上线很好 | 数据可能已过时或与真实分布脱节 |
| 过拟合只能换更简单模型 | 也可加数据、正则、早停、减特征 |
10. 关键术语速查
| 术语 | 一句话解释 |
|---|---|
| 泛化 | 在新数据上仍预测得好的能力 |
| 过拟合 | 过度贴合训练细节,新数据变差 |
| 欠拟合 | 连训练数据都学不好 |
| 训练集 | 用来更新模型参数的样本 |
| 验证集 | 用来调超参与做模型选择的样本 |
| 测试集 | 最终评估、尽量少用的样本 |
| 泛化曲线 | 训练损失与验证损失随训练进程的对比图 |
| 早停 | 在验证损失变差前提前结束训练 |
11. 延伸阅读
| 资源 | 适合看什么 |
|---|---|
| sklearn train_test_split | 划分训练/测试的基本 API |
| sklearn 模型选择概述 | 交叉验证与评估流程 |
| 专栏第 07 篇 | Log Loss、L2 与早停 |
| 专栏第 04 篇 | 学习率等超参为何要靠验证集调 |
| 专栏第 11 篇 | 分类场景用 AUC 等做集外评估 |
12. 小结
泛化问的是:「没见过的车,你还能不能估准?」过拟合是训练集虚好看、新数据掉链子;欠拟合是连训练都学不会。挡住过拟合的第一道工程防线,不是盲目换大模型,而是:
打乱并划分 → 只用训练集学参数 → 用验证集调参与监控 → 最后用测试集验收
同时盯住训练损失与验证损失:一旦验证损失掉头向上,就要警惕过拟合。
下一篇继续本单元,深入数据特性、标签与划分中的隐藏坑(重复样本、分布不一致、非平稳等)。
系列导航:
- 上一篇:【机器学习】(17)—— 类别特征处理入门
- 下一篇(预告):数据特性与数据集划分中的常见坑
如果本篇对你有帮助,欢迎点赞、收藏、关注博主,机器学习专栏持续更新中,下次更新不迷路。
—— 泛化与过拟合&spm=1001.2101.3001.5002&articleId=162905298&d=1&t=3&u=fade2adb0eea47fa883160a75e95dd17)
560

被折叠的 条评论
为什么被折叠?



