深入浅出:使用 Scikit-Learn 探究普通最小二乘法与岭回归的方差差异

在构建机器学习模型时,我们经常会遇到这样一个棘手的问题:模型在训练数据上表现完美,但在从未见过的测试数据上却一塌糊涂。这通常就是我们常说的“过拟合”现象,而在统计学上,这往往与模型的方差过高有关。作为数据科学爱好者或从业者,我们需要理解如何平衡模型的偏差与方差。

在这篇文章中,我们将深入探讨线性回归中的两个核心支柱——普通最小二乘法岭回归。我们将通过 Python 的 Scikit-Learn 库,不仅从理论上,更通过实战代码来演示为什么在处理多重共线性或高维数据时,岭回归往往能通过牺牲一点点偏差来换取方差的大幅降低,从而获得更稳健的预测性能。让我们开始这段探索之旅吧。

核心概念解析

在我们深入代码之前,先让我们巩固一下涉及到的关键概念。理解这些基石对于我们后续调整模型至关重要。

1. 普通最小二乘法

这是我们在学习线性回归时最先接触到的经典方法。其核心思想非常直观:我们试图找到一条直线(或超平面),使得所有数据点到这条线的垂直距离平方和(即残差平方和,RSS)最小。

数学上,OLS 并没有对系数的大小做任何限制。只要能减少误差,它会毫不犹豫地给特征赋予巨大的权重。这在特征之间高度相关(多重共线性)时非常危险,因为系数的估计值可能会变得极其不稳定,数据的微小扰动都会导致模型发生剧烈变化。

2. 岭回归

岭回归是 OLS 的正则化版本。你可以把它想象成给狂奔的 OLS 套上了缰绳。它在损失函数中引入了一个 L2 正则化项(即系数的平方和)。

这意味着岭回归在做拟合时,不仅要考虑误差的大小,还要考虑系数的大小。这种机制被称为“收缩”,它会将相关特征的系数向着零(但不等于零)进行压缩。通过这样做,我们有效地降低了模型的复杂度,从而显著降低了方差,使模型对新数据的预测更加稳定。

3. 正则化

正则化是防止模型过拟合的通用技术。除了我们在岭回归中使用的 L2 正则化(系数的平方),还有 L1 正则化(系数的绝对值,如 Lasso 回归)以及两者的结合——弹性网络。正则化的本质就是在损失函数中增加一个“惩罚项”,限制模型参数变得过大,迫使模型学习到更普遍的规律,而不是死记硬背训练数据中的噪声。

4. 评估指标:MSE 与 R方

在衡量模型好坏时,我们需要标尺:

  • 均方误差 (MSE):预测值与真实值之差的平方的平均值。数值越低越好。它对异常值非常敏感。
  • R方:决定系数,表示模型解释了数据中多少比例的方差。接近 1 表示拟合很好,但在高方差模型中,训练集上的 R 方可能是虚高的。

方差的可视化:多项式回归的实战

让我们通过一个具体的例子来看看这两种方法的差异。我们将创建一个带有噪声的非线性数据集,并使用高阶多项式特征来拟合它。这种场景下,OLS 极容易过拟合。

场景设定

假设我们正在分析一个物理实验数据,$X$ 是时间,$Y$ 是观测值,它们之间呈非线性关系,且包含测量噪声。

代码实战示例 1:基础拟合对比

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

# 设置随机种子以保证结果可复现
np.random.seed(42)

# 1. 生成合成数据集:包含非线性关系和噪声
# X 在 0 到 10 之间均匀分布
X = np.linspace(0, 10, 50)
# y 是 sin(x) 加上一些高斯噪声
y = np.sin(X) + np.random.normal(0, 0.5, 50)

# 2. 数据预处理:生成多项式特征
# 我们使用 degree=4,这意味着模型将尝试拟合 x^4 的曲线
poly = PolynomialFeatures(degree=4)
# 将 X 转换为 [1, x, x^2, x^3, x^4] 的形式
X_poly = poly.fit_transform(X.reshape(-1, 1))

# 3. 训练模型
# 训练普通最小二乘法模型
ols = LinearRegression().fit(X_poly, y)
# 训练岭回归模型,alpha 是正则化强度的超参数
ridge = Ridge(alpha=1).fit(X_poly, y)

# 4. 生成测试数据进行预测和绘图
# 创建更密集的点来画出平滑的拟合曲线
X_test = np.linspace(-2, 12, 100).reshape(-1, 1)
X_test_poly = poly.transform(X_test)

# 进行预测
ols_pred = ols.predict(X_test_poly)
ridge_pred = ridge.predict(X_test_poly)

# 计算训练集上的 MSE 作为参考
ols_mse = mean_squared_error(y_true=y, y_pred=ols.predict(X_poly))
ridge_mse = mean_squared_error(y_true=y, y_pred=ridge.predict(X_poly))

# --- 可视化部分 ---
plt.figure(figsize=(12, 5))

# 图 1: 普通最小二乘法 (OLS)
plt.subplot(1, 2, 1)
plt.scatter(X, y, color=‘blue‘, label=‘观测数据‘)
plt.plot(X_test, ols_pred, color=‘red‘, linewidth=2, label=f‘OLS 拟合 (MSE={ols_mse:.2f})‘)
plt.title(‘普通最小二乘法 (OLS)
高方差风险‘)
plt.legend()

# 图 2: 岭回归
plt.subplot(1, 2, 2)
plt.scatter(X, y, color=‘blue‘, label=‘观测数据‘)
plt.plot(X_test, ridge_pred, color=‘green‘, linewidth=2, label=f‘Ridge 拟合 (MSE={ridge_mse:.2f})‘)
plt.title(‘岭回归
更平滑的拟合曲线‘)
plt.legend()

plt.show()

代码解析与洞察:

在上面的代码中,你可以看到我们使用了 PolynomialFeatures(degree=4)。这大大增加了模型的复杂度(特征维度)。如果没有正则化,OLS 会极力去迎合每一个波动的噪声点。

当你运行这段代码时,观察红色的 OLS 曲线可能比绿色的 Ridge 曲线更扭曲一些。虽然在这个特定的随机种子下差异可能看似细微,但请想象一下如果我们的数据噪声更大,或者特征维度更高(比如 degree=15),OLS 的曲线将会变得极其震荡,呈现出剧烈的过拟合状态,而 Ridge 依然能保持相对平滑和稳健。

深入探究:岭回归中的超参数 Alpha

你可能会问:“岭回归中的 alpha 参数到底起什么作用?”

alpha 代表了正则化的强度。你可以把它看作是我们对“系数过大”的惩罚力度。

  • Alpha = 0:惩罚为 0,岭回归就完全变成了普通的最小二乘法 (OLS)。
  • Alpha -> 无穷大:惩罚极大,所有系数都被强力压缩向 0,模型变成了一条水平线(预测值为均值)。

让我们通过一个更实用的例子来演示如何选择合适的 alpha,并观察系数的变化。

代码实战示例 2:Alpha 对系数的影响与交叉验证

在现实项目中,我们不能凭空猜测 INLINECODE2194808c 的值。最好的实践是使用交叉验证来寻找最优值。Scikit-Learn 为我们提供了便捷的工具 INLINECODEd703aa9a。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge, RidgeCV
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_regression

# 1. 创建一个具有多重共线性的回归数据集
# n_samples=100, n_features=20, 其中只有 10 个特征是有用的
X, y = make_regression(n_samples=100, n_features=20, n_informative=10, noise=10, random_state=42)

# 为了演示多重共线性,我们人为添加一些相关的噪声特征
X[:, 5:10] += X[:, 0:5] * 0.5 

# 2. 数据标准化
# 这一步对于正则化模型至关重要!
# 因为正则化是基于系数的大小,如果特征量纲不同,会导致惩罚不公平。
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.3, random_state=42)

# 3. 使用 RidgeCV 自动寻找最优 Alpha
# 定义一组 alpha 候选值(对数尺度分布)
alphas = np.logspace(-3, 3, 100)

# 创建 RidgeCV 模型,使用留一交叉验证
ridge_cv = RidgeCV(alphas=alphas, store_cv_values=True)
ridge_cv.fit(X_train, y_train)

print(f"自动选择的最优 Alpha: {ridge_cv.alpha_:.4f}")
print(f"测试集 R方 得分: {ridge_cv.score(X_test, y_test):.4f}")

# 4. 可视化不同 Alpha 下的系数路径
# 这展示了随着正则化强度增加,系数是如何收缩的
coefs = []
for a in alphas:
    ridge = Ridge(alpha=a)
    ridge.fit(X_train, y_train)
    coefs.append(ridge.coef_)

plt.figure(figsize=(10, 6))
ax = plt.gca()
ax.plot(alphas, coefs)
ax.set_xscale(‘log‘)
plt.xlabel(‘Alpha (正则化强度)‘)
plt.ylabel(‘Coefficients (系数值)‘)
plt.title(‘Ridge 系数路径图
随着 Alpha 增加,所有系数趋向于 0‘)
plt.grid(True)
plt.show()

实战建议:

  • 标准化是必须的:上面的代码中我们使用了 StandardScaler。请记住,永远在做 Ridge 或 Lasso 回归之前进行标准化。如果不做,量纲大的特征(比如“年薪”数万元)会被惩罚得更厉害,而量纲小的特征(比如“年龄”几十岁)则被忽视。
  • 观察路径图:在生成的“系数路径图”中,你会看到所有线条都随着 Alpha 增加平稳地趋向于 0。这与 Lasso 回归不同(Lasso 会直接将某些系数变为 0,进行特征筛选),Ridge 回归保留了所有特征,但让它们的贡献变小。

OLS vs Ridge:方差对比的数学直觉

让我们从数学角度稍微深入一点点,以便理解为什么 Ridge 能降低方差。

假设我们的预测公式是 $\hat{y} = Xw$。

  • OLS 的解:$w_{OLS} = (X^T X)^{-1} X^T y$
  • Ridge 的解:$w_{Ridge} = (X^T X + \alpha I)^{-1} X^T y$

注意区别:Ridge 在矩阵求逆的部分加上了 $\alpha I$($\alpha$ 乘以单位矩阵)。

在统计学习中,我们知道估计量的方差与其输入矩阵的逆矩阵有关。当特征之间存在共线性时,$X^T X$ 矩阵的某些特征值会接近于 0,导致其逆矩阵 $(X^T X)^{-1}$ 的特征值变得极其巨大。这直接导致了 OLS 系数的估计具有极高的方差

而 Ridge 的 $(X^T X + \alpha I)$ 通过在主对角线上加上了正数 $\alpha$,改善了矩阵的条件数,使其“可逆性”更好,求逆结果更稳定。这就是数学上 Ridge 方差更低的根源。

实际应用中的常见陷阱

在你开始将 Ridge 回归应用到实际项目时,请留意以下几个常见的错误:

  • 忘记特征缩放:正如前文所述,这是新手最容易犯的错误。未缩放的数据会导致正则化失效,甚至比 OLS 表现更差。
  • Alpha 选择不当:如果你把 Alpha 设置得太大,模型会变得欠拟合,连训练数据的主要趋势都捕捉不到,变成了死板的直线。如果太小,又退化成了 OLS。务必使用 INLINECODE91d1fdf9 或 INLINECODE5a60a2f9。
  • 解释性误区:Ridge 回归虽然降低了方差,但牺牲了无偏性。这意味着系数的估计值是有偏的。如果你需要进行严格的因果推断(比如判断某药物是否绝对有效),可能需要谨慎使用有偏估计;但如果你的目标是预测准确率,Ridge 几乎总是优于 OLS。

性能优化与扩展技巧

如果你的数据量非常大(例如几十万行),计算矩阵的逆运算可能会变慢。

  • 使用 SVD 求解器:在 Scikit-Learn 的 INLINECODEa2b8f54e 中,默认 INLINECODE5c4c150b。对于稠密矩阵,它通常选择 Cholesky 分解。但在数据量大时,可以尝试 INLINECODEda948032 或 INLINECODEd1a9e9a8,这些随机梯度下降算法在处理大规模数据时收敛更快。

总结与下一步

在这篇文章中,我们一起探索了普通最小二乘法与岭回归之间的博弈。我们了解到,虽然 OLS 是无偏的,但在处理复杂或高相关数据时往往方差过高,导致过拟合。岭回归通过巧妙地引入 L2 正则化项,牺牲微小的偏差,显著降低了模型的方差,使其在面对新数据时更加鲁棒。

我们不仅讨论了理论,还通过代码演示了如何生成数据、如何标准化、如何使用交叉验证选择最佳 Alpha,以及如何可视化系数路径。

作为下一步,我建议你:

  • 动手实践:尝试将代码中的 make_regression 改为真实的数据集(比如 Scikit-Learn 自带的波士顿房价数据或糖尿病数据集),看看在真实场景下 Ridge 能提升多少分数。
  • 对比 Lasso:既然我们已经掌握了 Ridge,下次不妨试试 Lasso 回归(L1 正则化),观察它在特征筛选(将系数变为 0)方面与 Ridge 有何不同。
  • 弹性网络:最后,结合两者优势的 ElasticNet 也是一个值得收藏的工具。

希望这篇文章能帮助你更好地理解方差与偏差的权衡。Happy Coding!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/32148.html
点赞
0.00 平均评分 (0% 分数) - 0