Courses
您是否遇到过这样的情况:模型在训练数据上有 99% 的准确率,但一到生产环境几乎什么都预测不准?
能背会与真正学会是两回事。机器学习的核心是泛化——您需要的是在未见过的数据上也能成立的预测,而不仅仅是在训练数据上表现良好。如果不是这样,问题几乎总会落在两个方向之一。
这两个方向就是过拟合和欠拟合。修复之前,您必须先弄清自己正面临哪一个。
本文将带您识别过拟合与欠拟合、理解其成因,并给出帮助您达成平衡的动手步骤。
什么是欠拟合?
当模型过于简单,无法刻画数据中真正发生的关系时,就会出现欠拟合。
想象仅用一条规则来预测房价:“每套房子都值 30 万美元。”这条规则几乎处处错误。它看不到社区、面积、卧室数量、车库空间或建造年份。模型的灵活性远不足以跟随模式。
识别欠拟合的方法始终如一:训练准确率低,测试准确率也低。两个数都不好,但关键在于它们一起都不好。
典型情形是在弯曲的数据上拟合直线。直线从中间穿过,却错过了形状。无论再加多少训练数据都无济于事,因为模型本身无法表示这种关系。

欠拟合示例
什么是过拟合?
过拟合则是相反的问题——模型过于复杂。
它不是学习一般模式,而是记住了训练集。每个噪声点、每个奇怪的离群值、每个峰谷、数据中的每个巧合都被当作真实模式去关注。模型对训练数据近乎完美。
过拟合的好处在于它很容易被发现:训练准确率看起来很棒,但测试准确率很糟糕。
想象一位学生逐字背答案却没有学会底层知识。他在模拟测试中拿高分,却很可能在正式考试中失利。

过拟合示例
过拟合 vs 欠拟合:关键区别
对比之后,区别更容易看清。欠拟合的模型连见过的数据都表现不好;过拟合的模型在没见过的数据上表现不好。
二者在训练期间的表现不同:
- 欠拟合表现为整体平淡、平庸的性能——模型始终学不到多少东西
- 过拟合表现为出现“间隙”:训练分数不断上升,而测试分数停滞甚至随时间变差
它们的成因也相互映照。欠拟合源于“做得不够”:模型过于简单、特征缺失。过拟合源于“做得太多”:模型过于复杂、特征过多。
下面是二者的要点回顾:

欠拟合与过拟合对比
如何识别过拟合与欠拟合
理解理论上的表现是一回事,在自己的模型中把它们揪出来又是另一回事。
最简单的方法是比较训练误差与测试误差,并查看学习曲线。
训练误差 vs 测试误差
最快的检查方法是将数据划分为训练集与测试集,训练模型后分别查看各自的误差。
对于欠拟合,两者都会很高。模型没有很好地学会训练数据,对未见数据也不会更好——两边都很差。
对于过拟合,训练误差会非常低,而测试误差依然很高。模型把训练数据背下来了,但这种“知识”无法迁移。

训练与测试误差可视化
您需要分析这两个数字之间的“间隙”。若间隙小且误差都高,指向欠拟合。若间隙大且训练误差低、测试误差高,指向过拟合。若两者间隙小且都低,这是理想状态,说明模型学到了真实的数据表示。
学习曲线
学习曲线将训练误差与验证误差绘制为训练集规模或训练迭代次数的函数,展示模型学习过程中的动态。
在欠拟合模型中,两条曲线很快在较高误差处趋于平坦。新增数据无济于事,因为模型本就无法表示该模式。两条曲线都维持在高位。

欠拟合模型曲线
在过拟合模型中,训练曲线降至接近零,而验证曲线保持较高。随着训练继续,两者的间隙不断拉大。这条不断扩大的间隙就是图表中的过拟合。

过拟合模型曲线
健康的模型会表现为两条曲线都下降并在较低误差处相遇,且二者间隙很小。
过拟合与欠拟合为何发生
掌握如何识别后,下一个问题是为何会出现。二者都源于模型与问题之间的不匹配,但方向相反。
欠拟合的原因
欠拟合几乎总能追溯到以下三类原因之一:
- 模型过于简单: 线性模型无法表示弯曲的关系。模型的容量达不到问题所需的程度。
- 特征不足: 即便是有能力的模型,如果输入错误也会欠拟合。仅用邮政编码预测房价并不合理,还遗漏了面积、卧室数、房屋状况、房龄与地块大小。模型无从下手。
- 训练不足: 模型没有足够的深度、迭代次数、轮次,或学习率调整来达到良好解。训练过早停止。
过拟合的原因
过拟合源于给予模型的自由度超过数据所需。
- 模型过于复杂: 在小数据集上训练拥有数百万参数的深度神经网络,极易“死记硬背”。容量超出问题所需。
- 特征过多: 当特征数多于数据中有意义的模式时,模型会学到仅在训练样本中偶然存在、却无法泛化的相关性。
- 数据集过小: 训练数据有限时,即便适中复杂度的模型也可能把整套数据背下来。样本不够多,模型无法据此泛化。
- 训练过长: 模型在已学到真实模式后仍继续调整权重,开始去拟合噪声。从那一刻起,继续训练只会让情况变糟。
偏差-方差权衡
偏差-方差权衡解释了为何模型性能在于找到那个甜蜜点:既能很好地泛化到未见数据,又不过度简化问题或对训练集过拟合。
高偏差
偏差是源自模型对数据假设的误差。高偏差模型具有强且简单化的假设,无法表示数据中实际存在的复杂性。
这正是欠拟合。模型过于僵硬以致无法贴合模式,因此无论给多少数据,预测都偏离较大。
若将高偏差模型在不同样本上训练 100 次,这 100 个版本会犯相似的错误。它们的预测会围绕错误答案聚集。
高方差
方差是源自模型对所训练特定数据过度敏感的误差。高方差模型会捕捉每个细小模式,通常是噪声。
这就是过拟合。模型与训练集贴合得非常紧,但训练数据的微小变化就会导致截然不同的预测。
若将高方差模型在不同样本上训练 100 次,您会得到 100 个差异巨大的模型。它们在相同输入上的预测分布四散。
权衡
您无法完全消除偏差或方差,只能在二者之间移动。
通过提升模型复杂度可降低偏差,但方差会上升;通过简化模型可降低方差,但偏差会上升。目标是找到中间点,使总误差最低。

偏差-方差权衡示例
如何修复欠拟合
一旦诊断为欠拟合,有几种方法可以修复。它们都旨在提升模型表示数据模式的能力。
- 提高模型复杂度: 迁移到更灵活的模型。例如从线性回归到多项式回归,或将浅层树加深。
- 增加更多特征: 添加确有价值的新输入。创建交互项、多项式特征,或先前模型无法获取的领域特征。
- 延长训练时间: 模型可能尚未收敛。给予更多轮次或调整学习率调度。
- 降低正则化强度: 正则化会让模型更简单,这与解决欠拟合的方向相反。降低正则化强度或暂时移除,让模型更自由。
少量优质特征往往比更换架构更见效。在调整模型本身之前,先从这里入手。
如何修复过拟合
修复过拟合则反其道而行。您需要约束模型,使其不再“背”训练数据。
- 收集更多数据: 更大的数据集会显著增加模型“背答案”的难度。更多样本迫使模型找到贯穿整体的数据模式,而非仅适用于少数几行的关系。
- 应用正则化: L1 和 L2 正则化 会对较大的权重施加惩罚,从而防止模型过度依赖单个特征。这是最可靠的修复之一。
- 降低模型复杂度: 若模型相对于数据而言过大,则缩小它。减少参数、降低树深度或缩小网络规模。
- 使用交叉验证: 交叉验证 能更真实地反映模型在未见数据上的表现,用单个数据集获得更多训练-测试切分。
- 在神经网络中应用 Dropout: Dropout 在训练中随机禁用一定比例的神经元,迫使网络学习冗余表示,从而降低对某个单一神经元的依赖。
- 提前停止训练: 监控验证误差,一旦其开始上升(即便训练误差仍在下降)就停止训练。这称为早停法,是最容易实施的改动之一。
正则化与早停通常是首选。它们几乎没有成本且往往有效。
不同模型中的过拟合与欠拟合
不同模型家族呈现欠拟合与过拟合的方式各不相同。以下是三类常见模型在两个方向上的失效方式。
线性模型
- 欠拟合: 线性模型假设直线关系。当真实模式是曲线时,无论给多少数据,模型都无法跟随。
- 过拟合: 当添加足够多的多项式或交互项时,即便是线性回归也能“记住”噪声。岭回归(Ridge)与套索回归(Lasso)等方法主要就是为此而生。
决策树
- 欠拟合: 浅层树只能做少数几次划分。仅靠两三次决策,无法表达需要更多细节的模式。
- 过拟合: 深树易过拟合。若一直划分直到每个叶子仅包含一个训练样本,训练准确率将达到完美而测试准确率很差。这也是为何会有
max_depth、min_samples_split与剪枝等参数。
神经网络
- 欠拟合: 规模过小的网络会欠拟合。过早停止训练或优化器陷入次优解也会导致欠拟合。
- 过拟合: 在深度学习中更常见。拥有数百万参数的网络在给足轮次时,甚至可以“记住”大型数据集。Dropout、权重衰减、数据增广与早停都是为防止这一点而存在。
过拟合与欠拟合的更多示例
接下来通过两个经典示例与代码,直观展示这些模式。
多项式回归
带噪声的正弦波是个不错的测试场景。用不同次数的多项式来拟合,您会看到模型行为的变化。
import numpy as np
# Data
np.random.seed(7)
X = np.linspace(0, 1, 30)
y_true = np.sin(2 * np.pi * X)
y = y_true + np.random.normal(0, 0.2, X.shape)
# Fit polynomials of three degrees
X_smooth = np.linspace(0, 1, 300)
degrees = [1, 3, 15]
for degree in degrees:
coefs = np.polyfit(X, y, deg=degree)
y_pred = np.polyval(coefs, X_smooth)

多项式回归示例
一次项是条直线,产生欠拟合,完全跟不上曲线。三次项贴近真实形状,吸收了部分噪声但仍接近真值。十五次项则过拟合,在每个训练点间来回穿梭,并在其间产生巨大振荡。
不同深度的决策树
决策树也有同样故事。用相同数据训练不同深度的树,并在训练集与测试集上分别测量误差。
import numpy as np
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
# Data
np.random.seed(11)
X = np.linspace(0, 10, 250).reshape(-1, 1)
y = np.sin(X).ravel() + np.random.normal(0, 0.3, 250)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=0
)
depths = range(1, 21)
train_errors = []
test_errors = []
for depth in depths:
tree = DecisionTreeRegressor(max_depth=depth, random_state=0)
tree.fit(X_train, y_train)
train_errors.append(mean_squared_error(y_train, tree.predict(X_train)))
test_errors.append(mean_squared_error(y_test, tree.predict(X_test)))

决策树示例
随着树变深,训练误差持续降低,最终在每片叶子只含一个训练点时趋近于零。测试误差起初随树对真实关系的捕捉而下降,但当更深的划分开始拟合噪声时又回升。最低点位于恰好平衡二者的深度。
诊断模型性能的常见误区
即便选对了指标,也很容易得出错误结论。评估模型性能时,以下做法应当避免:
- 只看训练准确率: 训练准确率只说明模型对已见数据的拟合情况,对新输入的表现一无所知。任何结论前都要在独立数据集上测量。
- 忽视验证集: 验证数据用于调参(架构、超参数与停止点)。若反复使用同一测试集,模型最终也会对其过拟合。
- 以为越复杂越好: 更大的模型不等于更强的模型。若数据量小或关系本就简单,增加复杂度只会降低性能。先从简单开始,只有当诊断结果需要时再增加容量。
- 将噪声当作信号: 训练数据中的并非每个“模式”都值得学习。随机波动、抽样偏差、离群点与采集伪影,对灵活的模型看起来都可能“有意义”。若您无法解释某种关系为何应当存在,请谨慎对待。
在确定模型前应始终检查以上四点。大多数生产事故都与其中一项(或多项)相关。
结论
欠拟合与过拟合是模型无法泛化的两种方式。一个过于简单,学不会模式;另一个试图学会数据集中每一个点。
训练的真正目标是在二者之间取得平衡,使偏差与方差达到平衡,总误差最低。
验证集表现是告诉您所处位置的指标。在训练过程中持续跟踪它,并让训练误差与验证误差之间的差异指导您的决策。如果验证误差不再改善而训练误差继续下降,说明您已越过甜蜜点;如果两者都很高,说明尚未到达。
想系统学习更高级的数据科学概念并在 2026 年为就业做好准备?欢迎报名我们的 Machine Learning Engineer 学习路径,从基础进阶到 MLOps。
FAQs
过拟合和欠拟合的区别是什么?
欠拟合发生在模型过于简单,无法表示数据中的模式,因此在训练集和测试集上都表现不佳。过拟合则相反:模型把训练数据(包括噪声)学得过于“到位”,训练表现极好,但在新数据上失败。两者都会产生较弱的预测,但原因不同。
如何判断我的模型是过拟合还是欠拟合?
比较训练误差与测试误差:如果两者都高,就是欠拟合;如果训练误差很低但测试误差很高,就是过拟合。学习曲线同样有用:过拟合时训练与验证误差会发生分叉;欠拟合时两者在较高误差处趋于平坦。
什么是偏差-方差权衡?
偏差是模型过于简单带来的误差;方差是模型对训练数据过度敏感带来的误差。降低其中一个通常会提高另一个,因此目标是在总误差最低处找到平衡。平衡最佳的模型在新数据上的泛化能力最强。
收集更多数据能解决过拟合吗?
通常有帮助,但不是万能药。更多数据会让模型更难“背答案”,从而不得不寻找在整体上都成立的模式。但如果模型相对问题而言过于复杂,或特征大多是噪声,单纯增加数据并不能彻底解决。在这些情况下,正则化和更简单的模型往往更有效。
我可以用早停来防止神经网络过拟合吗?
可以,而且是最容易实施的修复之一。在训练过程中监控验证误差,当其持平或开始上升(即使训练误差仍在下降)时停止。这能抓住模型从学习真实模式转向拟合噪声的那一刻。大多数深度学习框架都内置了早停回调。