本文目录导读:

我来详细介绍如何使用Scikit-learn实现弹性网络(Elastic Net)回归,包括完整的案例代码。
弹性网络简介
弹性网络结合了L1(Lasso)和L2(Ridge)正则化,适用于特征数量多于样本数量或特征间存在相关性的情况。
完整案例代码
数据生成与模型训练
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, cross_val_score, GridSearchCV
from sklearn.linear_model import ElasticNet
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
import warnings
warnings.filterwarnings('ignore')
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 1. 生成示例数据
print("="*50)
print("1. 生成示例数据")
print("="*50)
# 生成具有噪声的回归数据
np.random.seed(42)
X, y, true_coef = make_regression(
n_samples=200, # 样本数量
n_features=20, # 特征数量
n_informative=10, # 有用的特征数量
noise=20, # 噪声水平
coef=True, # 返回真实系数
random_state=42
)
print(f"数据形状: X: {X.shape}, y: {y.shape}")
print(f"真实系数非零个数: {np.sum(true_coef != 0)}")
print(f"前10个真实系数: {true_coef[:10]}")
# 2. 数据预处理
print("\n" + "="*50)
print("2. 数据预处理")
print("="*50)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 标准化特征
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
print(f"训练集大小: {X_train.shape[0]} 样本")
print(f"测试集大小: {X_test.shape[0]} 样本")
# 3. 使用默认参数训练ElasticNet
print("\n" + "="*50)
print("3. 基础ElasticNet模型")
print("="*50)
# 创建弹性网络模型
# alpha: 正则化强度 (越大正则化越强)
# l1_ratio: L1正则化比例 (0=Ridge, 1=Lasso)
elastic_net = ElasticNet(
alpha=1.0,
l1_ratio=0.5,
random_state=42,
max_iter=10000
)
# 训练模型
elastic_net.fit(X_train_scaled, y_train)
# 预测
y_pred_train = elastic_net.predict(X_train_scaled)
y_pred_test = elastic_net.predict(X_test_scaled)
# 评估模型
print(f"训练集 R²: {r2_score(y_train, y_pred_train):.4f}")
print(f"测试集 R²: {r2_score(y_test, y_pred_test):.4f}")
print(f"测试集 MSE: {mean_squared_error(y_test, y_pred_test):.4f}")
print(f"测试集 MAE: {mean_absolute_error(y_test, y_pred_test):.4f}")
print(f"非零系数个数: {np.sum(elastic_net.coef_ != 0)}")
# 4. 超参数调优
print("\n" + "="*50)
print("4. 超参数调优 (GridSearchCV)")
print("="*50)
# 定义参数网格
param_grid = {
'alpha': [0.001, 0.01, 0.1, 1.0, 10.0],
'l1_ratio': [0.1, 0.3, 0.5, 0.7, 0.9, 1.0]
}
# 创建ElasticNet模型
elastic_net_base = ElasticNet(random_state=42, max_iter=10000)
# 网格搜索
grid_search = GridSearchCV(
estimator=elastic_net_base,
param_grid=param_grid,
scoring='r2',
cv=5,
n_jobs=-1,
verbose=1
)
# 执行网格搜索
grid_search.fit(X_train_scaled, y_train)
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳交叉验证得分: {grid_search.best_score_:.4f}")
# 5. 使用最佳参数训练模型
print("\n" + "="*50)
print("5. 优化后的模型")
print("="*50)
best_elastic = grid_search.best_estimator_
y_pred_best = best_elastic.predict(X_test_scaled)
print(f"优化后测试集 R²: {r2_score(y_test, y_pred_best):.4f}")
print(f"优化后测试集 MSE: {mean_squared_error(y_test, y_pred_best):.4f}")
print(f"非零系数个数: {np.sum(best_elastic.coef_ != 0)}")
# 6. 交叉验证
print("\n" + "="*50)
print("6. 交叉验证评估")
print("="*50)
cv_scores = cross_val_score(best_elastic, X_train_scaled, y_train, cv=5, scoring='r2')
print(f"交叉验证 R² 得分: {cv_scores}")
print(f"平均 R²: {cv_scores.mean():.4f} (+/- {cv_scores.std() * 2:.4f})")
# 7. 特征重要性分析
print("\n" + "="*50)
print("7. 特征重要性分析")
print("="*50)
# 获取特征系数
feature_importance = pd.DataFrame({
'feature': [f'Feature_{i}' for i in range(X.shape[1])],
'coefficient': best_elastic.coef_
})
feature_importance['abs_coefficient'] = np.abs(feature_importance['coefficient'])
feature_importance = feature_importance.sort_values('abs_coefficient', ascending=False)
print("重要特征 (Top 10):")
print(feature_importance.head(10))
print(f"\n零系数特征个数: {np.sum(best_elastic.coef_ == 0)}")
# 8. 可视化
print("\n" + "="*50)
print("8. 可视化分析")
print("="*50)
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
# 8.1 真实值 vs 预测值
axes[0, 0].scatter(y_test, y_pred_best, alpha=0.6, edgecolors='k')
axes[0, 0].plot([y.min(), y.max()], [y.min(), y.max()], 'r--', lw=2)
axes[0, 0].set_xlabel('真实值')
axes[0, 0].set_ylabel('预测值')
axes[0, 0].set_title(f'真实值 vs 预测值 (R² = {r2_score(y_test, y_pred_best):.4f})')
axes[0, 0].grid(True, alpha=0.3)
# 8.2 残差图
residuals = y_test - y_pred_best
axes[0, 1].scatter(y_pred_best, residuals, alpha=0.6, edgecolors='k')
axes[0, 1].axhline(y=0, color='r', linestyle='--', lw=2)
axes[0, 1].set_xlabel('预测值')
axes[0, 1].set_ylabel('残差')
axes[0, 1].set_title('残差图')
axes[0, 1].grid(True, alpha=0.3)
# 8.3 系数比较
axes[0, 2].plot(true_coef, 'o-', label='真实系数', alpha=0.7)
axes[0, 2].plot(best_elastic.coef_, 's-', label='弹性网络系数', alpha=0.7)
axes[0, 2].set_xlabel('特征索引')
axes[0, 2].set_ylabel('系数值')
axes[0, 2].set_title('系数比较')
axes[0, 2].legend()
axes[0, 2].grid(True, alpha=0.3)
# 8.4 不同alpha值的表现
alphas = [0.001, 0.01, 0.1, 1.0, 10.0]
r2_scores_alpha = []
non_zero_coefs = []
for alpha in alphas:
en = ElasticNet(alpha=alpha, l1_ratio=0.5, random_state=42, max_iter=10000)
en.fit(X_train_scaled, y_train)
y_pred = en.predict(X_test_scaled)
r2_scores_alpha.append(r2_score(y_test, y_pred))
non_zero_coefs.append(np.sum(en.coef_ != 0))
axes[1, 0].semilogx(alphas, r2_scores_alpha, 'o-', linewidth=2)
axes[1, 0].set_xlabel('Alpha (对数尺度)')
axes[1, 0].set_ylabel('R² 得分')
axes[1, 0].set_title('不同Alpha值的R²得分')
axes[1, 0].grid(True, alpha=0.3)
# 8.5 不同l1_ratio值的表现
l1_ratios = [0.1, 0.3, 0.5, 0.7, 0.9, 1.0]
r2_scores_l1 = []
non_zero_coefs_l1 = []
for l1_ratio in l1_ratios:
en = ElasticNet(alpha=0.1, l1_ratio=l1_ratio, random_state=42, max_iter=10000)
en.fit(X_train_scaled, y_train)
y_pred = en.predict(X_test_scaled)
r2_scores_l1.append(r2_score(y_test, y_pred))
non_zero_coefs_l1.append(np.sum(en.coef_ != 0))
axes[1, 1].plot(l1_ratios, r2_scores_l1, 'o-', linewidth=2, label='R²得分')
axes[1, 1].plot(l1_ratios, non_zero_coefs_l1, 's-', linewidth=2, label='非零系数')
axes[1, 1].set_xlabel('L1 Ratio')
axes[1, 1].set_ylabel('数值')
axes[1, 1].set_title('不同L1 Ratio的表现')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)
# 8.6 特征重要性条形图
top_10_features = feature_importance.head(10)
axes[1, 2].barh(range(10), top_10_features['coefficient'].values,
color=['red' if x < 0 else 'blue' for x in top_10_features['coefficient']])
axes[1, 2].set_yticks(range(10))
axes[1, 2].set_yticklabels(top_10_features['feature'].values)
axes[1, 2].set_xlabel('系数值')
axes[1, 2].set_title('Top 10 特征重要性')
axes[1, 2].axvline(x=0, color='k', linestyle='-', linewidth=0.5)
axes[1, 2].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 9. 模型比较
print("\n" + "="*50)
print("9. 模型比较 (默认vs优化)")
print("="*50)
models_comparison = pd.DataFrame({
'模型': ['默认ElasticNet', '优化ElasticNet'],
'训练集R²': [r2_score(y_train, y_pred_train),
r2_score(y_train, best_elastic.predict(X_train_scaled))],
'测试集R²': [r2_score(y_test, y_pred_test), r2_score(y_test, y_pred_best)],
'非零系数': [np.sum(elastic_net.coef_ != 0), np.sum(best_elastic.coef_ != 0)]
})
print(models_comparison.to_string(index=False))
关键参数说明
主要参数
- alpha: 正则化强度参数(λ),控制整体正则化程度
- alpha越大,正则化越强,模型越简单
- alpha越小,模型更复杂,容易过拟合
- l1_ratio: L1正则化的比例(ρ)
- l1_ratio=0: 纯Ridge回归
- l1_ratio=1: 纯Lasso回归
- 0<l1_ratio<1: 弹性网络
参数选择建议
# 对于高维稀疏数据的参数选择
params_sparse = {
'alpha': [0.001, 0.01, 0.1], # 较小的alpha
'l1_ratio': [0.7, 0.9, 1.0] # 接近Lasso
}
# 对于数据相关性强的参数选择
params_correlated = {
'alpha': [0.1, 1.0, 10.0], # 较大的alpha
'l1_ratio': [0.2, 0.4, 0.6] # 平衡L1和L2
}
实际应用示例
使用真实数据集
from sklearn.datasets import load_diabetes
# 加载糖尿病数据集
diabetes = load_diabetes()
X, y = diabetes.data, diabetes.target
# 创建弹性网络模型
elastic = ElasticNet(alpha=0.1, l1_ratio=0.5)
# 训练和评估
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
elastic.fit(X_train, y_train)
print(f"测试集R²: {elastic.score(X_test, y_test):.4f}")
注意事项
- 数据标准化:弹性网络对特征尺度敏感,务必先进行标准化
- 特征选择:l1_ratio接近1时特征选择效果更明显
- 计算效率:大规模数据建议使用
SAGA求解器 - 早停:设置
max_iter足够大,避免迭代不充分
这个案例涵盖了弹性网络的主要功能和使用场景,你可以根据实际需求调整参数和可视化部分。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播