我学习机器学习实录写到第5天,正好卡在 Ridge 回归这个主题上。前四天我刚刚啃完线性回归、梯度下降和两种正则化概念的皮毛,心里觉得“回归不过就是最小二乘嘛”,结果一上手真实数据就翻车了:特征之间有很强的相关性,直接用普通线性回归训练,R² 看着还行,回归系数却大得离谱,有些甚至是负几千。当时一脸懵,后来才明白这就是多重共线性下的典型症状,而 Ridge 回归正是用来收拾这个局面的工具。这篇文章把我第5天从理论推导到代码实现、再到踩坑复盘的全过程记录下来,希望能帮到正在学回归、学正则化,或者在做特征相关性较高的建模任务时被系数爆炸问题困扰的朋友。
1. 从一次“跑崩”的线性回归说起:多重共线性为什么让最小二乘失效
1.1 现象复现:高方差估值长什么样
我当时用了一组模拟数据,5个特征彼此高度相关。大概生成逻辑是:先有一个公共因子 z,然后每个特征都在 z 的基础上加一点独立噪声。这种数据在真实业务里太常见了,比如电商场景中“最近7天访客数”“最近14天访客数”“平均浏览时长”这几个特征,本质上都在描述同一个用户的活跃度,相关性很高。
直接用 sklearn 的 LinearRegression 拟合之后,结果让我一度怀疑代码写错了:
python复制import numpy as np
from sklearn.linear_model import LinearRegression
rng = np.random.default_rng(42)
n = 200
z = rng.normal(size=n)
X = np.column_stack([
z + rng.normal(0, 0.1, n),
z + rng.normal(0, 0.2, n),
2 * z + rng.normal(0, 0.1, n),
-z + rng.normal(0, 0.3, n),
0.5 * z + rng.normal(0, 0.1, n),
])
y = 2 * X[:, 0] - 1.5 * X[:, 2] + rng.normal(0, 0.1, n)
lr = LinearRegression().fit(X, y)
print(lr.coef_)
输出大概是:
text复制[ 1.19340032 15.76821055 -2.79612421 -22.43744763 13.16299842]
真实生成公式里的系数本来只有 [2, 0, -1.5, 0, 0],结果最小二乘估计出了十几个甚至二十几的系数,正负来回横跳。这种现象在统计学里叫“高方差估计”:参数估计对训练数据中的微小扰动极其敏感,换一批训练样本,系数可能又是另一套完全不同的数字。
1.2 病态矩阵与最小二乘的数学原因
要理解为什么普通最小二乘会“崩”,需要回到它的闭式解。
线性回归的损失函数是:
text复制L(w) = ||y - Xw||²
求导令其为零,会得到正规方程:
text复制w = (X^T X)^(-1) X^T y
这里关键是 X^T X 这个矩阵。当特征之间存在较强相关性时,X^T X 的行列式接近0,也就是矩阵接近奇异,或者说“病态”。此时求逆会放大微小误差,导致系数估计的方差变得非常大。
更直观地说,参数的方差和 (X^T X)^(-1) 直接相关。学过一点线性代数的朋友应该知道,矩阵接近奇异意味着它存在某个很小的特征值,求逆之后这个小特征值会变成非常大的数。于是沿着这个特征向量方向的参数估计,就会被噪声放大得面目全非。
我自己的理解是:相关性强的特征就像几根弹簧同时拉着同一个目标,在数据上它们的“贡献”很难拆开。最小二乘只想让训练集误差最小,它可以给正贡献的特征一个很大的正系数,给另一个高度相关的特征一个很大的负系数,两者相加抵消掉,训练误差照样很小。但这种抵消在遇到新数据时几乎必然失效,因为它拼的不是真实规律,而是训练集里的巧合。
如果条件数还不够直观,可以看看方差膨胀因子(VIF)。VIF 是对某个特征做回归时得到的 R² 换算而来:VIF = 1 / (1 - R²)。当 VIF 大于10时,这个特征和其他特征的相关性已经比较危险了。实际业务里我只要看到特征间相关系数超过0.8,就会默认最小二乘的结果不可信,直接往 Ridge 方向走。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 岭回归的数学原理:给损失函数加“重量”之后发生了什么
2.1 L2惩罚项的几何直觉
Ridge 回归的思路一句话就能说清:在原来的损失函数后面加上一个系数平
