3 Lasso 回归
看模型的范式 | Lasso 回归 |
---|---|
问题是什么 | 回归拟合 |
模型是什么 | 线性模型 |
优化指标 | 最小二乘损失的基础上+ L1 正则化项 |
求解方法 | 坐标下降法 |
评价模型 |
首先,lasso与岭回归都是正则化目标函数。但是,与岭回归不同,Lasso 使用L1正则化,这会带来特征选择的特性——将不重要特征的系数压缩至零,也就是生成稀疏解。 Lasso 在最小二乘损失的基础上添加 L1 正则化项(系数绝对值之和),其目标函数为: \(\begin{matrix}\text{Q=}&\min_\beta\left\{\|\mathbf{y}-\mathbf{X}\boldsymbol{\beta}\|_2^2+\lambda\|\boldsymbol{\beta}\|_1\right\}\end{matrix}\)
其中$λ$>0是正则化参数,$|\beta|1=\sum{j=1}^p | \beta_j | $是L1正则化项。我们的目标是求解参数向量$β$,使得$Q$的值最小。 |
由于L1正则项 $∥β∥1=\sum{j=1}^{n} | \beta_j | $ 不可导,故不能用常规求矩阵偏导的方式来计算$β$向量,一般采用坐标下降法。在固定其他参数的情况下,对每个系数$β_j$依次优化。具体方法如下: |
-
令 $\mathbf{r}^{(j)}=\mathbf{y}-\sum_{k\neq j}\mathbf{x}_k\beta_k$ 其中 $\mathbf{x}_j$ 是数据矩阵 $\mathbf{X}$ 的第j列;
-
令 $\rho_j=\mathbf{x}_j^\top\mathbf{r}^{(j)}$,$z_j=|\mathbf{x}_j|_2^2$
-
β的解由软阈值函数给出:$\hat{\beta}_j=\frac{1}{z_j}S(\rho_j,\lambda/2)$
其中软阈值算子 $S(z,\gamma)$ 表示为:$S(z,\gamma)=\begin{cases}z-\gamma & \text{if } z>\gamma \ 0 & \text{if } z \leq\gamma \ z+\gamma & \text{if } z<-\gamma\end{cases}$ -
初始设置 $\beta_1=0$,然后用 $\beta_1$ 去计算剩余 $\beta$,同样的其余 $\beta_k$ 也可用来更新 $\beta_1$,这样反复迭代直至收敛。
在变量多重共线性的时候,我们往往希望模型在足够有效的前提下,能够使用越少的变量越好,例如,当$x_1=x_2$时,我们希望得到的模型表达式为$ y=2x_1+0x_2$,而不是 $y=x_1+x_2$,这种能令部分系数为0的效果,就被称为系数稀疏化,它可以起到简化模型或者筛选变量的作用
以二维为例,岭回归的正则项 $L_N = \alpha(w_1^2 + w_2^2)$ 是一个圆,$L_E$ 要与 $L_N$ 相切于坐标轴是很难的反观Lasso的正则项 $L_N = \alpha( | w_1 | + | w_2 | )$,它是一个棱形,$L_E$ 要与 $L_N$ 相切于坐标轴却很容易因此,岭回归很难得到稀疏系数,而相比之下,LASSO回归更易得到稀疏系数。因此,在筛选变量的一种技术在建模之前,可以先用Lasso回归检测哪些变量的系数为0,然后把系数为0的变量去掉再进行建模 |
参考:
一篇入门之-Lasso回归模型原理与实现(含代码)-老饼讲解
线性回归大结局(岭(Ridge)、 Lasso回归原理、公式推导),你想要的这里都有 - 一无是处的研究僧 - 博客园
B站
代码示例:
from sklearn.linear_model import Lasso
import numpy as np
# 生成数据
x1 = np.arange(0,100) # 生成x1
x2 = x1*4+3 # 生成x2,这里的x2与x1是线性相关的
x = np.concatenate((x1.reshape(-1, 1),x2.reshape(-1, 1)),axis=1) # 将x1,x2合并作为x
y = x.dot([2,3]) # 生成y
# Lasso模型训练
alpha =0.3 # 设置正则项系数alpha
mdl = Lasso(alpha=alpha,fit_intercept=True,tol=1e-4,max_iter=1000) # 初始化Lasso回归模型
mdl.fit(x,y) # 用数据训练模型
sim_y= mdl.predict(x) # 预测
print('\nLasso训练结果:')
print('权重:'+str(mdl.coef_))
print('截距:'+ str(mdl.intercept_))
print( '均方误差:'+str(((y-sim_y)*(y-sim_y)).sum()))
print( '损失函数loss值:'+str(((y-sim_y)*(y-sim_y)).sum()/(2*x.shape[0])+alpha*(abs(mdl.coef_.sum()))))
print('迭代次数:'+str(mdl.n_iter_))