using-sparsity-to-regularize-models

LASSO正则化

LASSO( least absolute shrinkage and selection operator,最小绝对值收缩和选择算子)方法与岭回归和LARS(least angle regression,最小角回归)很类似。与岭回归类似,它也是通过增加惩罚函数来判断、消除特征间的共线性。与LARS相似的是它也可以用作参数选择,通常得出一个相关系数的稀疏向量。

Getting ready

岭回归也不是万能药。有时就需要用LASSO回归来建模。本主题将用不同的损失函数,因此就要用对应的效果评估方法。

How to do it...

首先,我们还是用make_regression函数来建立数据集:

In [3]:
from sklearn.datasets import make_regression
reg_data, reg_target = make_regression(n_samples=200, n_features=500, n_informative=5, noise=5)

之后,我们导入lasso对象:

In [6]:
from sklearn.linear_model import Lasso
lasso = Lasso()

lasso包含很多参数,但是最意思的参数是alpha,用来调整lasso的惩罚项,在How it works...会具体介绍。现在我们用默认值1。另外,和岭回归类似,如果设置为0,那么lasso就是线性回归:

In [8]:
lasso.fit(reg_data, reg_target)
Out[8]:
Lasso(alpha=1.0, copy_X=True, fit_intercept=True, max_iter=1000,
   normalize=False, positive=False, precompute=False, random_state=None,
   selection='cyclic', tol=0.0001, warm_start=False)

再让我们看看还有多少相关系数非零:

In [9]:
import numpy as np
np.sum(lasso.coef_ != 0)
Out[9]:
9
In [10]:
lasso_0 = Lasso(0)
lasso_0.fit(reg_data, reg_target)
np.sum(lasso_0.coef_ != 0)
d:\programfiles\Miniconda3\lib\site-packages\IPython\kernel\__main__.py:2: UserWarning: With alpha=0, this algorithm does not converge well. You are advised to use the LinearRegression estimator
  from IPython.kernel.zmq import kernelapp as app
d:\programfiles\Miniconda3\lib\site-packages\sklearn\linear_model\coordinate_descent.py:432: UserWarning: Coordinate descent with alpha=0 may lead to unexpected results and is discouraged.
  positive)
Out[10]:
500

和我们设想的一样,如果用线性回归,没有一个相关系数变成0。而且,如果你这么运行代码,scikit-learn会给出建议,就像上面显示的那样。

How it works...

对线性回归来说,我们是最小化残差平方和。而LASSO回归里,我们还是最小化残差平方和,但是加了一个惩罚项会导致稀疏。如下所示:

$$\sum {e_i + \lambda \ {\begin{Vmatrix} \beta \end{Vmatrix}}_1} $$

最小化残差平方和的另一种表达方式是:

$$ RSS(\beta),其中 {\begin{Vmatrix} \beta \end{Vmatrix}}_1 \lt \beta $$

这个约束会让数据稀疏。LASSO回归的约束创建了围绕原点的超立方体(相关系数是轴),也就意味着大多数点都在各个顶点上,那里相关系数为0。而岭回归创建的是超平面,因为其约束是L2范数,少一个约束,但是即使有限制相关系数也不会变成0。

LASSO交叉检验

上面的公式中,选择适当的$\lambda$(在scikit-learn的Lasso里面是alpha,但是书上都是$\lambda$)参数是关键。我们可以自己设置,也可以通过交叉检验来获取最优参数:

In [11]:
from sklearn.linear_model import LassoCV
lassocv = LassoCV()
lassocv.fit(reg_data, reg_target)
Out[11]:
LassoCV(alphas=None, copy_X=True, cv=None, eps=0.001, fit_intercept=True,
    max_iter=1000, n_alphas=100, n_jobs=1, normalize=False, positive=False,
    precompute='auto', random_state=None, selection='cyclic', tol=0.0001,
    verbose=False)

lassocv有一个属性就是确定最合适的$\lambda$:

In [13]:
lassocv.alpha_
Out[13]:
0.58535963603062136

计算的相关系数也可以看到:

In [17]:
lassocv.coef_[:5]
Out[17]:
array([ 0.       , -0.       ,  0.       ,  0.0192606, -0.       ])

用最近的参数拟合后,lassocv的非零相关系数有29个:

In [18]:
np.sum(lassocv.coef_ != 0)
Out[18]:
29

LASSO特征选择

LASSO通常用来为其他方法所特征选择。例如,你可能会用LASSO回归获取适当的特征变量,然后在其他算法中使用。

要获取想要的特征,需要创建一个非零相关系数的列向量,然后再其他算法拟合:

In [22]:
mask = lassocv.coef_ != 0
new_reg_data = reg_data[:, mask]
new_reg_data.shape
Out[22]:
(200, 29)