逻辑斯蒂回归

{% if theme.baidu_push %} {% endif %}

逻辑斯蒂回归

逻辑回归

在之前的课程中我们已经学习接触过相关的回归模型了,我们知道回归模型是用来处理和预测连续型标签的算法。然而逻辑回归,是一种名为“回归”的线性分类器,其本质是由线性回归变化而来的,一种广泛使用于分类问题中的广义回归算法。要理解逻辑回归从何而来,得要先理解线性回归。线性回归是机器学习中最简单的的回归算法,它写作一个几乎人人熟悉的方程(为了更好理解本节后面的讲解到的sigmod函数,下面的回归函数用z来表示):
img

其中𝛉0被称为截距(intercept), 𝛉1~𝛉n 被称为系数(coefficient),这个表达式,其实就和我们中学时就无比熟悉的y=ax+b是同样的性质。我们可以使用矩阵来表示这个方程,其中x和𝛉都可以被看做是一个列矩阵,则有:
img

通过上图函数z,线性回归使用输入的特征矩阵X来输出一组连续型的标签值y_pred,以完成各种预测连续型变量的任务 (比如预测产品销量,预测股价等等)。
那如果我们的标签是离散型变量,尤其是,如果是满足0-1分布的离散型变量,我们要怎么办呢?
可以使用逻辑回归这个回归模型,如果需要实现分类效果使用sigmod函数
img

  • 函数解释:
    • Sigmoid函数是一个S型的函数,当自变量z趋近正无穷时,因变量g(z)趋近于1,而当z趋近负无穷时,g(z)趋近于0,它能够将任何实数(非0和1的标签数据)映射到(0,1)区间,使其可用于将任意值函数转换为更适合二分类的函数。 因为这个性质,Sigmoid函数也被当作是归一化的一种方法,与我们之前学过的MinMaxSclaer同理,是属于数据预处理中的“缩放”功能,可以将数据压缩到[0,1]之内。区别在于,MinMaxScaler归一化之后,是可以取到0和1的(最大值归一化后就是1,最小值归一化后就是0),但Sigmoid函数只是无限趋近于0和1。
      img
  • 简单来说:
    • 逻辑回归就是使用simoid函数将线性方程返回的结果(线性回归模型预测出来的结果)压缩到0-1之间,从而实现的二分类的任务!
    • 逻辑回归 == (线性回归+sigmiod函数)
  • 总之
    1. 逻辑回归就是线性回归+sigmoid函数,在逻辑回归里是有着求解权重系数w的需求。
    2. sigmoid函数返回的结果就是样本分到某一个类别的概率。

损失函数

  • 在逻辑回归分类的时候,不管原始样本中的类别使用怎样的值或者文字表示,逻辑回归统一将其视为0类别和1类别。
  • 因为逻辑回归也采用了寻找特征和目标之间的某种关系,则每个特征也是有权重的就是w,那么也会存在真实值和预测值之间的误差(损失函数),那么逻辑回归的损失函数和线性回归的损失函数是否一样呢?
    • 由于逻辑回归是用于分类的,因此该损失函数和线性回归的损失函数是不一样的!逻辑回归采用的损失函数是:对数似然损失函数:
  • 注意:没有求解参数需求的模型是没有损失函数的,比如KNN,决策树。
  • 损失函数被写作如下:
    • 为什么使用-log函数为损失函数,损失函数的本质就是,如果我们预测对了,则没有损失,反之则损失需要变的很大,而-log函数在【0,1】之间正好符合这一点(-log可以放大损失)。
      • -log(h)表示分类到正例1的损失
      • -log(1-h)表示分类到反例0的损失
    • 损失函数表征预测值与真实值之间的差异程度,如果预测值与真实值越接近则损失函数应该越小
      img

解释:

  • yilog(h)表示分类到真实标签的正例的损失,根据-log函数得知如果分类正确则损失值小,反之损失大

  • -(1-yi)log(1-h)表示分类到真实标签反例的损失,根据-log函数得知如果分类正确则损失小,反之损失大

  • 那么两者相加就获得了逻辑回归模型总分类结果的损失!

  • 将逻辑回归对应的预测结果带入损失函数:
    img

    梯度下降

    • 逻辑回归的数学目的是求解能够让模型最优化,拟合程度最好的参数𝛉的值,即求解能够让损失函数J(𝛉)最小化的𝛉值。
    • 梯度下降原理介绍:
      • 假设现在有一个带两个特征并且没有截距的逻辑回归y(x1,x2),两个特征所对应的参数分别为[𝛉1,𝛉2]。下面这个华丽的平面就是我们的损失函数 J(𝛉1,𝛉2)在以𝛉1,𝛉2和J为坐标轴的三维立体坐标系上的图像。现在,我们寻求的是损失函数的最小值,也就是图像的最低点。
        show
  • 那我们怎么做呢?我在这个图像上随机放一个小球,当我松手,这个小球就会顺着这个华丽的平面滚落,直到滚到深蓝色的区域——损失函数的最低点。为了严格监控这个小球的行为,我让小球每次滚动的距离有限,不让他一次性滚到最低点,并且最多只允许它滚动100步,还要记下它每次滚动的方向,直到它滚到图像上的最低点。

  • 可以看见,小球从高处滑落,在深蓝色的区域中来回震荡,最终停留在了图像凹陷处的某个点上。非常明显,我们可以观察到几个现象:

    • 首先,小球并不是一开始就直向着最低点去的,它先一口气冲到了蓝色区域边缘,后来又折回来,我们已经规定了小球是多次滚动,所以可见,小球每次滚动的方向都是不同的。
    • 另外,小球在进入深蓝色区域后,并没有直接找到某个点,而是在深蓝色区域中来回震荡了数次才停下。停下来有两种可能:
      • 1、 小球已经滚到了图像的最低点,所以停下了,
      • 2、 由于我设定的步数限制,小球还没有找到最低点,但也只好在100步的时候停下了。也就是说,小球不一定滚到了图像的最低处。
    • 但无论如何,小球停下的就是我们在现有状况下可以获得的唯一点了。如果我们够幸运,这个点就是图像的最低点,那我们只要找到这个点的对应坐标(𝛉1,𝛉2,J),就可以获取能够让损失函数最小的参数取值[𝛉1,𝛉2]了。如此,梯度下降的过程就已经完成。
  • 在这个过程中,小球其实就是一组组的坐标点(𝛉1,𝛉2,J);小球每次滚动的方向就是那一个坐标点的梯度向量的方向,因为每滚动一步,小球所在的位置都发生变化,坐标点和坐标点对应的梯度向量都发生了变化,所以每次滚动的方向也都不一样;人为设置的100次滚动限制,就是sklearn中逻辑回归的参数max_iter,代表着能走的最大步数.

    • 所以梯度下降,其实就是在众多[𝛉1,𝛉2]可能的值中遍历,一次次求解坐标点的梯度向量,不断让损失函数的取值J逐渐逼近最小值,再返回这个最小值对应的参数取值[𝛉1,𝛉2]的过程。

正则化

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

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

  • 我们知道损失函数的损失值越小(在训练集中预测值和真实值越接近)则逻辑回归模型就越有可能发生过拟合(模型只在训练集中表现的好,在测试集表现的不好)的现象。通过正则化的L1和L2范式可以加入惩罚项C来矫正模型的拟合度。因为C越小则损失函数会越大表示正则化的效力越强,参数𝛉会被逐渐压缩的越来越小。

    • 注意:L1正则化会将参数w压缩为0,L2正则化只会让参数尽量小,不会取到0。原因解释会涉及到坐标下降法和求导相关,故作不解释,只需要记住结论即可!
  • L1和L2范式的区别

    • 在L1正则化在逐渐加强的过程中,携带信息量小的、对模型贡献不大的特征的参数w,会比携带大量信息的、对模型有巨大贡献的特征的参数更快地变成0,所以L1正则化本质是一个特征选择的过程。L1正则化越强,参数向量中就越多的参数为0,选出来的特征就越少,以此来防止过拟合。因此,如果特征量很大,数据维度很高,我们会倾向于使用L1正则化。
    • L2正则化在加强的过程中,会尽量让每个特征对模型都有一些小的贡献,但携带信息少,对模型贡献不大的特征的参数w会非常接近于0。通常来说,如果我们的主要目的只是为了防止过拟合,选择L2正则化就足够了。但是如果选择L2正则化后还是过拟合,模型在未知数据集上的效果表现很差,就可以考虑L1正则化。

逻辑回归API

  • from sklearn.linear_model import LogisticRegression
  • 超参数介绍:
    • penalty:
      • 可以输入l1或者l2来指定使用哪一种正则化方式。不填写默认"l2"。 注意,若选择"l1"正则化,参数solver仅能够使用求解方式”liblinear"和"saga“,若使用“l2”正则 化,参数solver中所有的求解方式都可以使用。
    • C:
      • 惩罚项。C越小,损失函数会越大,模型对损失函数的惩罚越重,正则化的效力越强,参数会逐渐被压缩得越来越小。
    • max_iter:
      • 梯度下降中能走的最大步数,默认值为100.步数的不同取值可以帮助我们获取不同的损失函数的损失值。目前没有好的办法可以计算出最优的max_iter的值,一般是通过绘制学习曲线对其进行取值。
    • solver:
      • 我们之前提到的梯度下降法,只是求解逻辑回归参数𝛉的一种方法。sklearn为我们提供了多种选择,让我们可以使用不同的求解器来计算逻辑回归。求解器的选择,由参数"solver"控制,共有五种选择。
        • liblinear:是二分类专用(梯度下降),也是现在的默认求解器。
        • lbfgs,newton-cg,sag,saga:是多分类专用,几乎不用。
          img
      • multi_class:
    • 输入"ovr", “multinomial”, “auto"来告知模型,我们要处理的分类问题的类型。默认是"ovr”。
      • ‘ovr’:表示分类问题是二分类,或让模型使用"一对多"的形式来处理多分类问题。
      • ‘multinomial’:表示处理多分类问题,这种输入在参数solver是’liblinear’时不可用。
      • “auto”:表示会根据数据的分类情况和其他参数来确定模型要处理的分类问题的类型。比如说,如果数据是二分 类,或者solver的取值为"liblinear",“auto"会默认选择"ovr”。反之,则会选择"multinomial"。
    • class_weight:
      • 表示样本不平衡处理的参数。样本不平衡指的是在一组数据中,某一类标签天生占有很大的比例,或误分类的代价很高,即我们想要捕捉出某种特定的分类的时候的状况。什么情况下误分类的代价很高?
        • 例如,我们现在要对潜在犯罪者和普通人进行分类,如果没有能够识别出潜在犯罪者,那么这些人就可能去危害社会,造成犯罪,识别失败的代价会非常高,但如果,我们将普通人错误地识别成了潜在犯罪者,代价却相对较小。所以我们宁愿将普通人分类为潜在犯罪者后再人工甄别,但是却不愿将潜在犯罪者 分类为普通人,有种"宁愿错杀不能放过"的感觉。
        • 再比如说,在银行要判断“一个新客户是否会违约”,通常不违约的人vs违约的人会是99:1的比例,真正违约的人其实是非常少的。这种分类状况下,即便模型什么也不做,全把所有人都当成不会违约的人,正确率也能有99%, 这使得模型评估指标变得毫无意义,根本无法达到我们的“要识别出会违约的人”的建模目的。
      • None:
        • 因此我们要使用参数class_weight对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少数类, 向捕获少数类的方向建模。该参数默认None,此模式表示自动给与数据集中的所有标签相同的权重,即自动1: 1。
      • balanced:
        • 当误分类的代价很高的时候,我们使用”balanced“模式,可以解决样本不均衡问题。

示例

乳腺癌数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn.model_selection import train_test_split

data = datasets.load_breast_cancer()
feature = data.data
target = data.target

x_train,x_test,y_train,y_test = train_test_split(feature,target,test_size=0.2,random_state=2020)

model = LogisticRegression(penalty='l2',C=0.1,max_iter=100,
solver='liblinear',multi_class='auto',
class_weight=None)


model.fit(x_train,y_train)

model.score(x_test,y_test)

0.9649122807017544

1
2
3
#模型进行样本分类
sample = x_test[6]
model.predict([sample])
1
2
#计算分类概率
model.predict_proba([sample])

array([[9.99999894e-01, 1.05694979e-07]])

  • 用网格搜索调整参数
    - Grid Search:一种调参手段;穷举搜索:在所有候选的参数选择中,通过循环遍历,尝试每一种可能性,表现最好的参数就是最终的结果。其原理就像是在数组里找最大值。(为什么叫网格搜索?以有两个参数的模型为例,参数a有3种可能,参数b有4种可能,把所有可能性列出来,可以表示成一个3*4的表格,其中每个cell就是一个网格,循环过程就像是在每个网格里遍历、搜索,所以叫grid search)
    img
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from sklearn.model_selection import GridSearchCV #网格搜索
#定义一个字典:存放的就是不同的超参数的取值
params = {
'penalty':('l1','l2'),
'C':(0.1,0.3,0.5,0.7,0.9,1.0),
'max_iter':(100,300,600,800,1000,2000,3000),
}

model = LogisticRegression(solver='liblinear')

#创建网格搜索的工具对象
tool = GridSearchCV(model,params,cv=5)
#使用工具对象找寻模型最优超参数
tool.fit(x_train,y_train)
1
2
#显示最优的模型超参数
tool.best_params_

{‘C’: 1.0, ‘max_iter’: 2000, ‘penalty’: ‘l1’}

1
2
#基于交叉验证找寻到最优的模型超参数测试模型结果为如下分数
tool.best_score_

0.956043956043956