特征选择与防过拟合:L2正则化(岭回归)|原理+公式+Python实战全攻略

L2正则化(又称岭回归/Ridge Regression)是机器学习中控制模型过拟合、处理多重共线性的核心方法,也是特征选择的“隐形工具”。它不会直接删除特征,而是通过压缩不重要特征的系数实现“软筛选”,兼顾模型稳定性与泛化能力。


一、先搞懂:L2正则化到底解决什么问题?

1. 核心痛点:过拟合与多重共线性

  • 过拟合:模型在训练数据上表现极好,但换了新数据就“翻车”(比如把噪声当成规律)
  • 多重共线性:特征之间高度相关(如“身高”和“体重”),导致普通线性回归系数不稳定、解释性差

2. L2正则化的核心作用

  • 防止过拟合:惩罚模型的复杂系数,让参数“变小”,避免过度依赖个别特征
  • 处理多重共线性:通过正则化让相关特征的系数更均衡,避免系数波动过大
  • 软特征选择:把不重要特征的系数压缩到接近0,间接筛选出关键特征(不直接删除)

3. 形象比喻:给模型“套紧箍咒”

普通线性回归像“无拘无束的学生”,为了考好(拟合训练数据)会死记硬背所有细节;而L2正则化像给学生套了“紧箍咒”,限制它过度复杂——虽然还是会学所有知识点(保留所有特征),但不会对无关细节(无用特征)过度关注,换套题(新数据)也能考好。


二、L2正则化是什么?通俗理解

1. 本质:给损失函数加“惩罚项”

L2正则化的核心是在模型的“损失函数”后,添加一项参数平方和的惩罚项,强制参数尽量“小而温和”:

  • 重要特征:系数虽被惩罚,但仍保持较大值
  • 不重要特征:系数被压缩到接近0,对预测结果影响极小

2. 与L1正则化的核心区别

对比项 L2正则化(岭回归) L1正则化(Lasso)
正则项形式 系数的平方和(∑wj2\sum w_j^2wj2 系数的绝对值和(∑\sum |wjw_jwj|)
特征处理 系数接近0(软筛选) 系数直接为0(硬删除)
共线性处理 强(均衡相关特征系数) 弱(随机保留一个相关特征)
模型稳定性

三、核心公式(必须掌握)

1. 普通线性回归目标函数(最小二乘)

J(w,b)=12m∑i=1m(y^(i)−y(i))2 J(w, b) = \frac{1}{2m} \sum_{i=1}^m \left( \hat{y}^{(i)} - y^{(i)} \right)^2 J(w,b)=2m1i=1m(y^(i)y(i))2

  • 仅追求“预测误差最小”,容易导致系数过大(过拟合)或不稳定(多重共线性)

2. L2正则化(岭回归)目标函数

J(w,b)=12m∑i=1m(w⊤x(i)+b−y(i))2+λ2∥w∥22 J(w, b) = \frac{1}{2m} \sum_{i=1}^m \left( w^\top x^{(i)} + b - y^{(i)} \right)^2 + \frac{\lambda}{2} \|w\|_2^2 J(w,b)=2m1i=1m(wx(i)+by(i))2+2λw22
或矩阵形式(更简洁):
J(w)=12m∥Xw−y∥22+λ2∥w∥22 J(w) = \frac{1}{2m} \|Xw - y\|_2^2 + \frac{\lambda}{2} \|w\|_2^2 J(w)=2m1Xwy22+2λw22

各部分含义:
  • ∥Xw−y∥22\|Xw - y\|_2^2Xwy22:残差平方和(拟合误差项),衡量模型对数据的拟合程度
  • λ\lambdaλ:正则化强度(惩罚系数)
    • λ\lambdaλ 越大:惩罚越重,系数越小(模型越简单)
    • λ\lambdaλ 越小:惩罚越轻,系数越接近普通回归(易过拟合)
  • ∥w∥22=∑j=1nwj2\|w\|_2^2 = \sum_{j=1}^n w_j^2w22=j=1nwj2:L2范数(惩罚项核心),即所有特征系数的平方和
  • bbb(偏置项):通常不参与惩罚(避免模型整体偏移)

3. 解析解(岭回归解)

对目标函数求导并令导数为0,可得到闭合解(无需迭代,直接计算):
wridge=(X⊤X+mλI)−1X⊤y w_{ridge} = (X^\top X + m\lambda I)^{-1} X^\top y wridge=(XX+I)1Xy

  • III:单位矩阵,作用是让X⊤XX^\top XXX可逆(解决多重共线性导致的矩阵奇异问题)
  • 这也是岭回归比普通线性回归更稳定的核心原因

四、L2正则化的算法流程(必背)

  1. 数据准备:输入特征矩阵XXX,目标变量yyy
  2. 特征标准化(关键步骤)
    L2对特征尺度敏感(如“收入(万元)”和“年龄(岁)”),需标准化为“均值=0,方差=1”,确保惩罚公平
  3. 设置正则化系数λ\lambdaλ
    通过交叉验证选择最优λ\lambdaλ,平衡拟合误差与模型复杂度
  4. 训练岭回归模型
    最小化目标函数,得到稳定的系数www
  5. 软特征选择
    保留系数绝对值较大的特征,剔除系数接近0的特征(可设定阈值,如∣wj∣<0.01|w_j| < 0.01wj<0.01
  6. 模型评估:用筛选后的特征重新建模,验证泛化能力

五、Python 完整实战:加州房价预测与特征选择

1. 导入库+加载数据

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score

# 加载数据(20640个样本,8个特征)
housing = fetch_california_housing()
X = pd.DataFrame(housing.data, columns=housing.feature_names)
y = housing.target

print("样本数:", X.shape[0])
print("特征数:", X.shape[1])
print("特征名:", list(X.columns))
X.head()

2. 探索性数据分析(EDA)

# 1. 目标变量分布
plt.figure(figsize=(8, 4))
sns.histplot(y, bins=50, kde=True, color='#3498db')
plt.title("目标变量:房价中位数分布", fontsize=12)
plt.xlabel("房价中位数(单位:10万美元)")
plt.ylabel("频数")
plt.show()

# 2. 特征相关性热力图(查看多重共线性)
df_corr = X.copy()
df_corr['Target'] = y
corr = df_corr.corr()

plt.figure(figsize=(10, 8))
sns.heatmap(corr, annot=True, fmt=".2f", cmap='RdBu_r', vmin=-1, vmax=1)
plt.title("特征相关性热力图", fontsize=14)
plt.tight_layout()
plt.show()

3. 数据预处理(拆分+标准化)

# 1. 拆分训练集/测试集(7:3)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)

# 2. 标准化(L2正则化必须步骤)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

print("训练集标准化后形状:", X_train_scaled.shape)
print("测试集标准化后形状:", X_test_scaled.shape)

4. 初始岭回归模型(固定λ\lambdaλ

# 设置初始正则化系数
alpha_init = 1.0
ridge_init = Ridge(alpha=alpha_init, random_state=42)
ridge_init.fit(X_train_scaled, y_train)

# 查看特征系数
coef_init = pd.Series(ridge_init.coef_, index=X.columns).sort_values()
print("=== 初始岭回归(alpha=1.0)特征系数 ===")
print(coef_init)

# 模型性能评估
y_train_pred = ridge_init.predict(X_train_scaled)
y_test_pred = ridge_init.predict(X_test_scaled)

print(f"\n训练集 MSE: {mean_squared_error(y_train, y_train_pred):.4f}")
print(f"训练集 R²: {r2_score(y_train, y_train_pred):.4f}")
print(f"测试集 MSE: {mean_squared_error(y_test, y_test_pred):.4f}")
print(f"测试集 R²: {r2_score(y_test, y_test_pred):.4f}")

# 可视化特征系数
plt.figure(figsize=(10, 6))
coef_init.plot(kind='barh', color='teal')
plt.axvline(0, color='black', linewidth=1)
plt.title("初始模型特征系数(alpha=1.0)", fontsize=12)
plt.xlabel("系数大小")
plt.grid(alpha=0.3, axis='x')
plt.show()

5. 交叉验证找最优λ\lambdaλ(推荐做法)

# 生成候选lambda(对数分布,覆盖范围更广)
alphas = np.logspace(-3, 3, 50)  # 从0.001到1000的50个值

# 网格搜索+5折交叉验证
param_grid = {'alpha': alphas}
grid = GridSearchCV(
    Ridge(random_state=42),
    param_grid,
    cv=5,
    scoring='neg_mean_squared_error',  # 负MSE(越大越好)
    n_jobs=-1  # 并行计算
)
grid.fit(X_train_scaled, y_train)

# 最优结果
best_alpha = grid.best_params_['alpha']
best_ridge = grid.best_estimator_

print(f"=== 交叉验证最优结果 ===")
print(f"最优lambda: {best_alpha:.4f}")

# 最优模型性能
y_test_pred_best = best_ridge.predict(X_test_scaled)
print(f"优化后测试集 MSE: {mean_squared_error(y_test, y_test_pred_best):.4f}")
print(f"优化后测试集 R²: {r2_score(y_test, y_test_pred_best):.4f}")

6. λ\lambdaλ对模型的影响可视化

# 1. MSE随lambda变化趋势
mse_train_list = []
mse_test_list = []

for a in alphas:
    model = Ridge(alpha=a, random_state=42)
    model.fit(X_train_scaled, y_train)
    mse_train_list.append(mean_squared_error(y_train, model.predict(X_train_scaled)))
    mse_test_list.append(mean_squared_error(y_test, model.predict(X_test_scaled)))

plt.figure(figsize=(10, 6))
plt.plot(alphas, mse_train_list, label='训练集MSE', color='blue')
plt.plot(alphas, mse_test_list, label='测试集MSE', color='red')
plt.xscale('log')  # 对数刻度,更清晰
plt.xlabel('lambda(正则化强度)')
plt.ylabel('均方误差(MSE)')
plt.title('MSE随lambda变化趋势', fontsize=12)
plt.legend()
plt.grid(alpha=0.3)
plt.show()

# 2. 特征系数随lambda变化趋势
coef_df = pd.DataFrame(index=alphas, columns=X.columns)
for a in alphas:
    model = Ridge(alpha=a, random_state=42)
    model.fit(X_train_scaled, y_train)
    coef_df.loc[a] = model.coef_

plt.figure(figsize=(12, 6))
for col in X.columns:
    plt.plot(alphas, coef_df[col], label=col)
plt.xscale('log')
plt.xlabel('lambda(正则化强度)')
plt.ylabel('特征系数')
plt.title('特征系数随lambda变化路径', fontsize=12)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

7. 最优模型的特征筛选与可视化

# 最优模型特征系数
coef_best = pd.Series(best_ridge.coef_, index=X.columns).sort_values()

# 可视化最优系数
plt.figure(figsize=(10, 6))
coef_best.plot(kind='barh', color='purple')
plt.axvline(0, color='black', linewidth=1)
plt.title(f"最优模型特征系数(lambda={best_alpha:.4f})", fontsize=12)
plt.xlabel("系数大小")
plt.grid(alpha=0.3, axis='x')
plt.show()

# 软特征选择(筛选系数绝对值>0.05的特征)
threshold = 0.05
selected_features = coef_best[abs(coef_best) > threshold].index.tolist()
print(f"=== 筛选后的关键特征 ===")
print(selected_features)

# 用筛选后的特征重新建模
X_train_selected = X_train[selected_features]
X_test_selected = X_test[selected_features]

# 标准化筛选后的特征
scaler_selected = StandardScaler()
X_train_selected_scaled = scaler_selected.fit_transform(X_train_selected)
X_test_selected_scaled = scaler_selected.transform(X_test_selected)

# 训练最终模型
final_model = Ridge(alpha=best_alpha, random_state=42)
final_model.fit(X_train_selected_scaled, y_train)

# 最终性能
y_pred_final = final_model.predict(X_test_selected_scaled)
print(f"\n筛选后模型 R²: {r2_score(y_test, y_pred_final):.4f}")
print(f"筛选后模型 MSE: {mean_squared_error(y_test, y_pred_final):.4f}")

8. 预测结果可视化(真实值vs预测值)

plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_test_pred_best, alpha=0.3, color='blue')
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', linewidth=2)  # 对角线(理想预测)
plt.xlabel('真实房价中位数')
plt.ylabel('预测房价中位数')
plt.title('真实值 vs 预测值(最优岭回归模型)', fontsize=12)
plt.grid(alpha=0.3)
plt.show()

# 残差分布(验证模型假设合理性)
residuals = y_test - y_test_pred_best
plt.figure(figsize=(8, 4))
sns.histplot(residuals, bins=50, kde=True, color='gray')
plt.title('残差分布(真实值-预测值)', fontsize=12)
plt.xlabel('残差值')
plt.ylabel('频数')
plt.grid(alpha=0.3)
plt.show()

六、L2正则化的优缺点(必背)

优点

  1. 稳定处理多重共线性:通过正则化让相关特征系数均衡,避免普通回归的系数波动
  2. 防止过拟合:惩罚系数平方和,控制模型复杂度,提升泛化能力
  3. 数学解稳定:解析解存在且可逆(解决矩阵奇异问题),计算高效
  4. 保留全部特征:软筛选不直接删除特征,避免信息丢失(适合特征都有潜在价值的场景)
  5. 对异常值相对稳健:相比普通回归,受极端值影响更小

缺点

  1. 不能显式特征选择:系数不会直接为0,无法彻底删除无用特征(需手动设定阈值)
  2. 模型解释性略差:保留所有特征,即使系数接近0也会参与预测,不如L1简洁
  3. 依赖标准化:对特征尺度敏感,必须先标准化才能保证惩罚公平
  4. 不适用于稀疏建模:若需构建“少特征”的稀疏模型,L2不如L1或ElasticNet

七、L2正则化与其他特征选择方法对比

方法 正则项形式 是否稀疏 抗多重共线性 特征选择方式 适合场景
L2正则化(岭回归) ∑wj2\sum w_j^2wj2 软选择(系数接近0) 特征相关、需保留全部特征
L1正则化(Lasso) ∑\sum |wjw_jwj| 硬选择(系数=0) 高维数据、需稀疏建模
ElasticNet λ1∑\lambda_1\sumλ1 |wjw_jwj| + λ2∑wj2\lambda_2\sum w_j^2λ2wj2 混合选择 需平衡稀疏性与稳定性
树模型(RF/XGBoost) 基于节点分裂增益 嵌入式选择 非线性关系、特征交互复杂
过滤法(卡方/方差) 无(基于统计指标) 过滤式选择 初步粗筛、快速去除低价值特征

八、适用场景与替代方案

优先用L2正则化的情况

  1. 特征存在显著多重共线性(如经济、金融数据)
  2. 不希望删除任何特征(担心信息丢失)
  3. 追求模型稳定性和泛化能力(预测优先于解释)
  4. 线性模型场景(如线性回归、逻辑回归)

考虑其他方法的情况

  1. 需显式删除特征(稀疏建模):用L1正则化或ElasticNet
  2. 数据非线性、特征交互复杂:用随机森林、XGBoost(自带特征重要性)
  3. 快速粗筛特征:用过滤法(如方差阈值、互信息)
  4. 既要稀疏性又要稳定性:用ElasticNet(L1+L2混合)

九、最简单总结(背诵版)

  1. L2正则化(岭回归)= 线性回归 + L2范数惩罚(系数平方和)
  2. 核心作用:防过拟合、处理多重共线性、软特征选择
  3. 关键步骤:必须标准化特征 + 交叉验证调λ\lambdaλ
  4. 优点:稳定、抗共线性、保留全部特征
  5. 缺点:不直接删除特征、依赖标准化、不适用于稀疏建模
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐