Elastic-Net是一种结合了L1和L2正则化的线性回归模型。它的目标是最小化一个损失函数,这个损失函数由三部分组成:
-
均方误差项:$$(\frac{1}{2n_{samples}}) Xw - y ^2$$,这部分是普通的线性回归损失,用于衡量模型的预测值与真实值之间的差异。 -
L1正则化项:$$αρ w _1$$,这部分是Lasso回归的惩罚项。它倾向于使一些系数变为零,从而实现特征选择,使模型变得稀疏。 -
L2正则化项:$$(α(1-ρ)/2) w _2^2$$,这部分是岭回归的惩罚项。它倾向于使所有系数都接近于零,以防止过拟合,但不会使系数完全变为零。
在scikit-learn
中,ElasticNet
的参数alpha
对应于公式中的α
,控制整体的惩罚力度。参数l1_ratio
对应于公式中的ρ
,它是一个介于0和1之间的混合比率。
- 当
l1_ratio
为0
时,模型退化为纯L2正则化,即岭回归(Ridge)。 - 当
l1_ratio
为1
时,模型退化为纯L1正则化,即Lasso回归。 - 当
l1_ratio
介于0
和1
之间时,它结合了Lasso和岭回归的优点,特别适用于特征之间存在高度相关性的情况。
1.代码模拟训练与不同模型对比
【1】导包,生成真实数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import numpy as np
from sklearn.linear_model import ElasticNet, LinearRegression, Lasso
import matplotlib.pyplot as plt
np.random.seed(42)
n_samples, n_features = 100, 50
X = np.random.randn(n_samples, n_features)
# 引入相关性:让前两个特征线性相关
X[:,0] = X[:,1] * 2 + np.random.randn(n_samples) * 0.1
# 真实的稀疏的系数
true_w = np.zeros(n_features)
true_w[:5] = np.array([10, -5, 3, 2, -1]) # 只有前5个特征系数非零
true_b = 5
y = X.dot(true_w) + true_b + np.random.randn(n_samples) * 2
print(f"真实的系数数量:{np.count_nonzero(true_w)}")
【2】模型训练与比较
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from sklearn.metrics import mean_squared_error
models = {
"普通线性回归": LinearRegression(),
"Lasso(alpha=0.1)": Lasso(alpha=0.1),
"Elastic Net(alpha=0.1,l1_ratio=0.7)": ElasticNet(alpha=0.1, l1_ratio=0.7)
}
coef_df = {
"真实系数":true_w
}
mse_results = {}
for name, model in models.items():
model.fit(X, y)
coef_df[name] = model.coef_
y_pred = model.predict(X)
mse = mean_squared_error(y, y_pred)
mse_results[name] = mse
print(f"- {name} : 均方误差(MSE)={mse:.2f}")
print(f"- 学到的非零系数的数量:{np.count_nonzero(model.coef_):.0f}")
【3】可视化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
plt.figure(figsize=(15, 8))
x_axis = np.arange(n_features)
width = 0.2
plt.bar(x_axis - 1.5*width, coef_df['真实系数'], width, label='真实系数', color='black')
plt.bar(x_axis - 0.5*width, coef_df['普通线性回归'], width, label='普通线性回归', color='skyblue')
plt.bar(x_axis + 0.5*width, coef_df['Lasso(alpha=0.1)'], width, label='Lasso (alpha=0.1)', color='salmon')
plt.bar(x_axis + 1.5*width, coef_df['Elastic Net(alpha=0.1,l1_ratio=0.7)'], width, label='Elastic-Net (alpha=0.1, l1_ratio=0.7)', color='lightgreen')
plt.title("不同模型学习到的系数与真实系数对比", fontsize=16)
plt.xlabel("特征索引", fontsize=12)
plt.ylabel("系数大小", fontsize=12)
plt.legend()
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()
真实系数:只有前5个特征有非零值,其余都为0。
普通线性回归:由于没有正则化,模型会为所有50个特征都计算出一个系数,其中一些可能是由噪声或特征相关性引起的,与真实系数有较大偏差。
Lasso回归:由于L1正则化,Lasso会倾向于将许多不重要的特征系数压缩为0,因此其非零系数的数量会显著减少,更接近真实的稀疏结构。
Elastic-Net回归:由于结合了L1和L2正则化,它也会将许多不重要的系数设为0,其表现会介于普通线性回归和Lasso之间,并且在处理相关特征时可能比Lasso更稳定。