回归 (Regression) 是一种建模任务,涉及在给定输入的情况下预测数值。
线性回归 (Linear regression) 是回归的标准算法,它假设输入和目标变量之间存在线性关系。线性回归的扩展是在训练期间向损失函数添加惩罚项,从而鼓励更简单的模型,使其系数取值更小。这些扩展被称为正则化线性回归或惩罚线性回归。
Lasso 回归 (Lasso Regression) 是一种流行的正则化线性回归类型,它包含 L1 惩罚。这会收缩那些对预测任务贡献不大的输入变量的系数。这种惩罚允许一些系数的值变为零,从而可以从模型中有效移除输入变量,提供一种自动特征选择的类型。
在本教程中,您将学习如何在 Python 中开发和评估 Lasso 回归模型。
完成本教程后,您将了解:
- Lasso 回归是线性回归的扩展,在训练期间向损失函数添加正则化惩罚。
- 如何评估 Lasso 回归模型并使用最终模型对新数据进行预测。
- 如何通过网格搜索和自动方式为新数据集配置 Lasso 回归模型。
让我们开始吧。

如何在Python中开发LASSO回归模型
照片作者:Phil Dolby,部分权利保留。
教程概述
本教程分为三个部分;它们是:
- Lasso回归
- Lasso 回归示例
- 调整 Lasso 超参数
Lasso回归
线性回归是指一个假设输入变量和目标变量之间存在线性关系的模型。
当只有一个输入变量时,这种关系是一条直线,而在更高维度时,这种关系可以被认为是连接输入变量和目标变量的超平面。模型的系数是通过优化过程找到的,该过程旨在最小化预测值 (yhat) 和期望目标值 (y) 之间的平方误差之和。
- loss = sum i=0 to n (y_i – yhat_i)^2
线性回归的一个问题是模型估计的系数可能很大,这使得模型对输入敏感且可能不稳定。对于观测值(样本)很少或样本数(n)少于输入预测变量(p)或变量(所谓的p >> n 问题)的问题尤其如此。
解决回归模型稳定性的一种方法是修改损失函数,为具有大系数的模型添加额外成本。在训练期间使用这些修改后损失函数的线性回归模型统称为惩罚线性回归。
一种流行的惩罚是根据系数绝对值之和来惩罚模型。这被称为 L1 惩罚。L1 惩罚最小化了所有系数的大小,并允许一些系数最小化为零,从而将预测变量从模型中移除。
- l1_penalty = sum j=0 to p abs(beta_j)
L1 惩罚最小化了所有系数的大小,并允许任何系数取值为零,从而有效地从模型中移除了输入特征。
这是一种自动特征选择。
…惩罚绝对值的一个结果是,对于某个 lambda 值,某些参数实际上被设置为 0。因此,lasso 产生的模型同时使用了正则化来改进模型和进行特征选择。
— 第 125 页,《应用预测建模》,2013。
此惩罚项可以添加到线性回归的成本函数中,并称为最小绝对收缩和选择算子正则化(LASSO),或更常见地简称为“Lasso”(首字母大写)。
岭回归 (ridge regression) 的一个流行替代方法是最小绝对收缩和选择算子模型,通常称为 lasso。
— 第 124 页,《应用预测建模》,2013。
有一个名为“lambda”的超参数,用于控制惩罚项对损失函数的加权。默认值 1.0 会为惩罚项提供完全权重;值为 0 则排除惩罚项。非常小的 lambda 值,例如 1e-3 或更小,是常见的。
- lasso_loss = loss + (lambda * l1_penalty)
现在我们熟悉了 Lasso 惩罚回归,让我们来看一个实际例子。
Lasso 回归示例
在本节中,我们将演示如何使用 Lasso 回归算法。
首先,让我们引入一个标准的回归数据集。我们将使用住房数据集。
住房数据集是一个标准的机器学习数据集,包含 506 行数据,其中有 13 个数值输入变量和一个数值目标变量。
使用重复的 10 折分层交叉验证和三次重复的测试框架,一个朴素模型可以达到约 6.6 的平均绝对误差 (MAE)。一个表现最佳的模型在此测试框架上可达到约 1.9 的 MAE。这为该数据集的预期性能提供了范围。
该数据集涉及根据美国波士顿市郊区的房屋细节来预测房价。
无需下载数据集;我们将在工作示例中自动下载它。
下面的示例下载并以 Pandas DataFrame 的形式加载数据集,并总结了数据集的形状和前五行数据。
1 2 3 4 5 6 7 8 9 10 |
# 加载和汇总住房数据集 from pandas import read_csv from matplotlib import pyplot # 加载数据集 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv' dataframe = read_csv(url, header=None) # 总结形状 print(dataframe.shape) # 总结前几行 print(dataframe.head()) |
运行示例,确认了 506 行数据和 13 个输入变量以及一个数值目标变量(共 14 个)。我们还可以看到所有输入变量都是数值型的。
1 2 3 4 5 6 7 8 9 |
(506, 14) 0 1 2 3 4 5 ... 8 9 10 11 12 13 0 0.00632 18.0 2.31 0 0.538 6.575 ... 1 296.0 15.3 396.90 4.98 24.0 1 0.02731 0.0 7.07 0 0.469 6.421 ... 2 242.0 17.8 396.90 9.14 21.6 2 0.02729 0.0 7.07 0 0.469 7.185 ... 2 242.0 17.8 392.83 4.03 34.7 3 0.03237 0.0 2.18 0 0.458 6.998 ... 3 222.0 18.7 394.63 2.94 33.4 4 0.06905 0.0 2.18 0 0.458 7.147 ... 3 222.0 18.7 396.90 5.33 36.2 [5 行 x 14 列] |
scikit-learn Python 机器学习库通过 Lasso 类提供了 Lasso 惩罚回归算法的实现。
令人困惑的是,lambda 项可以通过定义类时的“alpha”参数进行配置。默认值是 1.0,表示完全惩罚。
1 2 3 |
... # 定义模型 model = Lasso(alpha=1.0) |
我们可以使用重复 10 折交叉验证在住房数据集上评估 Lasso 回归模型,并报告数据集上的平均平均绝对误差 (MAE)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 在数据集上评估一个 lasso 回归模型 from numpy import mean from numpy import std from numpy import absolute from pandas import read_csv from sklearn.model_selection import cross_val_score from sklearn.model_selection import RepeatedKFold from sklearn.linear_model import Lasso # 加载数据集 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv' dataframe = read_csv(url, header=None) data = dataframe.values X, y = data[:, :-1], data[:, -1] # 定义模型 model = Lasso(alpha=1.0) # 定义模型评估方法 cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1) # 评估模型 scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1) # 将分数强制为正数 scores = absolute(scores) print('Mean MAE: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行该示例可以在住房数据集上评估 Lasso 回归算法,并报告 10 折交叉验证三次重复的平均 MAE。
鉴于学习算法的随机性,您的具体结果可能会有所不同。可以尝试运行几次示例。
在这种情况下,我们可以看到模型达到了约 3.711 的 MAE。
1 |
Mean MAE: 3.711 (0.549) |
我们可以决定使用 Lasso 回归作为最终模型,并对新数据进行预测。
这可以通过在所有可用数据上拟合模型并调用 predict() 函数来实现,传入新的数据行。
我们可以用一个完整的示例来演示这一点,如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 使用 lasso 回归模型对数据集进行预测 from pandas import read_csv from sklearn.linear_model import Lasso # 加载数据集 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv' dataframe = read_csv(url, header=None) data = dataframe.values X, y = data[:, :-1], data[:, -1] # 定义模型 model = Lasso(alpha=1.0) # 拟合模型 model.fit(X, y) # 定义新数据 row = [0.00632,18.00,2.310,0,0.5380,6.5750,65.20,4.0900,1,296.0,15.30,396.90,4.98] # 进行预测 yhat = model.predict([row]) # 总结预测 print('Predicted: %.3f' % yhat) |
运行示例,拟合模型并对新数据行进行预测。
鉴于学习算法的随机性,您的具体结果可能会有所不同。尝试运行几次示例。
1 |
Predicted: 30.998 |
接下来,我们可以看看如何配置模型超参数。
调整 Lasso 超参数
我们如何知道默认超参数 alpha=1.0 对我们的数据集是合适的?
我们不这样做。
相反,测试一组不同的配置并找出最适合我们数据集的方法是很好的做法。
一种方法是以对数 10 为基进行网格搜索 alpha 值,从 1e-5 到 100,找出最适合数据集的值。另一种方法是测试 0.0 到 1.0 之间的值,网格间隔为 0.01。我们将在此案例中尝试后者。
下面的示例使用 GridSearchCV 类和我们定义的网格值来演示这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# 为 lasso 回归进行网格搜索超参数 from numpy import arange from pandas import read_csv from sklearn.model_selection import GridSearchCV from sklearn.model_selection import RepeatedKFold from sklearn.linear_model import Lasso # 加载数据集 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv' dataframe = read_csv(url, header=None) data = dataframe.values X, y = data[:, :-1], data[:, -1] # 定义模型 model = Lasso() # 定义模型评估方法 cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1) # 定义网格 grid = dict() grid['alpha'] = arange(0, 1, 0.01) # 定义搜索 search = GridSearchCV(model, grid, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1) # 执行搜索 results = search.fit(X, y) # 总结 print('MAE: %.3f' % results.best_score_) print('Config: %s' % results.best_params_) |
运行示例将使用重复交叉验证评估每种配置组合。
鉴于学习算法的随机性,您的具体结果可能会有所不同。尝试运行几次示例。
您可能会看到一些可以安全忽略的警告,例如
1 |
目标未收敛。您可能希望增加迭代次数。 |
在这种情况下,我们可以看到我们取得了比默认值 3.711 略好的结果,为 3.379。忽略负号,库为了优化目的将 MAE 设为负数。
我们可以看到模型为该惩罚项分配了 alpha 权重 0.01。
1 2 |
MAE: -3.379 Config: {'alpha': 0.01} |
scikit-learn 库还提供了一个内置的算法版本,可以通过 LassoCV 类自动查找好的超参数。
要使用该类,模型将按正常方式拟合到训练数据集,并在训练过程中自动调整超参数。然后可以使用拟合模型进行预测。
默认情况下,模型将测试 100 个 alpha 值。我们可以通过设置“alphas”参数将其更改为 0 到 1 之间间隔为 0.01 的值网格,就像我们在上一个示例中所做的那样。
以下示例将演示这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 使用自动配置的 lasso 回归算法 from numpy import arange from pandas import read_csv from sklearn.linear_model import LassoCV from sklearn.model_selection import RepeatedKFold # 加载数据集 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv' dataframe = read_csv(url, header=None) data = dataframe.values X, y = data[:, :-1], data[:, -1] # 定义模型评估方法 cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1) # 定义模型 model = LassoCV(alphas=arange(0, 1, 0.01), cv=cv, n_jobs=-1) # 拟合模型 model.fit(X, y) # 总结选择的配置 print('alpha: %f' % model.alpha_) |
运行示例会拟合模型,并通过交叉验证发现能获得最佳结果的超参数。
鉴于学习算法的随机性,您的具体结果可能会有所不同。尝试运行几次示例。
在这种情况下,我们可以看到模型选择了超参数 alpha=0.0。这与我们通过手动网格搜索发现的结果不同,可能是由于搜索或选择配置的系统方式不同。
1 |
alpha: 0.000000 |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
书籍
API
文章
总结
在本教程中,您学习了如何在 Python 中开发和评估 Lasso 回归模型。
具体来说,你学到了:
- Lasso 回归是线性回归的扩展,在训练期间向损失函数添加正则化惩罚。
- 如何评估 Lasso 回归模型并使用最终模型对新数据进行预测。
- 如何通过网格搜索和自动方式为新数据集配置 Lasso 回归模型。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
如何将预测值的向量导出为 .csv 文件,而不是只导出 MAE?
好问题,请看本教程
https://machinelearning.org.cn/how-to-save-a-numpy-array-to-file-for-machine-learning/
非常感谢,现在可以工作了。假设我有许多模型的输出,如何将它们写入一个 .csv 文件,其中列名是模型名称?
首先将数据按您想要的方式组织到内存中,然后保存。
为什么权重会变成零而不是在正值和负值之间振荡?例如,假设 w=0.4 且 a*signw=0.5,下一次更新 w=-0.1 a*signw=-0.5,下一次更新 w=0.4。那么为什么不会发生周期性地发生这种情况,或者我在这里遗漏了什么?
在训练期间添加到损失中的权重惩罚会鼓励那些不为模型带来价值的输入的权重趋向于零。
哇,很棒的博客,我喜欢它,我学到了一个新算法。正在等待关于在纯 Python 3 中实现 LASSO 的文章。
谢谢!
你好 Jason,愿上帝保佑你,我们想要非线性回归算法。
感谢您的建议!
嗨,Jason,
当我想对 Lasso 进行分类时,如何实现调优超参数?
您可以使用网格搜索或随机搜索,或许可以从这里开始
https://machinelearning.org.cn/hyperparameter-optimization-with-random-search-and-grid-search/
非常感谢您提供如此有用的教程。
在使用 Lasso 时,我们可以使用 Standard Scaler 和 PCA 吗?
提前感谢
当然可以。
你好,
缩放(标准化/归一化)是否会对 LASSO 回归产生负面影响?在我的项目中,在缩放变量后,RMSE 从 135 增加到 220。请澄清我的疑虑。
代码是正确的,因为对于其他回归模型,我通过归一化得到了所需的结果。
不,缩放会有助于大多数线性模型——但它并非在所有情况下都有帮助。
如何将李克特量表类型的数据用于 LASSO 回归?请建议。
我建议在建模前对数据进行归一化或标准化。
https://machinelearning.org.cn/standardscaler-and-minmaxscaler-transforms-in-python/
嗨,Jason,
很棒的博客。我想知道如何在 Python 中为分类实现 lasso。
谢谢!
抱歉,此时我没有从头开始编码 lasso 的示例。
嗨,Jason,
LassoCV 在产生最佳 alpha 时是否考虑了每个折叠的标准差?如果没有,我们如何分别标准化不同的折叠以避免数据泄露?
谢谢,
Roi
数据标准化?我认为不是,也许文档可以帮助您
https://scikit-learn.cn/stable/modules/generated/sklearn.linear_model.LassoCV.html
“特别是对于观测值(样本)很少或样本数(n)多于输入预测变量(p)或变量(所谓的 p >> n 问题)的问题。”
– 我认为您可能弄反了?除非我理解错了,您指的是特征比样本多的情况,对吧?
没错。感谢您指出这一点。
嗨,Jason,
您知道如何输出 LASSO 的预测区间吗?如何获得 LASSO 的置信区间?
您只是在用不同的函数进行回归。所以,就像您在线性回归中所做的那样,在这里也是一样。
面板数据呢?简单和动态的,带工具变量、分类变量和虚拟变量的?
你好 D.K…请提供更具体的问题,以便我们能更好地帮助您。
你好,如何使用 LASSO 或 elasticnet 进行分类问题的特征选择?如果有人能在这方面指导我,我将非常感激。
你好 sara…以下讨论可能对您有帮助
https://stats.stackexchange.com/questions/381383/how-to-use-elastic-net-to-select-a-set-of-features
那么,ML Lasso 模型与稀疏表示中的非 ML Lasso 回归模型有何不同?
你好 Reclusive…以下讨论可能有助于澄清
https://stats.stackexchange.com/questions/151954/sparsity-in-lasso-and-advantage-over-ridge-statistical-learning
这是一个 Lasso 与普通回归几乎相同的示例。创建一个 alpha 找到 > 0 的示例是否会更好?这可能需要特征标准化。
你好 Endre…你说得对,在某些情况下,当 Lasso 的 alpha 参数(也称为正则化参数)设置得太低时,Lasso 可能与普通最小二乘 (OLS) 回归非常相似,系数收缩程度很小。为了更有效地展示 Lasso 的效果,最好选择一个 alpha 参数有显著影响(即 \(\alpha > 0\)) 的示例。
### 增强 Lasso 回归示例的步骤
1. **特征标准化:**
– Lasso 回归对特征的尺度敏感。标准化或归一化特征很重要,这样它们才能对模型做出相等的贡献。
– 在应用 Lasso 回归之前,您可以使用 Scikit-learn 的
StandardScaler
来标准化数据集。2. **选择合适的 Alpha:**
– 首先使用交叉验证测试一系列 alpha 值,以找到正则化效果显著的最优值。
– 使用 Scikit-learn 的
LassoCV
或GridSearchCV
自动查找最佳 alpha,以最小化交叉验证误差。3. **演示系数收缩:**
– 在应用具有合适 alpha 的 Lasso 后,展示一些系数如何被减小到零,从而证明 Lasso 执行特征选择的能力。
– 与 OLS 进行比较,以突出模型复杂度和系数值的差异。
### 实现示例
python
from sklearn.linear_model import Lasso, LassoCV
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import numpy as np
# 示例数据集(假设 X、y 已定义)
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)
# 执行 LassoCV 以找到最优 alpha
lasso_cv = LassoCV(cv=5, random_state=42)
lasso_cv.fit(X_train_scaled, y_train)
# 最优 alpha
best_alpha = lasso_cv.alpha_
print(f'最优 alpha: {best_alpha}')
# 使用最佳 alpha 应用 Lasso
lasso = Lasso(alpha=best_alpha)
lasso.fit(X_train_scaled, y_train)
# 预测和性能
y_pred = lasso.predict(X_test_scaled)
mse = mean_squared_error(y_test, y_pred)
print(f'均方误差: {mse}')
# 显示系数
print("Lasso 后的系数:")
print(lasso.coef_)
### 关键点
– **特征标准化:**确保特征贡献相等,Lasso 能够有效地惩罚系数。
– **最优 Alpha:**选择合适的 alpha 有助于展示正则化的强度,从而实现有意义的系数收缩。
– **与 OLS 比较:**突出 Lasso 和 OLS 之间非零系数数量的差异,强调 Lasso 的特征选择能力。
这种方法将使示例更加稳健和信息丰富,展示 Lasso 和常规回归之间的实际差异。