第十七篇:偏差和方差——为什么模型总是在“学不够”和“学太多”之间摇摆

在机器学习里,有一个特别常见的现象:

模型太简单时,效果不好。
模型太复杂时,效果也不好。

好像模型总是在两个极端之间来回摇摆:

一边是:

学得不够,抓不住规律。

另一边是:

学得太多,把噪声也当成规律。

这背后其实对应的是两个非常核心的概念:

偏差(Bias)

方差(Variance)

很多人第一次看到这两个词,会觉得有点抽象。
但如果你结合前面已经学过的内容,其实它们并不难理解。


1. 先用一句非常直观的话理解这两个词

偏差可以理解为:

模型的想法是不是太简单了。

方差可以理解为:

模型会不会太容易被数据里的细节影响。

如果你把模型当成一个学生,可以这样想:

偏差高的学生:

对知识理解得太粗,很多题型都做不好。

方差高的学生:

特别依赖做过的题型,一换题就容易慌。

理想状态是:

既理解核心规律,又不会对训练样本过度依赖。


2. 什么是偏差(Bias)

偏差大的模型,通常有一个特点:

模型本身表达能力不够。

也就是说,它即使努力学习,也很难把数据里的真实规律学完整。

比如:

用一条直线去拟合明显弯曲的曲线。
不管你怎么调参数,它都不可能贴合数据趋势。

这种情况下:

训练集表现不好
测试集表现也不好

这就是典型的:

欠拟合(underfitting)

偏差大的模型通常会:

  • 过于简单
  • 忽略重要特征关系
  • 无法表达复杂模式

常见例子:

  • 用线性模型处理明显非线性问题
  • 决策树深度太浅
  • KNN 的 K 设得太大
  • GBDT 的树太少

这些情况,本质都是:

模型能力不够,学不到真正规律。


3. 什么是方差(Variance)

方差大的模型,通常有另一种问题:

对训练数据太敏感。

训练数据稍微变化一点,模型结果就变化很大。

这种模型通常会:

把训练集学得非常细致
甚至把噪声也学进去

结果就是:

训练集表现很好
测试集表现明显下降

这就是典型的:

过拟合(overfitting)

方差大的模型通常会:

  • 对局部数据过度拟合
  • 边界特别复杂
  • 对新数据不稳定

常见例子:

  • 决策树太深
  • KNN 的 K 太小
  • SVM 的 C 和 gamma 太大
  • GBDT 树太多或学习率太高

这些情况,本质都是:

模型太灵活,把训练集记住了。


4. 一个经典类比:射箭靶子

偏差和方差,经常用射箭来类比。

假设靶心代表真实规律。

高偏差

箭都集中在一个地方,但离靶心很远。

说明模型很稳定,但方向错了。

学得不够。


高方差

箭落得到处都是,非常分散。

说明模型不稳定,对数据变化太敏感。

学得太细。


理想情况

箭集中在靶心附近。

说明模型既稳定,又抓住了规律。

这才是我们真正想要的状态。


5. 为什么模型复杂度会影响偏差和方差

一般来说:

模型越简单:

偏差越高
方差越低

模型越复杂:

偏差越低
方差越高

也就是说:

简单模型不容易过拟合,但容易学不够。
复杂模型更容易学到规律,但也更容易学过头。

这就是为什么模型选择永远不是:

越复杂越好
也不是:

越简单越安全

而是:

找到一个刚刚好的复杂度。


6. 一张非常经典的关系图

如果你把:

横轴看成模型复杂度
纵轴看成误差

通常会看到三条曲线:

训练误差:

随着模型复杂度增加,持续下降。

验证误差:

先下降,再上升。

偏差:

随着模型复杂度增加而下降。

方差:

随着模型复杂度增加而上升。

验证误差最低的位置,就是偏差和方差比较平衡的地方。

这就是:

偏差-方差权衡(bias-variance tradeoff)


7. 为什么很多调参,其实都在调偏差和方差

你回头看前面学过的内容,会发现很多操作本质都在调这两件事。

比如:

KNN 中:

K 太大 → 模型过于平滑 → 高偏差
K 太小 → 模型对样本敏感 → 高方差

决策树中:

树太浅 → 高偏差
树太深 → 高方差

随机森林中:

树数量增加 → 降低方差

GBDT 中:

学习率太大 → 方差高
学习率较小 → 更稳

SVM 中:

C 太小 → 偏差高
C 太大 → 方差高

正则化:

增加正则 → 降低方差

你会发现:

很多看起来完全不同的算法,其实都在处理同一个问题:

如何让模型既能学习规律,又不过度依赖训练数据。


8. 一个简单代码例子帮助理解

我们继续用多项式回归来观察偏差和方差变化:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline

np.random.seed(0)

X = np.linspace(0, 10, 30)
y = np.sin(X) + np.random.normal(0, 0.2, 30)

X = X.reshape(-1,1)

degrees = [1, 3, 15]

plt.scatter(X, y)

for d in degrees:
    model = make_pipeline(
        PolynomialFeatures(d),
        LinearRegression()
    )
    
    model.fit(X, y)
    
    X_plot = np.linspace(0,10,200).reshape(-1,1)
    
    plt.plot(X_plot, model.predict(X_plot), label=f"degree={d}")

plt.legend()
plt.title("偏差-方差示例")
plt.show()

你通常会看到:

degree=1:

模型太简单 → 高偏差

degree=3:

拟合较好 → 平衡状态

degree=15:

曲线乱抖 → 高方差


9. 为什么理解偏差和方差很重要

因为它会改变你看待模型的方式。

很多人一开始会觉得:

模型效果不好 → 我要换一个更复杂的模型

但有时候问题其实不是模型不够复杂,而是:

模型已经太复杂了。

或者:

数据本身噪声很大。

或者:

特征不合适。

理解偏差和方差以后,你就会知道:

什么时候应该让模型更强一点
什么时候应该让模型收一点

而不是一味堆复杂度。


10. 这一篇真正想让读者建立的感觉

机器学习不是一味追求复杂模型。

而是:

找到一个刚刚好的模型复杂度。

既不过度简化世界,
也不过度迷恋训练集。

偏差和方差这两个概念,其实是在提醒我们:

模型能力越强,越需要克制。

真正好的模型,不是最复杂的那个,而是最合适的那个。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐