视频作者:菜菜TsaiTsai 链接:【技术干货】菜菜的机器学习sklearn【全85集】Python进阶_哔哩哔哩_bilibili
正则化是用来防止模型过拟合的过程,常用的有L1正则化和L2正则化两种选项。这个增加的范式,被称为“正则项”,也被称为"惩罚项"。损失函数改变,基于损失函数的最优化来求解的参数取值必然改变,我们以此来调节模型拟合的程度。 其中L1范式表现为参数向量中的每个参数的绝对值之和,L2范数表现为参数向量中的每个参数的平方和的开方值。 $$ \begin{aligned} J(\theta){L1}&=C \cdot J(\theta)+\sum\limits{j=1}^{p}|\theta_{j}|\quad (j \geq 1)\ J(\theta){L2}&=C \cdot J(\theta)+\sqrt{\sum\limits{j=1}^{p}(\theta_{j})^{2}}\quad (j \geq 1) \end{aligned} $$ 其中$J(\theta)$是损失函数,$C$是用来控制正则化程度的超参数,$p$是方程中特征的总数,$\theta_{j}$代表每一个参数,在这里$j$要大于等于1,因为我们参数向量$\theta$中的一个参数是$\theta_{0}$,而截距通常是不参与正则化的 sklearn当中,常数项C是在损失函数的前面,通过调控损失函数本身的大小,来调节对模型的惩罚。
在许多书籍和博客中,大家可能也会见到如下的写法: $$ \begin{aligned} J(\theta){L1}&=J(\theta)+ \frac{1}{2b^{2}}\sum\limits{j}^{}|\theta_{j}|\ J(\theta)_{L2}&=J(\theta)+ \frac{\theta^{T}\theta}{2\sigma^{2}} \end{aligned} $$ 其实和上面我们展示的式子的本质是一模一样的。在大多数教材和博客中,常数项是乘以正则项,通过调控正则项来调节对模型的惩罚。
L1正则化和L2正则化虽然都可以控制过拟合,但它们的效果并不相同。当正则化强度逐渐增大(即C逐渐变小),参数$\theta$的取值会逐渐变小,但L1正则化会将参数压缩为0,L2正则化只会让参数尽量小,不会取到0,也就是所说的L1正则化会产生稀疏解。
部分的正则化方法是在经验风险或者经验损失$L_{emp}$(emprirical loss)上加上一个结构化风险,结构化风险用参数范数惩罚$\Omega(\theta)$,用来限制模型的学习能力、通过防止过拟合来提高泛化能力。
所以总的损失函数(也叫目标函数)为: $$ J(\theta; X, y) = L_{emp}(\theta; X, y) + \alpha\Omega(\theta) $$ 其中$X$是输入数据,$y$是标签,$\theta$是参数,$\alpha \in [0,+∞]$是用来调整参数范数惩罚与经验损失的相对贡献的超参数,当$α=0$时表示没有正则化,$α$越大对应该的正则化惩罚就越大。对于L1正则化(其中$\omega$是模型的参数) 有: $$ \Omega(\theta) = ||\omega||_{1} $$ 面中的蓝色轮廓线是没有正则化损失函数的等高线,中心的蓝色点为最优解,左图、右图分别为L2、L1正则化给出的限制。 可以看到在正则化的限制之下,L2正则化给出的最优解$\omega∗$是使解更加靠近原点,也就是说L2正则化能降低参数范数的总和。L1正则化给出的最优解$\omega∗$是使解更加靠近某些轴,而其它的轴则为0,所以L1正则化能使得到的参数稀疏化作者:自由星人布丁 链接:机器学习-L1正则化为什么会产生稀疏解 - 知乎 (zhihu.com)
文章还有更详细的数学上的推导关于L1范数约束会得到稀疏的解
在L1正则化在逐渐加强的过程中,携带信息量小的、对模型贡献不大的特征的参数,会比携带大量信息的、对模型有巨大贡献的特征的参数更快地变成0,所以L1正则化本质是一个特征选择的过程,掌管了参数的“稀疏性”。因此,如果特征量很大,数据维度很高,我们会倾向于使用L1正则化。由于L1正则化的这个性质,逻辑回归的特征选择可以由Embedded嵌入法来完成。 相对的,L2正则化在加强的过程中,会尽量让每个特征对模型都有一些小的贡献,但携带信息少,对模型贡献不大的特征的参数会非常接近于0。 通常来说,如果我们的主要目的只是为了防止过拟合,选择L2正则化就足够了。但是如果选择L2正则化后还是过拟合,模型在未知数据集上的效果表现很差,就可以考虑L1正则化。 而两种正则化下C的取值,都可以通过学习曲线来进行调整。
LogisticRegression(
["penalty='l2'", 'dual=False', 'tol=0.0001', 'C=1.0', 'fit_intercept=True', 'intercept_scaling=1', 'class_weight=None', 'random_state=None', "solver='warn'", 'max_iter=100', "multi_class='warn'", 'verbose=0', 'warm_start=False', 'n_jobs=None'],
)
# penalty:可以输入"l1"或"l2"来指定使用哪一种正则化方式,不填写默认"l2"。
# 注意,若选择"l1"正则化,参数solver仅能够使用求解方式”liblinear"和"saga“;若使用“l2”正则化,参数solver中所有的求解方式都可以使用。
# C:C正则化强度的倒数,必须是一个大于0的浮点数,不填写默认1.0,即默认损失函数与正则项的比值是1:1。C越小,损失函数会越小,模型对损失函数的惩罚越重,正则化的效力越强,参数θ会逐渐被压缩得越来越小。
from sklearn.linear_model import LogisticRegression as LR
from sklearn.datasets import load_breast_cancer
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
data = load_breast_cancer()
X = data.data
y = data.target
X.shape
---
(569, 30)
lrl1 = LR(penalty="l1",solver="liblinear",C=0.5,max_iter=1000)
lrl2 = LR(penalty="l2",solver="liblinear",C=0.5,max_iter=1000)
lrl1 = lrl1.fit(X,y)
lrl1.coef_ # 各个特征所对应的参数
# 注意返回的是二维array
---
array([[ 3.98754228, 0.03153078, -0.13532423, -0.01620142, 0. ,
0. , 0. , 0. , 0. , 0. ,
0. , 0.50383838, 0. , -0.07126945, 0. ,
0. , 0. , 0. , 0. , 0. ,
0. , -0.24537614, -0.12838236, -0.01442535, 0. ,
0. , -2.0550076 , 0. , 0. , 0. ]])
(lrl1.coef_ != 0).sum() # l1正则化可能会把部分特征系数压缩成0
---
10
lrl2 = lrl2.fit(X,y)
lrl2.coef_
---
array([[ 1.60607308e+00, 9.80640554e-02, 5.51538489e-02,
-4.80814634e-03, -9.75651764e-02, -2.97883054e-01,
-4.58633029e-01, -2.27937385e-01, -1.40149921e-01,
……
-4.37780410e-01, -4.31445382e-01, -8.46315361e-02]])
(lrl2.coef_ != 0).sum()
---
30
可以看见,当我们选择L1正则化的时候,许多特征的参数都被设置为了0,这些特征在真正建模的时候,就不会出现在我们的模型当中了,而L2正则化则是对所有的特征都给出了参数。
究竟哪个正则化的效果更好呢
l1 = []
l2 = []
l1test = []
l2test = []
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=420)
for i in np.linspace(0.05,2,19):
lrl1 = LR(penalty="l1",solver="liblinear",C=i,max_iter=1000) # 也有random_state
lrl2 = LR(penalty="l2",solver="liblinear",C=i,max_iter=1000)
lrl1 = lrl1.fit(Xtrain,Ytrain)
l1.append(accuracy_score(lrl1.predict(Xtrain),Ytrain))
l1test.append(accuracy_score(lrl1.predict(Xtest),Ytest))
lrl2 = lrl2.fit(Xtrain,Ytrain)
l2.append(accuracy_score(lrl2.predict(Xtrain),Ytrain))
l2test.append(accuracy_score(lrl2.predict(Xtest),Ytest))
graph = [l1,l2,l1test,l2test]
color = ['green','k','lightgreen','gray']
label = ['L1','L2','L1test','L2test']
plt.figure(figsize=(6,6))
for i in range(len(graph)):
plt.plot(np.linspace(0.05,2,19),graph[i],color[i],label=label[i])
plt.legend(loc='lower right') # 也可以写plt.legend(loc=4)
plt.xlabel('Parameter C')
plt.show()
可见,至少在乳腺癌数据集下,两种正则化的结果区别不大。但随着C的逐渐变大,正则化的强度越来越小,模型在训练集和测试集上的表现都呈上升趋势,直到C=0.8左右,训练集上的表现依然在走高,但模型在未知数据集上的表现开始下跌,这时候就是出现了过拟合。我们可以认为,C设定为0.8会比较好。 在实际使用时,基本就默认使用l2正则化,如果感觉到模型的效果不好,那就换L1试试看。
标签:plt,菜菜,L2,penalty,正则,参数,L1,theta,sklearn From: https://blog.51cto.com/u_15767241/5923514这里说一下matplotlib相关的
# 在我们show之前,所有画图都在同一个画布上 # 当我们show之后,再进行画图,不会再之前的画布上 # 如果在show之后有创建新画布则用创建的画布 # 如果没有,默认创建画布(这么做不规范,画布没有任何设置,主要不好理解) plt.figure(figsize=(3,2)) # 就像本例,我们设置画布figsize=(3,2) for i in range(2): plt.plot(np.linspace(0.05,1,19),graph[i],color[i],label=label[i]) plt.legend(loc='lower right') # 也可以写plt.legend(loc=4) plt.show() # 第一次show的时候figsize=(3,2)被用掉了,新的画图就要默认用创建画布