L1正则L2正则
本系列重点在浅显易懂,快速上手。不进行过多的理论讲解:也就是不去深究what,而是关注how。全文围绕以下三个问题展开:
1)长什么样?
2)解决什么问题?
3)怎么实现?
3.1)从数学讲,原理
3.2)从代码上讲,如何掉包实现
1)长什么样
该系列第一篇文章讲了线性回归,它的损失函数是MSE(误差平方和):
J ( θ ) = 1 2 ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 J\left(\theta\right)=\frac{1}{2}\sum_{i=1}^{m}\left(h_{\theta}\left(x^{\left(i\right)}\right)-y^{\left(i\right)}\right)^{2} J(θ)=21i=1∑m(hθ(x(i))−y(i))2
为了防止过拟合,也就是θ值不能过大或过小,可以在目标函数上增加一个正则项,来对θ进行约束,具体有两种方式就是所谓的L1正则和L2正则。如下:
L1正则:加入了L1正则的线性回归模型也称为LASSO回归。
J ( θ ) = 1 2 ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 + λ ∑ j = 1 n ∣ θ j ∣ , λ > 0 J\Big(\theta\Big)=\frac{1}{2}\sum_{i=1}^{m}\Big(h_{\theta}\Big(x^{\left(i\right)}\Big)-y^{\left(i\right)}\Big)^{2}+\lambda\sum_{j=1}^{n}\Big|\theta_{j}\Big|\quad,\lambda\:>\:0 J(θ)=21i=1∑m(hθ(x(i))−y(i))2+λj=1∑n θj ,λ>0
L2正则:加入了L2正则的线性回归模型也称为Ridge回归(岭回归)。
J ( θ ) = 1 2 ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 + λ ∑ i = 1 n θ j 2 , λ > 0 J\Big(\theta\Big)=\frac{1}{2}\sum_{i=1}^{m}\Big(h_{\theta}\Big(x^{(i)}\Big)-y^{(i)}\Big)^{2}+\lambda\sum_{i=1}^{n}\theta^{2}_{j}\quad,\lambda\:>\:0 J(θ)=21i=1∑m(hθ(x(i))−y(i))2+λi=1∑nθj2,λ>0
2)解决什么问题
用来解决过拟合问题,当特征的维度过多时,L1可以产生稀疏解,就是一些特征的系数为0,所以可以用来做特征选择。L2正则化可以获得平滑(smooth)解。
3)怎么实现
数学原理
到底L1和L2正则是怎么实现约束θ参数的,我们将J(θ)拆开看。
第一部分为:
1 2 ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 \frac{1}{2}\sum_{i=1}^{m}\Big(h_{\theta}\Big(x^{\left(i\right)}\Big)-y^{\left(i\right)}\Big)^{2} 21i=1∑m(hθ(x(i))−y(i))2
如果以二元函数为例,假设就两个特征。上式就是一个椭圆方程。θ1和θ2的取值在等高线上,二维上就是 一组同心圆,越靠近圆心,损失值越小。
再看第二部分:将θ1和θ2的取值,限制在阴影面积内,越靠近远点,L1正则的值越小,λ的值越大对θ的限制越厉害。
λ ∑ j = 1 n ∣ θ j ∣ \lambda\sum_{j=1}^{n}\Big|\theta_{j}\Big|\quad λj=1∑n θj
将两个图合在一起,θ就取值在两个图形的交点上,梯度下降法,事实上是在沿着梯度(最大方向导数)的方向优化θ,可以理解为由交点指向圆心,将梯度进行分解,一个分向量沿着L1正则图形的边,一个垂直于边,显然垂直方向的分量被约束了,所以交点会沿着边移动,移动到坐标轴的交点,就实现了部分特征的系数为0。
同理L2正则项的,图像如下:θ被限制在圆上。梯度的分向量一个沿着圆的切线一个垂直于圆的切线,牵引着θ在圆上移动,但不会正好把交点牵引到坐标轴上,所以L2正则的θ会充分考虑每个特征。
如果想要即使用L1正则,又使用L2正则,就是弹性网络算法(Elasitc Net)。
J ( θ ) = 1 2 ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 + λ ( p ∑ j = 1 n ∣ θ j ∣ + ( 1 − p ) ∑ j = 1 n θ j 2 ) J\left(\theta\right)=\frac{1}{2}\sum_{i=1}^{m}\left(h_{\theta}\left(x^{(i)}\right)-y^{(i)}\right)^{2}+\lambda\Bigg(p\sum_{j=1}^{n}\left|\theta_{j}\right|+\left(1-p\right)\sum_{j=1}^{n}\theta_{j}^{2}\Bigg) J(θ)=21i=1∑m(hθ(x(i))−y(i))2+λ(pj=1∑n∣θj∣+(1−p)j=1∑nθj2)
掉包实现
实际上只需要在其他机器学习方法的参数里面定义penalty【 **{‘l1’, ‘l2’, ‘elasticnet’, None}, default=’l2’】**参数就可以了。
以逻辑回归为例:
from sklearn.linear_model import LogisticRegression #sklearn中,线性回归模型在linear_model模块中
# 调取sklearn中自带的数据集
from sklearn.datasets import load_iris #调用上文一开始提到大波士顿房价数据集
X, y = load_boston(return_X_y=True) #获取X,y数据
ndarray = np.c_[X,y]
X = ndarray[np.where(ndarray[:,-1:]<2)[0]] #逻辑回归做2分类,只筛选y值为0和1的样本
LR = LogisticRegression(penalty="L1") #初始化一个逻辑回归模型,在初始化模型的时候定义L1、L2正则。
LR.fit(X,y) #fit函数用于训练
LR.predict(X) #predict函数用于预测
LR.coef_ #coef_用于返回θ的值
LR.intercept_ #intercept_用于返回常数项的值(截距)
上文中提到的lasso回归,ridge回归,Elasitc Net在sklearn中都有对应的模块:
from sklearn.linear_model import Lasso
from sklearn.linear_model import Ridge
from sklearn.linear_model import ElasticNet
使用方法和上面一样,不再赘述。
详情参考sklearn官网:
API Reference — scikit-learn 1.3.0 documentation
PI Reference — scikit-learn 1.3.0 documentation](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.linear_model)