写点什么

《菜菜的机器学习 sklearn 课堂》逻辑回归,java 教程百度云最新版

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:4318 字

    阅读完需:约 14 分钟

虽然我们熟悉的逻辑回归通常被用于处理二分类问题,但逻辑回归也可以做多分类。


sklearn 中的逻辑回归




| 逻辑回归相关的类 | 说明 |


| --- | --- |


| linear_model.LogisticRegression | 逻辑回归分类器(又叫 logit 回归,最大熵分类器) |


| linear_model.LogisticRegressionCV | 带交叉验证的逻辑回归分类器 |


| linear_model.logistic_regression_path | 计算 Logistic 回归模型以获得正则化参数的列表 |


| linear_model.SGDClassifier | 利用梯度下降求解的线性分类器(SVM,逻辑回归等等) |


| linear_model.SGDRegressor | 利用梯度下降最小化正则化后的损失函数的线性回归模型 |


| metrics.log_loss | 对数损失,又称逻辑损失或交叉熵损失 |


| 【 在 sklearn0.21 版本中即将被移除】 | |


| --- | --- |


| linear_model.RandomizedLogisticRegression | 随机的逻辑回归 |


| 其他会涉及的类 | 说明 |


| --- | --- |


| metrics.confusion_matrix | 混淆矩阵,模型评估指标之一 |


| metrics.roc_auc_score | ROC 曲线,模型评估指标之一 |


| metrics.accuracy_score | 精确性,模型评估指标之一 |


linear_model.LogisticRegression


===================================================================================================


class sklearn.linear_model.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


)


二元逻辑回归的损失函数



损失函数的概念与解惑

在学习决策树和随机森林时,我们曾经提到过两种模型表现:


  • 训练集上的表现

  • 测试集上的表现


我们建模是追求模型在测试集上的表现最优,因此模型的评估指标往往是用来衡量模型在测试集上的表现的。


然而,逻辑回归有着基于训练数据求解参数 θ \theta θ的需求,并且希望训练出来的模型能够尽可能地拟合训练数据,即模型在训练集上的预测准确率越靠近 100%越好。


因此,我们使用"损失函数"这个评估指标,来衡量参数为θ的模型拟合训练集时产生的信息损失的大小,并以此衡量参数θ的优劣。如果用一组参数建模后,


  • 模型在训练集上表现良好


那我们就说模型拟合过程中的损失很小,损失函数的值很小,这一组参数就优秀


  • 模型在训练集上表现糟糕


损失函数就会很大,模型就训练不足,效果较差,这一组参数也就比较差


即是说,我们在求解参数 θ \theta θ时,追求损失函数最小,让模型在训练数据上的拟合效果最优,即预测准确率尽量靠近 100%。


关键概念:损失函数


衡量参数 θ \theta θ的优劣的评估指标,用来求解最优参数的工具


损失函数小,模型在训练集上表现优异,拟合充分,参数优秀


损失函数大,模型在训练集上表现差劲,拟合不足,参数糟糕


我们追求:能够让损失函数最小化的参数组合



注意:没有"求解参数"需求的模型没有损失函数,比如 KNN,决策树


逻辑回归的损失函数是由极大似然估计推导出来的,具体结果可以写作:


J ( θ ) = ? ∑ i = 1 m ( y i ? l o g ( y θ ( x i ) ) + ( 1 ? y i ) ? l o g ( 1 ? y θ ( x i ) ) ) ) J(\theta) = - \sum _{i=1} ^m (y_i * log(y_\theta(x_i)) + (1-y_i) * log(1-y_\theta(x_i)))) J(θ)=?i=1∑m?(yi??log(yθ?(xi?))+(1?yi?)?log(1?yθ?(xi?))))


其中, θ \theta θ表示求解出来的一组参数,m 是样本的个数, y i y_i yi?是样本 i 上真实的标签, y θ ( x i ) y_\theta(x_i) yθ?(xi?)是样本 i 上,基于参数 θ \theta θ计算出来的逻辑回归返回值, x i x_i xi?是样本 i 各个特征的取值。我们的目标就是求解出使 J ( θ ) J(\theta) J(θ)最小的 θ \theta θ取值。


注意,在逻辑回归的本质函数 y(x)里,特征矩阵 x 是自变量,参数是 θ \theta θ。但在损失函数中,参数 θ \theta θ是损失函数的自变量,x 和 y 都是已知的特征矩阵和标签,相当于是损失函数的参数。不同的函数中,自变量和参数各有不同,因此大家需要在数学计算中,尤其是求导的时候避免混淆。


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


重要参数 penalty & C



正则化(L1、L2)

正则化是用来防止模型过拟合的过程,常用的有 L1 正则化和 L2 正则化两种选项,分别通过在损失函数后加上参数向量 θ \theta θ的 L1 范式和 L2 范式的倍数来实现,这个增加的范式,被称为"正则项",也被称为"惩罚项"。


损失函数改变,基于损失函数的最优化来求解的参数取值必然改变,我们以此来调节模型拟合的程度


  • L1 范式表现为参数向量中的每个参数的绝对值之和


J ( θ ) L 1 = C ? J ( θ ) + ∑ j = 1 n ∣ θ j ∣ ( j ≥ 1 ) J(\theta)_{L1} = C * J(\theta) + \sum_{j=1}^{n} |\theta_j | (j \ge 1) J(θ)L1?=C?J(θ)+j=1∑n?∣θj?∣(j≥1)


  • L2 范数表现为参数向量中的每个参数的平方和的开方值。


J ( θ ) L 2 = C ? J ( θ ) + ∑ j = 1 n ( θ j ) 2 ( j ≥ 1 ) J(\theta)_{L2} = C * J(\theta) + \sqrt{\sum_{j=1}^n(\theta_j)^2}(j \ge 1) J(θ)L2?=C?J(θ)+j=1∑n?(θj?)2 ?(j≥1)


  • J ( θ ) J(\theta) J(θ) - 损失函数

  • C - 用来控制正则化程度的超参数

  • n - 方程中特征的总数,也是方程中参数的总数

  • j - 每个参数


在这里 j 要大于等于 1,因为我们的参数向量 θ \theta θ中,第一个参数是 θ 0 \theta_0 θ0?是截距,它通常不参与正则化。


在许多书籍和博客中,大家可能也会见到如下的写法:



其实和我们上面的式子的本质是一模一样的。不过在大多数教材和博客中,常数项是乘以正则项,通过调控正则项来调节对模型的惩罚。而 sklearn 当中,常数项 C 是在损失函数的前面,通过调控损失函数本身的大小,来调节对模型的惩罚。


参数:


  • penalty


可以输入"l1""l2"指定使用哪一种正则化方式,不填写默认 "l2"


若选择"l1"正则化,参数solver仅能够使用求解方式"liblinear""saga"


若使用"l2"正则化,参数solver中所有的求解方式都可以使用


  • C


C 是正则化强度的倒数,必须是一个大于 0 的浮点数,不填写默认 1.0,即默认正则项与损失函数的比值是 1:1。C 越小,损失函数会越小,模型对损失函数的惩罚越重,正则化的效力越强,参数会逐渐被压缩得越来越小。


L1 正则化和 L2 正则化虽然都可以控制过拟合,但它们的效果并不相同。当正则化强度逐渐增大(即 C 逐渐变小),参数 θ \theta θ的取值会逐渐变小:


  • L1 正则化会将参数压缩为 0

  • L2 正则化只会让参数尽量小,不会取到 0


在 L1 正则化在逐渐加强的过程中,携带信息量小的


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


、对模型贡献不大的特征的参数,会比携带大量信息的、对模型有巨大贡献的特征的参数更快地变成 0,所以 L1 正则化本质是一个特征选择的过程,掌管了参数的“稀疏性”。L1 正则化越强,参数向量中就越多的参数为 0,参数就越稀疏,选出来的特征就越少,以此来防止过拟合。因此,如果特征量很大,数据维度很高,我们会倾向于使用 L1 正则化。由于 L1 正则化的这个性质,逻辑回归的特征选择可以由 Embedded 嵌入法来完成。


相对的,L2 正则化在加强的过程中,会尽量让每个特征对模型都有一些小的贡献,但携带信息少,对模型贡献不大的特征的参数会非常接近于 0。通常来说,如果我们的主要目的只是为了防止过拟合,选择 L2 正则化就足够了。但是如果选择 L2 正则化后还是过拟合,模型在未知数据集上的效果表现很差,就可以考虑 L1 正则化。


两种正则化下 C 的取值,都可以通过学习曲线来进行调整。


建立两个逻辑回归,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


data.data.shape #569 个样本,30 个特征


lrl1 = LR(penalty="l1",solver="liblinear",C=0.5,max_iter=1000) #l1 范式正则化


lrl2 = LR(penalty="l2",solver="liblinear",C=0.5,max_iter=1000) #l2 范式正则化


#逻辑回归的重要属性 coef_(θ),查看每个特征所对应的参数


lrl1 = lrl1.fit(X,y)


lrl1.coef_ # l1 正则化会让参数为 0


(lrl1.coef_ != 0).sum(axis=1)


lrl2 = lrl2.fit(X,y)


lrl2.coef_ # l2 正则化不会让参数为 0


可以看见,当我们选择 L1 正则化的时候,许多特征的参数都被设置为了 0,这些特征在真正建模的时候,就不会出现在我们的模型当中了,而 L2 正则化则是对所有的特征都给出了参数


究竟哪个正则化的效果更好呢?还是都差不多?


np.linspace(0.05, 1, 19) #从 0.05 开始到 1,取出 19 个数字


l1 = []


l2 = []


l1test = []


l2test = []

30%数据用于测试,70%用于训练,420 是随便输的数

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) # l1 正则化


lrl2 = LR(penalty="l2",solver="liblinear",C=i,max_iter=1000) # l2 正则化


lrl1 = lrl1.fit(Xtrain,Ytrain)


l1.append(accuracy_score(lrl1.predict(Xtrain),Ytrain))


l1test.append(accuracy_score(lrl1.predict(Xtest),Ytest)) # lrl1.score(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) #标签名的位置在哪里? 4 表示:右下角


plt.show()



可见,至少在我们的乳腺癌数据集下,两种正则化的结果区别不大。但随着 C 的逐渐变大,正则化的强度越来越小,模型在训练集和测试集上的表现都呈上升趋势,直到 C=0.8 左右,训练集上的表现依然在走高,但模型在未知数据集上的表现开始下跌,这时候就是出现了过拟合。我们可以认为,C 设定为 0.8 会比较好。


实际使用时,基本就默认使用 l2 正则化,如果感觉到模型的效果不好,那就换 L1 试试看


附录


=====================================================================

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
《菜菜的机器学习sklearn课堂》逻辑回归,java教程百度云最新版