【机器学习】(18)—— 泛化与过拟合

泛化与过拟合入门:训练集效果很好

摘要:模型在训练集上损失很低,上线却翻车——这几乎是每个入门者都会撞上的墙。根因往往不是「没换更炫的算法」,而是没有在未见数据上检验泛化。本文讲清泛化(Generalization)过拟合 / 欠拟合,以及为什么要把数据分成训练 / 验证 / 测试三份。贯穿汽车重量与油耗示例。适合读完特征工程系列的读者;本单元后续篇会继续讲数据特性、类别不平衡与损失曲线精读。


1. 先认清优先级:数据往往比算法更值钱

学完线性回归、逻辑回归、特征处理之后,很多人下一步会想:换个更复杂的模型会不会立刻变强?

项目里经验往往相反——数据集的质量与规模,通常比「更炫的算法」更能拉开差距。构造数据、清洗、特征工程,常常占掉项目大部分时间。算法当然重要,但若训练分布漂了、划分乱了、过拟合没拦住,再好的损失公式也白搭。

请添加图片描述

本篇开始进入「数据集、泛化与过拟合」单元。这一单元内容多,专栏会拆开写:

篇次聚焦
本篇(18)泛化、过/欠拟合、训练/验证/测试三分法
后续篇数据特性与标签、类别不平衡、划分细节
再后续模型复杂度、L2 加深、损失曲线怎么读

第 07 篇已从 Log Loss 角度提过正则化;本篇把它放回 「新数据上好不好」 这一更大目标里。


2. 什么是泛化

机器学习的目标,不是把训练集背下来,而是在新样本上仍能做出靠谱预测。这种能力叫泛化(Generalization)

请添加图片描述

专栏例子:用汽车重量预测 MPG 或「是否高效」。你真正关心的是:

  • 下一辆没进训练集的车,预测是否靠谱?
  • 不是:那 7 辆训练车能不能拟合到小数点后很多位?
概念一句话
训练表现模型在「已见过」样本上的对错
泛化表现模型在「未见过」样本上的对错
目标泛化要好,而不只是训练损失漂亮

没有泛化,模型只是一份「带权重的备忘录」。


3. 过拟合与欠拟合

3.1 过拟合:实验室满分,野外零分

过拟合(Overfitting) 指模型把训练集的细节、噪声也「记住」了,以致在新数据上预测变差。

直觉类比:考试只刷了同一套卷子的怪题,换一套正常卷就崩——不是不会,是背偏了。

在重量–MPG 散点上,可以想象三条拟合线:

请添加图片描述

类型训练集新数据常见原因
欠拟合也差模型太简单、特征不够、训练不足
恰当拟合较好较好复杂度与数据匹配
过拟合极好变差模型过复杂、样本少、噪声被学进去

过拟合的两大主因可以记成:

  1. 训练数据不能代表真实世界(或代表不了验证/测试分布)
  2. 模型相对数据量过于复杂

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.5018训练
3.6915训练
3.4418训练
3.4316训练
4.3415验证
4.4214测试
2.3724测试

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. 小结

泛化问的是:「没见过的车,你还能不能估准?」过拟合是训练集虚好看、新数据掉链子;欠拟合是连训练都学不会。挡住过拟合的第一道工程防线,不是盲目换大模型,而是:

打乱并划分 → 只用训练集学参数 → 用验证集调参与监控 → 最后用测试集验收

同时盯住训练损失与验证损失:一旦验证损失掉头向上,就要警惕过拟合。

下一篇继续本单元,深入数据特性、标签与划分中的隐藏坑(重复样本、分布不一致、非平稳等)。

系列导航


如果本篇对你有帮助,欢迎点赞、收藏、关注博主,机器学习专栏持续更新中,下次更新不迷路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值