前面学习线性回归、逻辑回归、决策树、集成学习和 GBDT 时,我们一直在训练模型,让模型尽可能学到数据里的规律。

但机器学习里有一个很重要的问题:

模型在训练集上表现很好,不代表它在新数据上也表现很好。

如果模型把训练数据里的噪声、偶然样本、特殊细节都记住了,就会出现过拟合(Overfitting)。正则化(Regularization)就是用来控制模型复杂度、提升泛化能力的一类方法。

欠拟合、合适拟合与过拟合

1. 什么是泛化能力

机器学习真正关心的不是训练集分数,而是模型面对新数据时的表现。

例如我们训练一个模型预测学生是否通过考试。训练集中有 100 个学生,模型全部预测正确,训练准确率达到 $100%$。

这听起来很好,但如果换一批新学生,准确率只有 $65%$,说明模型可能只是记住了训练集,而没有学到稳定规律。

这种“面对新数据仍然表现好”的能力,叫泛化能力。

可以简单记住:

训练集表现好:说明模型会做旧题
测试集表现好:说明模型学到了规律

在交叉验证那篇文章里,我们已经讲过:不能只看一次训练/测试划分,更稳妥的方式是用验证集或交叉验证评估模型。正则化则是进一步解决“模型太复杂”的问题。

相关回顾:交叉验证与网格搜索:让模型选择更可靠

2. 欠拟合与过拟合

模型常见问题可以分成两类。

2.1 欠拟合

欠拟合(Underfitting)表示模型太简单,连训练集里的基本规律都学不好。

例如用一条直线拟合明显弯曲的数据:

训练集误差高
测试集误差也高

这种情况通常需要:

  • 换更复杂的模型。
  • 加入更有用的特征。
  • 增加多项式特征或非线性模型。
  • 减弱正则化强度。

2.2 过拟合

过拟合(Overfitting)表示模型太复杂,把训练集里的噪声也记住了。

例如一棵很深的决策树,可能把每个训练样本都分得很细,训练集准确率很高,但测试集效果很差。

训练集误差低
测试集误差高

这种情况通常需要:

  • 降低模型复杂度。
  • 增加正则化。
  • 使用更多训练数据。
  • 使用交叉验证调参。
  • 对决策树限制深度或剪枝。

3. 训练误差和验证误差怎么看

判断过拟合时,不要只看训练误差。

训练误差与验证误差曲线

随着模型复杂度增加,通常会出现这样的变化:

模型复杂度 训练误差 验证误差 状态
太低 欠拟合
合适 较低 较低 泛化较好
太高 很低 变高 过拟合

假设我们调决策树的 max_depth,得到结果:

max_depth 训练准确率 验证准确率
1 0.72 0.70
3 0.86 0.84
5 0.93 0.88
10 1.00 0.79

如果只看训练准确率,max_depth=10 最好。但它的验证准确率下降了,说明树可能记住了训练集细节。

更合理的选择可能是:

max_depth = 5

这也是为什么交叉验证和正则化常常要一起出现:交叉验证帮助我们发现过拟合,正则化帮助我们缓解过拟合。

4. 偏差与方差

过拟合和欠拟合也可以从偏差(Bias)与方差(Variance)理解。

偏差大,表示模型假设太简单,系统性地学不到真实规律。

方差大,表示模型对训练数据太敏感,训练数据稍微变一下,模型就明显变化。

可以简单理解:

情况 偏差 方差 表现
欠拟合 训练集和测试集都差
合适拟合 较低 较低 训练集和测试集都不错
过拟合 训练集好,测试集差

KNN 中 $K$ 太小、决策树太深、GBDT 树太多或学习率太大,都可能导致方差偏高。

相关回顾:KNN:从距离到分类的直觉算法

相关回顾:决策树:像做选择题一样理解分类与回归

5. 正则化的核心思想

正则化的核心是:

在原来的损失函数后面,加一个惩罚项,限制模型不要太复杂。

普通训练目标通常是:

$$
\min_{\theta} J(\theta)
$$

加入正则化后变成:

$$
\min_{\theta} \left[J(\theta)+\lambda \Omega(\theta)\right]
$$

其中:

  • $J(\theta)$ 是原始损失函数。
  • $\Omega(\theta)$ 是正则化惩罚项。
  • $\lambda$ 是正则化强度。

这个公式可以理解成:

既要预测误差小,也要模型别太复杂

如果 $\lambda$ 很小,正则化影响弱,模型更自由,可能过拟合。

如果 $\lambda$ 很大,正则化影响强,模型被限制得很厉害,可能欠拟合。

6. L2 正则化:让参数整体变小

L2 正则化会惩罚参数平方和:

$$
\Omega(\mathbf{w})=\sum_{j=1}^{n}w_j^2
$$

加入 L2 后,目标函数可以写成:

$$
J_{L2}(\mathbf{w},b)
=
J(\mathbf{w},b)
+\lambda \sum_{j=1}^{n}w_j^2
$$

L2 的作用是让权重不要太大。

为什么权重太大可能不好?

假设线性模型为:

$$
\hat{y}=w_1x_1+w_2x_2+b
$$

如果 $w_1=100$,那么 $x_1$ 只要变化一点点,预测值就会剧烈变化。模型会对输入扰动很敏感,泛化能力可能变差。

L2 正则化会让参数更平滑、更保守。

6.1 一个带数字的例子

假设有两个模型,在训练集上的 MSE 都差不多:

模型 MSE 参数
模型 A 10 $w_1=2,w_2=1$
模型 B 9 $w_1=20,w_2=-15$

如果只看 MSE,模型 B 更好。

但加入 L2 正则化,设 $\lambda=0.1$:

模型 A:

$$
J_{L2}=10+0.1(2^2+1^2)=10+0.5=10.5
$$

模型 B:

$$
J_{L2}=9+0.1(20^2+(-15)^2)=9+0.1(625)=71.5
$$

加入正则化后,模型 B 虽然训练误差略低,但参数太大,惩罚非常高。模型会更倾向于选择模型 A 这种更平稳的参数。

这就是 L2 正则化的直觉:宁愿训练误差稍微高一点,也不要让模型用非常大的参数去死记训练集。

7. Ridge 回归

在线性回归中加入 L2 正则化,就得到 Ridge 回归。

普通线性回归目标是:

$$
\min_{\mathbf{w},b}
\frac{1}{m}\sum_{i=1}^{m}
(\hat{y}^{(i)}-y^{(i)})^2
$$

Ridge 回归目标是:

$$
\min_{\mathbf{w},b}
\left[
\frac{1}{m}\sum_{i=1}^{m}
(\hat{y}^{(i)}-y^{(i)})^2
+\lambda\sum_{j=1}^{n}w_j^2
\right]
$$

注意:通常不惩罚偏置 $b$,主要惩罚权重 $\mathbf{w}$。

Ridge 很适合特征之间存在相关性、参数不稳定的场景。

相关回顾:线性回归:从直觉到最小二乘法

8. L1 正则化:让一些参数变成 0

L1 正则化惩罚参数绝对值之和:

$$
\Omega(\mathbf{w})=\sum_{j=1}^{n}|w_j|
$$

加入 L1 后:

$$
J_{L1}(\mathbf{w},b)
=
J(\mathbf{w},b)
+\lambda \sum_{j=1}^{n}|w_j|
$$

L1 的一个重要特点是:它更容易让某些参数变成 0。

如果某个特征对应的权重变成 0,就相当于模型不再使用这个特征。因此 L1 正则化可以产生稀疏模型,也能起到特征选择的作用。

L1 与 L2 正则化约束直觉

8.1 一个带数字的例子

假设模型有 5 个特征:

学习时长、睡眠时长、是否吃早餐、鞋码、今天星期几

预测考试是否通过时,“鞋码”和“今天星期几”可能没有什么意义。

普通模型可能学到:

$$
\mathbf{w}=[1.8,0.7,0.3,0.05,-0.02]
$$

L1 正则化后,模型可能变成:

$$
\mathbf{w}=[1.6,0.5,0.2,0,0]
$$

这表示模型自动把“鞋码”和“今天星期几”的权重压到了 0。

所以 L1 常用于:

  • 特征很多时做特征选择。
  • 希望模型更简洁时。
  • 高维稀疏数据,例如文本特征。

9. Lasso 回归

在线性回归中加入 L1 正则化,就得到 Lasso 回归。

目标函数为:

$$
\min_{\mathbf{w},b}
\left[
\frac{1}{m}\sum_{i=1}^{m}
(\hat{y}^{(i)}-y^{(i)})^2
+\lambda\sum_{j=1}^{n}|w_j|
\right]
$$

Lasso 和 Ridge 的区别可以简单记忆:

方法 正则项 效果
Ridge $\sum w_j^2$ 让参数变小
Lasso $\sum w_j

如果希望保留所有特征但让参数稳定,可以用 Ridge。

如果希望自动筛掉一些特征,可以用 Lasso。

10. 逻辑回归中的正则化

逻辑回归中也经常使用正则化。

普通逻辑回归使用交叉熵损失:

$$
J(\mathbf{w},b)=
-\frac{1}{m}\sum_{i=1}^{m}
\left[
y^{(i)}\log(\hat{y}^{(i)})
+(1-y^{(i)})\log(1-\hat{y}^{(i)})
\right]
$$

加入 L2 正则化后:

$$
J_{L2}(\mathbf{w},b)=J(\mathbf{w},b)+\lambda\sum_{j=1}^{n}w_j^2
$$

这可以防止逻辑回归为了把训练集分得特别开,而学到过大的权重。

例如某个二分类任务中,两个类别刚好在训练集上几乎线性可分。没有正则化时,逻辑回归可能会把权重推得很大,让决策边界非常自信。但新数据稍微偏一点,模型就可能预测错。

加入正则化后,模型会更克制,概率输出也更稳定。

相关回顾:逻辑回归:从直线到概率的分类算法

11. 正则化如何影响梯度下降

以 L2 正则化为例:

$$
J_{L2}(\mathbf{w})=J(\mathbf{w})+\lambda\sum_{j=1}^{n}w_j^2
$$

对 $w_j$ 求导:

$$
\frac{\partial J_{L2}}{\partial w_j}
=
\frac{\partial J}{\partial w_j}
+2\lambda w_j
$$

梯度下降更新为:

$$
w_j := w_j-\alpha
\left(
\frac{\partial J}{\partial w_j}
+2\lambda w_j
\right)
$$

整理一下:

$$
w_j := (1-2\alpha\lambda)w_j
-\alpha\frac{\partial J}{\partial w_j}
$$

其中 $(1-2\alpha\lambda)w_j$ 会让权重每次更新时被稍微缩小一点。

这也是为什么 L2 正则化在深度学习里常常叫 weight decay,也就是权重衰减。

相关回顾:梯度下降法:机器学习如何一步步找到最优解

12. 决策树中的正则化:限制树复杂度

正则化不只存在于线性模型中。

对于决策树,控制模型复杂度的方式包括:

  • max_depth:限制最大深度。
  • min_samples_leaf:限制叶子节点最少样本数。
  • min_samples_split:限制内部节点继续划分所需的最少样本数。
  • 剪枝:去掉贡献不大的分支。

例如一棵树如果不限制深度,可能长成这样:

一直划分,直到每个叶子只剩 1 个样本

这时训练集准确率可能很高,但新数据表现不一定好。

如果设置:

DecisionTreeClassifier(max_depth=3, min_samples_leaf=5)

就相当于告诉模型:

不要把训练集切得太细,不要为了少数样本生成过于复杂的规则

从广义上看,这也是一种正则化。

13. GBDT 中的正则化思想

GBDT 本身是 Boosting 模型,表达能力很强,也可能过拟合。

常见控制方法包括:

  • 降低 learning_rate
  • 限制单棵树深度 max_depth
  • 限制叶子节点最少样本数。
  • 减少树数量,或使用 early stopping。
  • 使用 subsample 做随机采样。

GBDT 的更新公式是:

$$
F_t(x)=F_{t-1}(x)+\eta h_t(x)
$$

其中 $\eta$ 就是学习率。

如果 $\eta$ 很大,每棵树修正幅度太猛,容易把训练集噪声也学进去。

如果 $\eta$ 较小,每棵树只修正一点点,模型更稳,但需要更多树。

相关回顾:GBDT:从残差到梯度提升树的完整理解

14. 深度学习中的正则化

这篇文章也可以作为进入深度学习前的过渡。

神经网络参数很多,表达能力很强,因此也很容易过拟合。深度学习里常见正则化方法包括:

  • L2 正则化,也叫 weight decay。
  • Dropout,训练时随机丢弃一部分神经元。
  • Batch Normalization,有时也能带来一定正则化效果。
  • Early Stopping,验证集效果不再提升时停止训练。
  • 数据增强,通过变换样本增加数据多样性。

如果后面学习神经网络,可以把这些方法都理解为:

不要让模型只记住训练集,要让它学到更稳定、更通用的规律

15. Python 实战:Ridge 与 Lasso

下面用 scikit-learn 对比普通线性回归、Ridge 和 Lasso。

import numpy as np
from sklearn.datasets import make_regression
from sklearn.linear_model import Lasso, LinearRegression, Ridge
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# 构造一个回归数据集,其中只有部分特征真正有用
X, y = make_regression(
    n_samples=200,
    n_features=10,
    n_informative=4,
    noise=20,
    random_state=42,
)

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
)

# 正则化模型通常建议先标准化特征
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

models = {
    "LinearRegression": LinearRegression(),
    "Ridge": Ridge(alpha=1.0),
    "Lasso": Lasso(alpha=0.1, max_iter=10000),
}

for name, model in models.items():
    model.fit(X_train_scaled, y_train)
    y_pred = model.predict(X_test_scaled)
    mse = mean_squared_error(y_test, y_pred)

    print(name)
    print("MSE:", mse)
    print("weights:", model.coef_)
    print()

运行后可以观察:

  • Ridge 的权重通常会整体变小。
  • Lasso 可能会把一些权重压成 0。
  • 普通线性回归没有额外限制,参数可能更不稳定。

16. Python 实战:逻辑回归正则化强度

在 scikit-learn 的 LogisticRegression 中,参数 C 控制正则化强度。

注意:C 是正则化强度的倒数。

C 越小,正则化越强
C 越大,正则化越弱
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

data = load_breast_cancer()
X = data.data
y = data.target

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
    stratify=y,
)

for C in [0.01, 0.1, 1, 10, 100]:
    pipe = Pipeline([
        ("scaler", StandardScaler()),
        ("model", LogisticRegression(C=C, max_iter=1000)),
    ])

    pipe.fit(X_train, y_train)
    y_pred = pipe.predict(X_test)

    print("C =", C, "accuracy =", accuracy_score(y_test, y_pred))

如果后续配合 GridSearchCV,就可以系统选择更合适的 C

17. 实践建议

使用正则化时,可以记住这些经验:

  1. 先划分训练集、验证集、测试集,不要只看训练集误差。
  2. 线性模型、逻辑回归、L1/L2 正则化前通常需要标准化特征。
  3. L2 更常用于稳定模型,L1 更常用于特征选择。
  4. 正则化强度太弱,可能仍然过拟合。
  5. 正则化强度太强,可能导致欠拟合。
  6. 用交叉验证选择正则化强度,不要凭感觉乱选。
  7. 对决策树、GBDT 这类模型,也要通过深度、叶子样本数、学习率等方式控制复杂度。

18. 总结

过拟合的本质是:模型在训练集上学得太细,把噪声和偶然规律也记住了。

正则化的本质是:在追求训练误差小的同时,限制模型复杂度,让模型更稳。

可以把这篇文章和前面的机器学习文章串起来看:

  • 线性回归里,Ridge 和 Lasso 是正则化版本。
  • 逻辑回归里,正则化可以防止权重过大。
  • 决策树里,限制深度和剪枝是在控制复杂度。
  • 交叉验证可以帮助发现过拟合和选择正则化强度。
  • GBDT 里,学习率、树深度、早停也都带有正则化思想。

理解正则化之后,再进入深度学习会顺很多。因为神经网络参数更多、表达能力更强,控制过拟合会变得更加重要。