2 岭回归
看模型的范式 | 岭回归 |
---|---|
问题是什么 | 回归拟合 |
模型是什么 | 线性模型 |
优化指标 | 最小二乘损失+L2正则化项 |
求解方法 | 极大似然估计,求导得闭式解 |
评价模型 | $R^2$ |
岭回归模型的基本原理: 岭回归是一种用于处理多重共线性问题的线性回归扩展方法。它在最小二乘回归的基础上,引入了 L2 正则化项,通过惩罚回归系数的大小,防止模型过拟合,提高模型的稳健性和泛化能力。岭回归的目标是最小化损失函数$J$: \(J\left(\beta\right)=\sum_{i=1}^{n}\left(y_{i}-\hat{y}_{i}\right)^{2}+\lambda\sum_{j=1}^{p}\beta_{j}^{2}\) 式中:$y_{i}$为第$i$个样本的真实值;$\hat{y}_{i}$为第$i$个样本的预测值;$λ$ 是正则化参数;$β$是第$j$个特征的系数。 正则化的作用在于限制模型参数的增长幅度,通过增加惩罚项使得那些对预测贡献较小但会增大模型复杂度的系数被“压缩”,降低其绝对值。
$λ$可以为0到正无穷任何数
$λ$为0,岭回归和最小二乘法一样,最小化残差平方和,当$λ$越大,斜率就越小。确定$λ$的值,可以通过交叉验证尝试,确定哪个方差最小。
离散变量岭回归也可以,岭回归可以用于逻辑回归。
其中提到如果矩阵 X 的转置与矩阵 X 相乘后的矩阵不是满秩矩阵时,这个矩阵是不可逆的,还提到其本质是多个自变量 x 之间存在多重共线性。下面来介绍多重共线性的问题与解决这个问题的其中一个方法-岭回归$^1$ (Ridge Regression)
岭回归是一种巧妙的方法,可以确保你不会过度拟合训练数据——本质上,你是在减少模型对训练数据的敏感性。岭回归的参数估计可以通过最小化损失函数来实现。由于损失函数是二次的,因此可以通过解析方法直接求解(比梯度下降更方便)。具体来说,岭回归的参数可以通过以下公式计算得到: \(\theta = (X^TX + \lambda I)^{-1}X^Ty\) 其中,$X$是设计矩阵,$y$是目标值向量,$λ$是正则化参数,$I$是单位矩阵。这个公式提供了一个闭式解,意味着可以直接计算出参数$θ$,而不需要进行迭代搜索计算。在实际应用中,直接计算$(X^TX + \lambda I)^{-1}$可能会遇到数值稳定性问题,尤其是当$X^TX$接近奇异或不可逆时。为了解决这个问题,可以使用奇异值分解(SVD)或其他数值稳定的方法来计算参数,当然这在scikit-learn之类的库内部已经默认使用了稳定的数值方法来求解参数,不需要人工进行迭代。
岭回归代价函数的解析解 (1) 岭回归的代价函数 (2) 前面三项为标准线性回归代价函数展开后的结果,$w$ 的 L2-范数的平方可以写成向量$ w $的点积 (3) 合并第一项与第四项 \(\text{Cost}(w) = \sum_{i=1}^{N} (y_i - w^T x_i)^2 + \lambda \|w\|_2^2 \\= w^T X^T X w - 2w^T X^T y + y^T y + \lambda w^T w \\= w^T (X^T X + \lambda I) w - 2w^T X^T y + y^T y\) (1) 代价函数对$ w $求偏导数,根据向量求导公式,只有第一项和第二项与$ W $有关,最后一项为常数,又因为代价函数是个凸函数,当对 $W $的偏导数为 0 向量时,代价函数为最小值。 (2) 将第二项移项后同时除以2,再两边同时在前面乘以一个逆矩阵,等式左边的矩阵和逆矩阵乘后为单位矩阵,所以只剩下 $w$ 向量。 \(\frac{\partial \text{Cost}(w)}{\partial w} = 2(X^T X + \lambda I) w - 2X^T y = 0 \\w = (X^T X + \lambda I)^{-1} X^T y\) 可以看到岭回归代价函数的解析解相较于标准线性回归来说多了一个可以人为控制的对角矩阵,这时可以通过调整不同的 $λ $来使得括号内的矩阵可逆。
参考:
详解机器学习经典模型(原理及应用)——岭回归_岭回归模型-CSDN博客
一篇入门之-岭回归(Ridge Regression)模型原理与实现-如何看岭迹图-老饼讲解
机器学习算法系列(四)- 岭回归算法(Ridge Regression Algorithm) - 机器学习算法系列 - SegmentFault 思否
代码示例:
import numpy as np
from sklearn.linear_model import Ridge
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # 用于三维绘图
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 设置随机种子保证可复现性
np.random.seed(42)
# 生成二维特征数据(x1和x2)
# x1范围:0-10(比原数据范围更大),生成50个均匀分布的随机数
x1 = np.random.uniform(low=0, high=10, size=50)
# x2范围:0-5(与原数据范围接近),生成50个均匀分布的随机数
x2 = np.random.uniform(low=0, high=5, size=50)
# 组合成特征矩阵x(形状:50行2列)
x = np.column_stack((x1, x2))
# 生成目标值y(模拟真实线性关系 + 噪声)
# 真实关系假设为:y = 2.5*x1 + 1.8*x2 + 2(接近原数据的隐含关系)
# 添加正态分布噪声(均值0,标准差2),使数据更真实
noise = np.random.normal(loc=0, scale=2, size=50)
y = 2.5 * x1 + 1.8 * x2 + 2 + noise
reg = Ridge(alpha=1, fit_intercept=True)
reg.fit(x, y) # 用扩展数据训练模型
print("当前alpha: {}".format(reg.alpha))
print(f"模型权重(系数): {reg.coef_.round(4)}") # 输出x1和x2的系数
print(f"模型阈值(截距): {reg.intercept_.round(4)}") # 输出常数项
# 创建网格数据用于绘制回归平面(覆盖特征的实际范围)
x1_min, x1_max = x1.min(), x1.max()
x2_min, x2_max = x2.min(), x2.max()
x1_plot = np.linspace(x1_min, x1_max, 30) # x1方向的30个点
x2_plot = np.linspace(x2_min, x2_max, 30) # x2方向的30个点
X1, X2 = np.meshgrid(x1_plot, x2_plot) # 生成网格矩阵
# 计算回归平面的预测值(基于模型参数)
Y_pred = reg.predict(np.column_stack((X1.ravel(), X2.ravel()))).reshape(X1.shape)
# 创建三维画布
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
# 绘制原始数据点(红色散点)
ax.scatter(x1, x2, y, c='r', s=40, marker='o', label='原始数据点')
# 绘制回归平面(半透明蓝色)
ax.plot_surface(X1, X2, Y_pred, alpha=0.6, cmap='Blues', label='拟合平面')
# 设置坐标轴标签和标题
ax.set_xlabel('特征X1', fontsize=12)
ax.set_ylabel('特征X2', fontsize=12)
ax.set_zlabel('目标值Y', fontsize=12)
ax.set_title('岭回归拟合效果(扩展数据)', fontsize=14)
# 添加图例(注意:3D图中图例需要手动创建代理对象)
from matplotlib.lines import Line2D
legend_elements = [
Line2D([0], [0], marker='o', color='w', markerfacecolor='r', markersize=10, label='原始数据'),
Line2D([0], [0], color='blue', lw=4, alpha=0.5, label='拟合平面')
]
ax.legend(handles=legend_elements, loc='upper right')
# 调整视角(可选,根据需要修改azim和elev参数)
ax.view_init(elev=20, azim=-45)
plt.show() # 显示图像