大数跨境

导师:“为什么训练集99分,测试集却崩了?”我:“我以为模型越复杂越厉害!”导师:“高方差正在偷走你的泛化能力”

导师:“为什么训练集99分,测试集却崩了?”我:“我以为模型越复杂越厉害!”导师:“高方差正在偷走你的泛化能力” 机器学习和人工智能AI
2026-09-03
2

哈喽,大家好~

偏差与方差:模型越复杂,效果反而越差?

最近,很多同学也会发现:模型太简单学不会,模型太复杂又容易在测试集上表现变差。

这篇文章我们就用一个简单的多项式回归案例,把机器学习里的偏差、方差和过拟合一次讲清楚~

什么是偏差和方差?

假设我们要用模型拟合一组带噪声的数据。

如果模型过于简单,比如只用一条直线拟合明显弯曲的数据,它连训练集规律都没有学好,这就是高偏差

如果模型过于复杂,比如用一条剧烈波动的曲线穿过训练集的每一个点,它把噪声也当成了规律,这就是高方差

你可以这样理解:

  • 偏差:模型的“平均预测”离真实规律有多远。
  • 方差:模型换一批训练数据后,预测结果变化有多大。

模型误差通常可以拆成:

其中,偏差描述模型本身是否过于简单,方差描述模型是否对训练数据过于敏感。

也就是,偏差高,模型学不够;方差高,模型学过头。**

02多项式回归

我们构造这样一条真实规律:

这里的 是真实函数, 是随机噪声。

接下来分别使用一次、四次和十五次多项式进行拟合:

越小,模型越简单; 越大,模型表达能力越强。

但表达能力强不等于泛化能力强。十五次多项式可以把训练样本拟合得非常漂亮,却容易在样本点之间剧烈波动,这就是典型的过拟合。

Python实现

我们最后的数据分析题,第一张图对比不同复杂度模型的拟合曲线,观察欠拟合和过拟合。

第二张图统计不同多项式阶数下的偏差平方、方差和预测误差,观察模型复杂度变化带来的影响。

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

rng = np.random.default_rng(42)

def true_func(x):
    return np.sin(x)

# 一组训练数据
x_train = np.sort(rng.uniform(-3325))
y_train = true_func(x_train) + rng.normal(00.2525)

x_test = np.linspace(-33400)
y_true = true_func(x_test)

def build_model(degree):
    return make_pipeline(
        PolynomialFeatures(degree),
        LinearRegression()
    )

degrees_show = [1415]
colors = ["#00B4D8""#FF7A00""#E63946"]

fig, axes = plt.subplots(12, figsize=(145))

# 图1:不同复杂度的拟合曲线
axes[0].scatter(
    x_train, y_train, color="#8338EC",
    s=45, label="训练数据"
)
axes[0].plot(
    x_test, y_true, color="#222222",
    linewidth=3, label="真实规律"
)

for degree, color in zip(degrees_show, colors):
    model = build_model(degree)
    model.fit(x_train.reshape(-11), y_train)
    axes[0].plot(
        x_test, model.predict(x_test.reshape(-11)),
        color=color, linewidth=2.5,
        label=f"{degree}次多项式"
    )

axes[0].set_title("模型复杂度与拟合曲线")
axes[0].set_xlabel("x")
axes[0].set_ylabel("y")
axes[0].legend()
axes[0].grid(alpha=0.25)

# 图2:重复采样,估计偏差平方和方差
n_rounds = 100
bias2_list, variance_list, error_list = [], [], []

for degree in range(116):
    predictions = []

    for _ in range(n_rounds):
        x = rng.uniform(-3325)
        y = true_func(x) + rng.normal(00.2525)

        model = build_model(degree)
        model.fit(x.reshape(-11), y)
        predictions.append(model.predict(x_test.reshape(-11)))

    predictions = np.array(predictions)
    mean_prediction = predictions.mean(axis=0)

    bias2 = np.mean((mean_prediction - y_true) ** 2)
    variance = np.mean((predictions - mean_prediction) ** 2)
    error = np.mean((predictions - y_true) ** 2)

    bias2_list.append(bias2)
    variance_list.append(variance)
    error_list.append(error)

axes[1].plot(
    range(116), bias2_list,
    marker="o", color="#00B4D8",
    linewidth=2.5, label="偏差平方"
)
axes[1].plot(
    range(116), variance_list,
    marker="s", color="#FF006E",
    linewidth=2.5, label="方差"
)
axes[1].plot(
    range(116), error_list,
    marker="^", color="#FFBE0B",
    linewidth=2.5, label="总预测误差"
)

axes[1].set_title("偏差-方差随模型复杂度的变化")
axes[1].set_xlabel("多项式阶数")
axes[1].set_ylabel("误差")
axes[1].legend()
axes[1].grid(alpha=0.25)

plt.tight_layout()
plt.show()

第一张图中,一次多项式基本是一条直线,无法描述正弦曲线的弯曲变化,所以属于高偏差、欠拟合。

四次多项式通常能抓住整体趋势,在训练数据和真实规律之间取得比较好的平衡。

十五次多项式会努力穿过每一个训练点,曲线在边缘位置出现明显波动。它在当前训练集上表现很好,但换一批数据后,曲线很容易发生变化,这就是高方差、过拟合。

第二张图展示了更完整的变化过程。随着阶数增加,偏差平方通常下降,因为模型越来越有能力拟合真实规律;但方差会逐渐上升,因为模型开始依赖具体训练样本。

真正理想的模型,不是让偏差或方差单独达到最低,而是让两者之和尽量小。图中的“总预测误差”最低点,就是一个比较合适的复杂度区域。

实验中注意点

当模型出现高偏差时,可以增加特征、提高模型复杂度,或者减少正则化。

当模型出现高方差时,可以增加训练数据、降低模型复杂度,或者加强正则化。交叉验证也很重要,它能帮助我们选择更稳定的模型参数。

这里还要注意,训练误差很低并不代表模型真的好。我们最终关心的是验证集和测试集上的表现,也就是模型面对新数据时能不能继续做出准确预测。

总结

偏差告诉我们模型有没有学到足够的规律,方差告诉我们模型是否过度依赖某一批训练数据。模型选择的核心,就是在欠拟合和过拟合之间找到平衡。

大家可以继续尝试修改噪声大小、训练样本数量和正则化参数,观察偏差与方差曲线如何变化。也可以把多项式回归替换成决策树,看看树深度增加后,模型又会呈现怎样的过拟合现象。

【声明】内容源于网络
0
0
机器学习和人工智能AI
让我们一起期待 AI 带给我们的每一场变革!推送最新行业内最新最前沿人工智能技术!
内容 381
粉丝 0
机器学习和人工智能AI 让我们一起期待 AI 带给我们的每一场变革!推送最新行业内最新最前沿人工智能技术!
总阅读5.0k
粉丝0
内容381