正则化与过拟合:让模型不只记住训练集
前面学习线性回归、逻辑回归、决策树、集成学习和 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 正则化可以产生稀疏模型,也能起到特征选择的作用。
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. 实践建议
使用正则化时,可以记住这些经验:
- 先划分训练集、验证集、测试集,不要只看训练集误差。
- 线性模型、逻辑回归、L1/L2 正则化前通常需要标准化特征。
- L2 更常用于稳定模型,L1 更常用于特征选择。
- 正则化强度太弱,可能仍然过拟合。
- 正则化强度太强,可能导致欠拟合。
- 用交叉验证选择正则化强度,不要凭感觉乱选。
- 对决策树、GBDT 这类模型,也要通过深度、叶子样本数、学习率等方式控制复杂度。
18. 总结
过拟合的本质是:模型在训练集上学得太细,把噪声和偶然规律也记住了。
正则化的本质是:在追求训练误差小的同时,限制模型复杂度,让模型更稳。
可以把这篇文章和前面的机器学习文章串起来看:
- 线性回归里,Ridge 和 Lasso 是正则化版本。
- 逻辑回归里,正则化可以防止权重过大。
- 决策树里,限制深度和剪枝是在控制复杂度。
- 交叉验证可以帮助发现过拟合和选择正则化强度。
- GBDT 里,学习率、树深度、早停也都带有正则化思想。
理解正则化之后,再进入深度学习会顺很多。因为神经网络参数更多、表达能力更强,控制过拟合会变得更加重要。
