岭回归(Ridge Regression)在机器学习中的应用
岭回归(Ridge Regression)在机器学习中的应用
本文系统介绍了岭回归在处理多重共线性和过拟合问题中的应用。通过引入 L2 正则化项,岭回归有效控制回归系数幅度,提高模型稳定性与泛化能力。文章结合糖尿病数据集,展示了数据预处理、相关性分析、VIF 检测、最佳 α\alphaα 参数选择及预测效果可视化,全面说明了岭回归的建模流程与实际应用价值,为高维或特征相关性较强的数据分析提供了实用参考。
1. 算法介绍
岭回归(Ridge Regression),又称 Tikhonov 正则化,是一种针对传统线性回归的改进算法,主要用于解决多重共线性和过拟合问题。在线性回归中,当特征之间高度相关时,回归系数可能变得过大,从而导致模型对训练数据过度拟合,泛化能力下降。岭回归通过在最小二乘法的损失函数中引入 L2 正则化项,有效限制了回归系数的幅度,从而提高了模型的稳定性和鲁棒性。在实际应用中,这种方法特别适合处理高维数据或存在显著相关性的特征集合,使模型在面对新数据时能够保持良好的预测性能。
2. 数学模型
岭回归的数学模型与传统的线性回归相似,不同之处在于其损失函数中加入了正则化项。给定一组输入特征 XXX 和对应的目标值 yyy,岭回归的目标是最小化以下损失函数:
L(θ)=∑i=1n(yi−θTxi)2+λ∑j=1pθj2
\mathcal{L}(\theta) = \sum_{i=1}^{n} (y_i - \theta^T x_i)^2 + \lambda \sum_{j=1}^{p} \theta_j^2
L(θ)=i=1∑n(yi−θTxi)2+λj=1∑pθj2
其中,L(θ)\mathcal{L}(\theta)L(θ) 表示总损失函数,包含数据的平方误差和 L2 正则化项;θ\thetaθ 为回归系数向量,λ\lambdaλ 为正则化参数,用于调节正则化强度;ppp 是特征数量。
与普通最小二乘法相比,岭回归通过引入正则化项 λ∑j=1pθj2\lambda \sum_{j=1}^{p} \theta_j^2λ∑j=1pθj2,岭回归避免了回归系数过大,从而降低了模型对噪声的敏感性,并增强了其泛化能力。
3. 实现流程
我们可以使用 scikit-learn
库中的 Ridge
类来实现岭回归。以下是具体的实现步骤:
- 数据准备:首先,我们需要准备好数据集。可以使用真实数据集,也可以使用
make_regression
函数生成合成的回归数据集。 - 数据预处理:对数据进行标准化处理,因为岭回归对特征的尺度非常敏感。
- 模型训练:使用
Ridge
类创建模型并训练,调整正则化参数 α\alphaα。 - 模型评估:通过计算均方误差和 R2R^2R2 得分来评估模型。
- 超参数调优:使用网格搜索来调节正则化参数,寻找最佳模型。
4. 参数说明
Ridge(alpha=1.0, # 正则化强度,必须是正数。值越小,正则化效果越弱,值越大,正则化效果越强。*,fit_intercept=True, # 是否计算截距(偏置项)。如果设为 False,则不使用截距。copy_X=True, # 是否复制输入数据 X。如果设为 False,则 X 会被覆盖,可能会改变原始数据。max_iter=None, # 优化算法的最大迭代次数。如果设为 None,算法会使用默认的最大迭代次数。tol=0.0001, # 优化的容忍度。如果每次迭代的改善小于该值,算法会停止。solver='auto', # 用于优化的算法。选项包括 'auto'(自动选择)、'svd'、'cholesky'、'lsqr' 和 'saga'。'auto' 会根据数据集的大小自动选择最佳的求解器。positive=False, # 是否强制所有系数为正。如果设为 True,模型会强制所有特征的系数为正值,适用于期望正相关的场景。random_state=None, # 随机数种子,控制随机性。如果设为 None,会随机选择种子。如果设定了数值,可以确保实验结果的可重复性。
)
- alpha:控制正则化的强度。较大的
alpha
值会增强正则化,防止模型过拟合;较小的alpha
值会减弱正则化,可能导致过拟合。 - fit_intercept:控制是否包括截距项(偏置)。如果设置为
False
,模型将不包含截距。 - copy_X:如果为
True
,输入数据X
会被复制,以避免修改原始数据。如果为False
,X
会被覆盖。 - max_iter:设置优化过程中的最大迭代次数。如果没有指定,使用默认值。
- tol:设置优化的容忍度,当优化的改进小于该值时,算法会停止迭代。
- solver:指定用来求解的优化算法。不同的算法适用于不同的场景,选择合适的求解器可以加速训练过程。
- positive:如果为
True
,模型会强制所有回归系数为正,适用于需要所有特征有正向关系的场景。 - random_state:设置随机数种子,使得每次运行时生成相同的随机序列,保证结果的可重复性。
5. 样例讲解
以下是使用 make_regression
函数生成一个简单的数据集,并使用岭回归进行训练和预测的完整示例:
5.1 数据生成与预处理
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler# 生成回归数据:100个样本,10个特征,噪声为20
X, y = make_regression(n_samples=100, n_features=10, noise=20, random_state=42)# 查看数据集的一些基本信息
print(f"特征矩阵 X 的形状: {X.shape}")
print(f"目标变量 y 的形状: {y.shape}")# 标准化特征数据
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)# 划分数据集为训练集和测试集,80%训练集,20%测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
特征矩阵 X 的形状: (100, 10)
目标变量 y 的形状: (100,)
5.2 岭回归建模与训练
from sklearn.linear_model import Ridge
from sklearn.model_selection import GridSearchCV# 设置参数范围
param_grid = {'alpha': np.logspace(-6, 6, 13)} # alpha范围从1e-6到1e6# 使用网格搜索交叉验证来调优正则化参数
grid_search = GridSearchCV(Ridge(), param_grid, cv=10, scoring='neg_mean_squared_error', n_jobs=-1)
grid_search.fit(X_train, y_train)# 输出最佳正则化参数
print(f"最佳正则化参数 (alpha): {grid_search.best_params_['alpha']}")
最佳正则化参数 (alpha): 0.1
5.3 模型评估与可视化
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt# 设置中文字体为黑体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题# 使用最佳的岭回归模型进行预测
best_ridge = grid_search.best_estimator_
y_pred = best_ridge.predict(X_test)# 输出均方误差和R²得分
print(f"测试集上的均方误差: {mean_squared_error(y_test, y_pred):.4f}")
print(f"测试集上的R²得分: {r2_score(y_test, y_pred):.4f}")# 可视化预测结果与实际值的对比
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, color='blue', edgecolor='black')
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], color='red', linestyle='--')
plt.title('岭回归:预测值与实际值对比')
plt.xlabel('实际值')
plt.ylabel('预测值')
plt.grid(alpha=0.4)
plt.show()
测试集上的均方误差: 413.3413
测试集上的R²得分: 0.9932
5.4 可视化回归系数
# 可视化模型系数
plt.figure(figsize=(10, 6))
plt.bar(range(X.shape[1]), best_ridge.coef_)
plt.title('岭回归:特征系数')
plt.xlabel('特征')
plt.ylabel('系数')
plt.xticks(range(X.shape[1]))
plt.grid(alpha=0.4)
plt.show()
6. 实际应用
6.1 导入Python库
为了完成数据分析、可视化和岭回归建模,我们首先导入了所需的 Python 库。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_diabetes
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import mean_squared_error
from statsmodels.stats.outliers_influence import variance_inflation_factor# 设置 Seaborn 样式,支持中文和负号显示
sns.set_theme(style="whitegrid", font="Microsoft YaHei", rc={"axes.unicode_minus": False})
6.2 加载糖尿病数据集
本文章采用 scikit-learn 内置的糖尿病数据集。数据集包含若干标准化的临床特征和对应的疾病进展指标。我们将数据转换为 DataFrame,方便后续处理和分析,并将目标变量加入表格中,为后续建模做好准备。
diabetes = load_diabetes() # 加载 scikit-learn 内置糖尿病数据集
X, y = diabetes.data, diabetes.target
feature_names = diabetes.feature_names # 获取特征名称# 转换为 DataFrame 方便操作,并加入目标列
data = pd.DataFrame(X, columns=feature_names)
data['target'] = y
age | sex | bmi | bp | s1 | s2 | s3 | s4 | s5 | s6 | target | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.038076 | 0.050680 | 0.061696 | 0.021872 | -0.044223 | -0.034821 | -0.043401 | -0.002592 | 0.019907 | -0.017646 | 151.0 |
1 | -0.001882 | -0.044642 | -0.051474 | -0.026328 | -0.008449 | -0.019163 | 0.074412 | -0.039493 | -0.068332 | -0.092204 | 75.0 |
2 | 0.085299 | 0.050680 | 0.044451 | -0.005670 | -0.045599 | -0.034194 | -0.032356 | -0.002592 | 0.002861 | -0.025930 | 141.0 |
… | … | … | … | … | … | … | … | … | … | … | … |
439 | 0.041708 | 0.050680 | -0.015906 | 0.017293 | -0.037344 | -0.013840 | -0.024993 | -0.011080 | -0.046883 | 0.015491 | 132.0 |
440 | -0.045472 | -0.044642 | 0.039062 | 0.001215 | 0.016318 | 0.015283 | -0.028674 | 0.026560 | 0.044529 | -0.025930 | 220.0 |
441 | -0.045472 | -0.044642 | -0.073030 | -0.081413 | 0.083740 | 0.027809 | 0.173816 | -0.039493 | -0.004222 | 0.003064 | 57.0 |
6.3 相关性分析与可视化
在建模之前,需要了解特征之间以及特征与目标变量之间的关系。我们计算了相关性矩阵,并通过热力图进行可视化。热力图能够直观展示哪些特征与目标变量高度相关,以及特征间的相互关系,为特征选择提供参考。
corr_matrix = data.corr() # 计算特征与目标之间的相关性矩阵
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", fmt=".2f", cbar=True)
plt.title("特征与目标的相关性热力图")
plt.show()
6.4 检测多重共线性
多重共线性会导致线性回归模型系数不稳定,因此我们使用方差膨胀因子(VIF)来检测特征间的共线性问题。VIF 越高,说明该特征与其他特征高度相关,可能影响模型的稳定性。
X_df = data.drop(columns='target') # 仅保留特征列
vif_data = pd.DataFrame()
vif_data["feature"] = X_df.columns
# 逐特征计算 VIF
vif_data["VIF"] = [variance_inflation_factor(X_df.values, i) for i in range(X_df.shape[1])]
print("VIF 数据:\n", vif_data)
VIF 数据:
(id) feature VIF
0 age 1.217307
1 sex 1.278071
2 bmi 1.509437
3 bp 1.459428
4 s1 59.202510
5 s2 39.193370
6 s3 15.402156
7 s4 8.890986
8 s5 10.075967
9 s6 1.484623
针对高 VIF 特征,我们进一步绘制曲线图,观察特征值随样本索引变化的趋势,为后续建模提供参考。
# 4. 高 VIF 特征可视化
high_vif_features = ["s1", "s2", "s4"] # 可根据 VIF 结果调整fig, axes = plt.subplots(len(high_vif_features), 1, figsize=(14, 10))
axes = axes.flatten()for i, sort_col in enumerate(high_vif_features):# 按当前高 VIF 特征排序sorted_data = data.sort_values(by=sort_col).reset_index(drop=True)# 绘制所有高 VIF 特征曲线for feature in high_vif_features:axes[i].plot(sorted_data[feature].values, label=feature, alpha=0.7)axes[i].set_title(f"按 {sort_col} 排序的特征曲线")axes[i].set_xlabel(f"样本索引(按 {sort_col} 排序)")axes[i].set_ylabel("特征值(标准化后)")axes[i].legend(loc="upper left")axes[i].grid(color='gray', linestyle='--', linewidth=0.7, alpha=0.5)plt.tight_layout(rect=[0, 0, 0.9, 1])
plt.show()
6.5 设置最佳 alpha 参数(岭回归调参)
岭回归在普通线性回归的基础上加入 L2 正则化项,可以有效缓解多重共线性带来的问题。为了选择合适的正则化强度 alpha,我们将数据集拆分为训练集和测试集,并使用 GridSearchCV 进行交叉验证。通过在一定范围内搜索 alpha 值,找到使模型均方误差最小的最佳参数,从而保证模型既能拟合数据,又不过拟合。
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42
)alphas = np.logspace(-3, 3, 50) # 对数间隔候选值
ridge = Ridge()
param_grid = {'alpha': alphas}grid_search = GridSearchCV(ridge, param_grid, cv=5, scoring='neg_mean_squared_error')
grid_search.fit(X_train, y_train)
best_alpha = grid_search.best_params_['alpha']
print("最佳 alpha:", best_alpha)# 使用最佳 alpha 训练岭回归模型
ridge_best = Ridge(alpha=best_alpha)
ridge_best.fit(X_train, y_train)# 模型预测及均方误差计算
y_train_pred = ridge_best.predict(X_train)
y_test_pred = ridge_best.predict(X_test)
mse_train = mean_squared_error(y_train, y_train_pred)
mse_test = mean_squared_error(y_test, y_test_pred)
print(f"训练集 MSE: {mse_train:.2f}")
print(f"测试集 MSE: {mse_test:.2f}")
最佳 alpha: 0.06866488450043001
训练集 MSE: 2902.83
测试集 MSE: 2861.72
6.6 可视化回归系数随 alpha 变化
为了观察正则化强度对各特征系数的影响,我们绘制了回归系数随 alpha 变化的曲线。通过对比不同 alpha 值下系数的变化,可以直观理解正则化如何抑制部分特征系数的波动,从而提高模型的稳定性和泛化能力。
coefs = []
for a in alphas:ridge_a = Ridge(alpha=a)ridge_a.fit(X_train, y_train)coefs.append(ridge_a.coef_)
coefs = np.array(coefs)plt.figure(figsize=(12,6))
for i in range(coefs.shape[1]):sns.lineplot(x=alphas, y=coefs[:, i], label=feature_names[i])
plt.xscale('log') # 对数尺度
plt.xlabel('正则化参数 α')
plt.ylabel('回归系数')
plt.title('岭回归系数随 α 变化')
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.show()
6.7 可视化预测效果
最后,我们通过绘制真实值与预测值的散点图,直观展示岭回归模型的预测效果。理想情况下,点应分布在对角线上,说明模型能够较好拟合测试数据,从而验证模型的有效性。
plt.figure(figsize=(8,6))
sns.scatterplot(x=y_test, y=y_test_pred)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2) # 对角线
plt.xlabel('真实值')
plt.ylabel('预测值')
plt.title('岭回归预测效果')
plt.show()
7. 适用方向
岭回归特别适用于以下情况:
- 多重共线性:当数据集中的特征之间存在高度相关性时,普通最小二乘法可能会导致不稳定的回归系数,而岭回归通过正则化有效地解决了这个问题。
- 特征选择:通过调节正则化参数 α\alphaα,岭回归能够减少某些不重要特征的影响,增强模型的稳定性。
- 高维数据:当特征的维度较高时,岭回归能够有效防止过拟合,尤其在特征数量大于样本数量的情况下。
8. 文章总结
岭回归是解决线性回归中多重共线性和过拟合问题的一种有效方法。通过添加 L2 正则化项,岭回归限制了回归系数的过度增长,从而提升了模型的泛化能力。在实际应用中,调整正则化参数 α\alphaα 是关键步骤,适当的正则化能够有效控制模型的复杂度,提高其在未见数据上的表现。