sklearn逻辑回归中损失函数与正则化

在随机森林和决策树中,存在两种模型表现:训练集上和测试集上的表现。在建模过程中,追求模型在测试集上表现最优,因此模型的评价指标往往是用来衡量模型在测试集上的表现。然而逻辑回归有着基于训练数据求解参数的需求,并且希望训练出来的模型能够尽可能的拟合训练数据,即模型在训练集上的预测准确率越靠近100%越好。
因此使用“损失函数”这个评估指标,来衡量参数的优劣,即这一参数能否是模型在训练集上表现优异。
如果用一组参数建模后,模型在训练集上表现良好,那我们就说模型表现的规律与训练集数据的规律一致,拟合过程中的损失很小,损失函数的值很小,这一组参数就优秀;相反,如果模型在训练集上表现糟糕,损失函数就会很 大,模型就训练不足,效果较差,这一组参数也就比较差。即是说,我们在求解参数时,追求损失函数小,让 模型在训练数据上的拟合效果优,即预测准确率尽量靠近100%。

损失函数

衡量参数的优劣的评估指标,用来求解最优参数的工具。
损失函数小,模型在训练集上表现优异,拟合充足,参数优秀。
损失函数大,模型在训练集上表现差劲,拟合不足,参数糟糕。
我们追求,能够让损失函数最小化的参数组合。
没有“求解参数”需求的模型没有损失函数,比如KNN、决策树。

如果我们追求损失函数的最小值,让模型在训练集上表现最优,可能会引发一个问题:如果模型在训练集上表现优秀,却在测试集上表现糟糕,这就是我们常说的过拟合。虽然逻辑回归和线性回归是天生欠拟合的模型,但我们还是需要控制过拟合的技术来调整模型。
对逻辑回归中的过拟合控制,通过正则化来实现。

正则化

正则化是用来防止模型过拟合的过程,常用的有L1正则化和L2正则化两种选项。分别通过在损失函数后加上参数向量的L1范式和L2范式的倍数来实现。这个增加的范式,被称为“正则项”,也被称为"惩罚项"。损失函数改变,基于损失函数的优化来求解的参数取值必然改变,我们以此来调节模型拟合的程度。其中L1范数表现为参数向量中的每个参数的绝对值之和,L2范数表现为参数向量中的每个参数的平方和的开方值。

参数 说明
penalty 可以输入“l1”,“l2” 两种,默认l2。在l1中,参数solver仅能使用“liblinear”。
C C正则化强度的倒数,必须是一个大于0的浮点数,不填写默认1.0,即默认一倍正则项。 C越小,对损失函数的惩罚越重,正则化的效力越强,参数 会逐渐被压缩得越来越小。在很多书 籍和博客的原理讲解中, 被写作 ,为了大家便于理解sklearn中的参数,我将公式改写成 , 更加直观。

L1正则化和L2正则化虽然都可以控制过拟合,但它们的效果并不相同。当正则化强度逐渐增大(即C逐渐变小), 参数 的取值会逐渐变小,但L1正则化会将参数压缩为0,L2正则化只会让参数尽量小,不会取到0。
如果特征量很大,数据维度很高,倾向于使用L1正则化。
如果目的只是为了防止过拟合,选择L2就足够了。
还是要在具体情况下进行使用。

建立两个逻辑回归,观察L1和L2的差别

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

lrl1 = LR(penalty="l1", solver="liblinear", C=0.5, max_iter=1000)

lrl2 = LR(penalty="l2", solver="liblinear", C=0.5, max_iter=1000)

# 逻辑回归的重要属性coef_,查看每个特征所对应的参数 lrl1 = lrl1.fit(X,y) lrl1.coef_

lrl1 = lrl1.fit(X, y)

print(lrl1.coef_)
print((lrl1.coef_ != 0).sum(axis=1))  # 实现降维,系数为0的被压缩,成为一维数组

lrl2 = lrl2.fit(X, y)

print(lrl2.coef_)
print((lrl2.coef_ != 0).sum(axis=1))

在选择L1时许多参数变成了0,不会出现在建模中。# 10
L2是所有特征都给出了参数。 #30

继续观察哪个正则化效果最佳,或者相同:
代码实现:

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

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, 1, 19):
    lrl1 = LR(penalty="l1", solver="liblinear", C=i, max_iter=1000)
    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", "black", "lightgreen", "gray"]
label = ["L1", "L2", "L1test", "L2test"]

plt.figure(figsize=(6, 6))
for i in range(len(graph)):
    plt.plot(np.linspace(0.05, 1, 19), graph[i], color[i], label=label[i])
plt.legend(loc=4) 
plt.show()

运行结果:
在这里插入图片描述
随着C的逐渐变大,正则化的强度越来越小,模型在训练集和测试集上的表现都呈上升趋势,直到C=0.8左右,训练集上的表现依然在走高,但模型在未知数据集上的表现开始下跌,这时候就是出现了过拟合。我们可以认为,C设定为0.9会比较好。在实际使用时,基本就默认使用l2正则化,如果感觉到模型的效果不好,那就换L1试试。

发布了90 篇原创文章 · 获赞 15 · 访问量 3171

猜你喜欢

转载自blog.csdn.net/qq_43656233/article/details/104076273