哈喽,我是kk~
昨天,有同学反映,在字节的一面中居然问到了弹性网回归,这对于他来说,应该是非常简单。
毕竟刚刚毕业,虽然是重新找工作,但是对于基础理论的把握还是非常好的。
下面,咱们也把 弹性网回归 总结了一遍,和大家聊聊~
弹性网回归(Elastic Net Regression)是一种结合了岭回归(Ridge Regression)和Lasso回归(Lasso Regression)优点的线性回归方法。它在处理高维数据时表现得尤为出色,特别是当特征数目大于样本数目,或特征之间存在共线性时。
基本原理
弹性网回归的核心思想是通过正则化(regularization)来防止模型过拟合。在回归分析中,正则化技术用于控制模型复杂度,从而提高泛化能力。
目标函数
弹性网回归的目标函数可以表示为最小化以下损失函数:
其中:
是实际输出, 是模型预测值。 是样本数。 是特征数。 是回归系数。 和 是正则化参数,分别对应Lasso和Ridge部分的惩罚。
各部分
平方误差项: 是普通最小二乘法(OLS)损失,旨在最小化预测值与实际值之间的差异。
L1 正则化(Lasso): 增加了对模型稀疏性的约束,通过促使某些系数为零,实现特征选择。
L2 正则化(Ridge): 则用于抑制模型复杂度,使得系数分布更均匀,特别是在特征间存在多重共线性时,能够稳定系数估计。
优势
弹性网回归的主要优势在于:
特征选择:通过L1正则化,弹性网可以有效地选择重要特征,同时丢弃不重要的特征。 处理多重共线性:L2正则化部分能够有效处理特征之间的共线性问题,使得模型更稳定。 灵活性:通过调整 和 ,可以在Lasso和Ridge之间进行平衡,适应不同的数据特征。
参数选择
选择合适的 和 是弹性网回归的关键,通常可以使用交叉验证(cross-validation)来找到最佳参数组合。具体步骤如下:
划分训练集和验证集。 对不同的 和 值进行网格搜索。 在验证集上评估模型性能,选择使得验证集误差最小的参数组合。
手推公式
弹性网回归的解可以通过坐标下降法(coordinate descent)来求解。在每一步中,固定所有其他变量,逐个更新回归系数 。
更新公式
对于每一个系数 ,更新公式为:
其中, 是软阈值函数(soft thresholding function):
弹性网回归是一种强大且灵活的回归方法,能够有效地处理多维数据问题,兼具特征选择和稳定性的优势。通过适当的正则化参数选择,能够显著提升模型的预测性能和解释能力。
案例
在这个案例中,我们模拟一个房价预测的场景。我们将生成一些虚拟数据,包括房屋的特征(如面积、卧室数量、楼层等),然后使用弹性网回归模型来预测房价。我们将创建多种可视化图形来展示数据和模型的表现。
1. 数据生成
首先,我们需要生成一个虚拟数据集。这些特征将是随机生成的,以模拟现实世界中的特征。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 设置随机种子以确保可重复性
np.random.seed(42)
# 生成样本数和特征数
n_samples = 300
n_features = 10
# 生成随机特征
X = np.random.rand(n_samples, n_features) * 100 # 特征范围在0-100
true_coefficients = np.array([3, -2, 0, 5, 0, -1, 0, 0, 0, 0]) # 真实的系数
y = X @ true_coefficients + np.random.normal(0, 10, n_samples) # 添加一些噪声
# 创建DataFrame
feature_names = [f'Feature {i+1}' for i in range(n_features)]
data = pd.DataFrame(X, columns=feature_names)
data['Price'] = y
# 展示前5行数据
print(data.head())
2. 数据可视化
在训练模型之前,我们可以通过一些图形来观察数据的分布。
2.1 特征与目标变量的关系
我们将展示前两个特征与房价之间的关系。
# 特征与目标变量的关系
plt.figure(figsize=(14, 6))
# Feature 1
plt.subplot(1, 2, 1)
sns.scatterplot(x=data['Feature 1'], y=data['Price'], color='skyblue', s=50)
plt.title('Feature 1 vs Price', fontsize=16)
plt.xlabel('Feature 1', fontsize=14)
plt.ylabel('Price', fontsize=14)
plt.grid(True)
# Feature 2
plt.subplot(1, 2, 2)
sns.scatterplot(x=data['Feature 2'], y=data['Price'], color='salmon', s=50)
plt.title('Feature 2 vs Price', fontsize=16)
plt.xlabel('Feature 2', fontsize=14)
plt.ylabel('Price', fontsize=14)
plt.grid(True)
plt.tight_layout()
plt.show()
3. 模型训练
现在我们可以使用弹性网回归来训练模型。我们将使用sklearn
库来实现这一点。
from sklearn.model_selection import train_test_split
from sklearn.linear_model import ElasticNet
from sklearn.metrics import mean_squared_error, r2_score
# 拆分数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 初始化弹性网回归模型
elastic_net = ElasticNet(alpha=1.0, l1_ratio=0.5, random_state=42)
# 训练模型
elastic_net.fit(X_train, y_train)
# 预测
y_pred = elastic_net.predict(X_test)
# 计算模型性能
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print(f'Mean Squared Error: {mse:.2f}')
print(f'R^2 Score: {r2:.2f}')
4. 模型可视化
为了更好地理解模型的表现,我们可以绘制实际房价与预测房价之间的关系图。
4.1 实际与预测值的比较
# 实际值与预测值的比较
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, color='orange', alpha=0.7, s=100)
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], color='blue', linestyle='--', lw=2)
plt.title('Actual vs Predicted Prices', fontsize=16)
plt.xlabel('Actual Prices', fontsize=14)
plt.ylabel('Predicted Prices', fontsize=14)
plt.grid(True)
plt.xlim(min(y_test) - 10, max(y_test) + 10)
plt.ylim(min(y_test) - 10, max(y_test) + 10)
plt.show()
4.2 系数的可视化
我们可以通过条形图展示弹性网模型所学到的系数。
# 系数可视化
coefficients = elastic_net.coef_
plt.figure(figsize=(12, 6))
sns.barplot(x=feature_names, y=coefficients, palette='viridis') # 使用 feature_names
plt.title('Elastic Net Coefficients', fontsize=16)
plt.xlabel('Features', fontsize=14)
plt.ylabel('Coefficient Values', fontsize=14)
plt.xticks(rotation=45)
plt.grid(True)
plt.show()
5. 调参与交叉验证
为了找到最佳的正则化参数,我们可以使用交叉验证的方法来评估不同的 和 。
from sklearn.model_selection import GridSearchCV
# 网格搜索参数
param_grid = {
'alpha': [0.1, 0.5, 1.0, 1.5, 2.0],
'l1_ratio': [0.1, 0.3, 0.5, 0.7, 0.9]
}
# 初始化弹性网回归模型
elastic_net_cv = ElasticNet(random_state=42)
# 网格搜索
grid_search = GridSearchCV(elastic_net_cv, param_grid, cv=5, scoring='neg_mean_squared_error')
grid_search.fit(X_train, y_train)
# 输出最佳参数
print(f'Best Alpha: {grid_search.best_params_["alpha"]}')
print(f'Best L1 Ratio: {grid_search.best_params_["l1_ratio"]}')
6. 最终模型评估
使用最佳参数重新训练模型并进行最终评估。
# 使用最佳参数训练模型
best_model = ElasticNet(alpha=grid_search.best_params_['alpha'],
l1_ratio=grid_search.best_params_['l1_ratio'],
random_state=42)
best_model.fit(X_train, y_train)
y_pred_final = best_model.predict(X_test)
# 计算最终模型性能
final_mse = mean_squared_error(y_test, y_pred_final)
final_r2 = r2_score(y_test, y_pred_final)
print(f'Final Mean Squared Error: {final_mse:.2f}')
print(f'Final R^2 Score: {final_r2:.2f}')
7. 完整代码总结
将以上所有代码整合到一起,形成一个完整的示例。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.linear_model import ElasticNet
from sklearn.metrics import mean_squared_error, r2_score
# 设置随机种子
np.random.seed(42)
# 生成样本数和特征数
n_samples = 300
n_features = 10
X = np.random.rand(n_samples, n_features) * 100
true_coefficients = np.array([3, -2, 0, 5, 0, -1, 0, 0, 0, 0])
y = X @ true_coefficients + np.random.normal(0, 10, n_samples)
# 创建DataFrame
feature_names = [f'Feature {i+1}' for i in range(n_features)]
data = pd.DataFrame(X, columns=feature_names)
data['Price'] = y
# 可视化特征与价格关系
plt.figure(figsize=(14, 6))
plt.subplot(1, 2, 1)
sns.scatterplot(x=data['Feature 1'], y=data['Price'], color='skyblue', s=50)
plt.title('Feature 1 vs Price', fontsize=16)
plt.xlabel('Feature 1', fontsize=14)
plt.ylabel('Price', fontsize=14)
plt.grid(True)
plt.subplot(1, 2, 2)
sns.scatterplot(x=data['Feature 2'], y=data['Price'], color='salmon', s=50)
plt.title('Feature 2 vs Price', fontsize=16)
plt.xlabel('Feature 2', fontsize=14)
plt.ylabel('Price', fontsize=14)
plt.grid(True)
plt.tight_layout()
plt.show()
# 拆分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练弹性网回归模型
elastic_net = ElasticNet(alpha=1.0, l1_ratio=0.5, random_state=42)
elastic_net.fit(X_train, y_train)
y_pred = elastic_net.predict(X_test)
# 计算模型性能
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print(f'Mean Squared Error: {mse:.2f}')
print(f'R^2 Score: {r2:.2f}')
# 实际值与预测值比较
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, color='orange', alpha=0.7, s=100)
plt.plot([min(y_test), max(y_test)], [min(y_test), max(y_test)], color='blue', linestyle='--', lw=2)
plt.title('Actual vs Predicted Prices', fontsize=16)
plt.xlabel('Actual Prices', fontsize=14)
plt.ylabel('Predicted Prices', fontsize=14)
plt.grid(True)
plt.xlim(min(y_test) - 10, max(y_test) + 10)
plt.ylim(min(y_test) - 10, max(y_test) + 10)
plt.show()
# 系数可视化
coefficients = elastic_net.coef_
plt.figure(figsize=(12, 6))
sns.barplot(x=feature_names, y=coefficients, palette='viridis') # 使用 feature_names
plt.title('Elastic Net Coefficients', fontsize=16)
plt.xlabel('Features', fontsize=14)
plt.ylabel('Coefficient Values', fontsize=14)
plt.xticks(rotation=45)
plt.grid(True)
plt.show()
# 网格搜索参数
param_grid = {
'alpha': [0.1, 0.5, 1.0, 1.5, 2.0],
'l1_ratio': [0.1, 0.3, 0.5, 0.7, 0.9]
}
elastic_net_cv = ElasticNet(random_state=42)
grid_search = GridSearchCV(elastic_net_cv, param_grid, cv=5, scoring='neg_mean_squared_error')
grid_search.fit(X_train, y_train)
print(f'Best Alpha: {grid_search.best_params_["alpha"]}')
print(f'Best L1 Ratio: {grid_search.best_params_["l1_ratio"]}')
# 最终模型评估
best_model = ElasticNet(alpha=grid_search.best_params_['alpha'],
l1_ratio=grid_search.best_params_['l1_ratio'],
random_state=42)
best_model.fit(X_train, y_train)
y_pred_final = best_model.predict(X_test)
final_mse = mean_squared_error(y_test, y_pred_final)
final_r2 = r2_score(y_test, y_pred_final)
print(f'Final Mean Squared Error: {final_mse:.2f}')
print(f'Final R^2 Score: {final_r2:.2f}')
总结
在这个案例中,我们通过生成虚拟数据集来模拟房价预测的场景,使用弹性网回归模型进行训练和评估,并通过多种可视化手段展示了数据的分布和模型的性能。
都到这里了,点赞~
关于论文方面,我们最近组织了一个 1对1 的指导,感兴趣的同学可以扫码了解!~