1. 名为“回归”的分类器–逻辑回归
概述
逻辑回归,是一种名为“回归”的线性分类器,其本质是由线性回归变化而来的,一种广泛使用于分类问题中的广义回归算法。要理解逻辑回归从何而来,得要先理解线性回归。线性回归是机器学习中最简单的的回归算法,它写作一个几乎人人熟悉的方程
z
=
θ
0
+
θ
1
x
1
+
.
.
.
+
θ
n
x
n
z=\theta_0+\theta_1x_1+...+\theta_nx_n
z=θ0+θ1x1+...+θnxn
也可以用矩阵来表示这个方程
z
=
[
θ
0
,
θ
1
,
θ
2
,
.
.
.
,
θ
n
]
∗
[
x
0
x
1
.
.
.
x
n
]
=
θ
T
x
z=[θ_0,θ_1,θ_2,...,θ_n]*\begin{bmatrix} x_0\\ x_1 \\ ...\\ x_n \end{bmatrix}=\theta^Tx
z=[θ0,θ1,θ2,...,θn]∗⎣⎢⎢⎡x0x1...xn⎦⎥⎥⎤=θTx
线性回归的任务,就是构造一个预测函数
z
z
z来映射输入的特征矩阵x和标签值y的线性关系,而构造预测函数的核心就是找出模型的参数:
θ
T
\theta^T
θT和
θ
0
\theta_0
θ0 ,著名的最小二乘法就是用来求解线性回归中参数的数学方法。
如果是满足0-1分布的离散型变量,我们可以通过引入联系函数(link function),将线性回归方程z变换为g(z),并且令g(z)的值分布在(0,1)之间,且当g(z)接近0时样本的标签为类别0,当g(z)接近1时样本的标签为类别1,这样就得到了一个分类模型。而这个联系函数对于逻辑回归来说,就是Sigmoid函数:
g
(
z
)
=
1
1
+
e
−
z
g(z)=\frac{1}{1+e^{-z}}
g(z)=1+e−z1
Sigmoid函数是一个S型的函数,当自变量z趋近正无穷时,因变量g(z)趋近于1,而当z趋近负无穷时,g(z)趋近于0,它能够将任何实数映射到(0,1)区间,使其可用于将任意值函数转换为更适合二分类的函数。因为这个性质,Sigmoid函数也被当作是归一化的一种方法,与我们之前学过的MinMaxSclaer同理,是属于数据预处理中的“缩放”功能,可以将数据压缩到[0,1]之内。区别在于,MinMaxScaler归一化之后,是可以取到0和1的(最大值归一化后就是1,最小值归一化后就是0),但Sigmoid函数只是无限趋近于0和1。
线性回归中
z
=
θ
T
x
z=\theta^Tx
z=θTx,我们将
z
z
z带入,就得到二元逻辑回归模型的一般形式:
g
(
x
)
=
y
(
x
)
=
1
1
+
e
−
θ
T
x
g(x)=y(x)=\frac{1}{1+e^{-\theta^Tx}}
g(x)=y(x)=1+e−θTx1
而
y
(
x
)
y(x)
y(x) 就是我们逻辑回归返回的标签值。此时,
y
(
x
)
y(x)
y(x) 的取值都在[0,1]之间,因此
y
(
x
)
y(x)
y(x) 和
1
−
y
(
x
)
1-y(x)
1−y(x)相加必然为1。如果我们令
y
(
x
)
y(x)
y(x)除以
1
−
y
(
x
)
1-y(x)
1−y(x) 可以得到形似几率(odds)的一种表达,即
y
(
x
)
1
−
y
(
x
)
\frac{y(x)}{1-y(x)}
1−y(x)y(x) ,在此基础上取对数,可以很容易就得到:
l
n
y
(
x
)
1
−
y
(
x
)
=
l
n
(
1
1
+
e
−
θ
T
x
1
−
1
1
+
e
−
θ
T
x
)
=
l
n
(
1
1
+
e
−
θ
T
x
e
−
θ
T
x
1
+
e
−
θ
T
x
)
=
l
n
(
1
e
−
θ
T
x
)
=
l
n
(
e
θ
T
x
)
=
θ
T
x
\begin{aligned} ln\frac{y(x)}{1-y(x)} & = ln(\frac{\frac{1}{1+e^{-\theta^Tx}}}{1-\frac{1}{1+e^{-\theta^Tx}}})\\ & = ln(\frac{\frac{1}{1+e^{-\theta^Tx}}}{\frac{e^{-\theta^Tx}}{1+e^{-\theta^Tx}}}) \\ & = ln(\frac{1}{e^{-\theta^Tx}})\\ &=ln(e^{\theta^Tx})\\ &=\theta^Tx \end{aligned}
ln1−y(x)y(x)=ln(1−1+e−θTx11+e−θTx1)=ln(1+e−θTxe−θTx1+e−θTx1)=ln(e−θTx1)=ln(eθTx)=θTx
不难发现,
y
(
x
)
y(x)
y(x)的形似几率取对数的本质其实就是我们的线性回归
z
z
z,我们实际上是在对线性回归模型的预测结果取对数几率来让其的结果无限逼近0和1。因此,其对应的模型被称为”对数几率回归“(logistic Regression),也就是我们的逻辑回归,这个名为“回归”却是用来做分类工作的分类器。
线性回归的核心任务是通过求解
θ
\theta
θ构建
z
z
z这个预测函数,并希望预测函数
z
z
z能够尽量拟合数据,因此逻辑回归的核心任务也是类似的:求解
θ
\theta
θ来构建一个能够尽量拟合数据的预测函数
y
(
x
)
y(x)
y(x),并通过向预测函数中输入特征矩阵来获取相应的标签值
y
y
y。
为什么需要逻辑回归
线性回归对数据的要求很严格,比如标签必须满足正态分布,特征之间的多重共线性需要消除等等,而现实中很多真实情景的数据无法满足这些要求,因此线性回归在很多现实情境的应用效果有限。逻辑回归是由线性回归变化而来,因此它对数据也有很多要求。
而且,逻辑回归的原理其实并不简单。要理解逻辑回归,必须要有一定的数学基础,才能够对逻辑回归进行调优。况且,要计算概率,朴素贝叶斯可以计算出真正意义上的概率,要进行分类,机器学习中能够完成二分类功能的模型简直多如牛毛。因此,在数据挖掘,人工智能所涉及到的医疗,教育,人脸识别,语音识别这些领域,逻辑回归没有太多的出场机会。
但是,无论机器学习领域如何折腾,逻辑回归依然是一个受工业商业热爱,使用广泛的模型,因为它有着不可替代的优点:
- 逻辑回归对线性关系的拟合效果好到丧心病狂,特征与标签之间的线性关系极强的数据,比如金融领域中的信用卡欺诈,评分卡制作,电商中的营销预测等等相关的数据,都是逻辑回归的强项。虽然现在有了梯度提升树GDBT,比逻辑回归效果更好,也被许多数据咨询公司启用,但逻辑回归在金融领域,尤其是银行业中的统治地位依然不可动摇(相对的,逻辑回归在非线性数据的效果很多时候比瞎猜还不如,所以如果你已经知道数据之间的联系是非线性的,千万不要迷信逻辑回归)。
- 逻辑回归计算快:对于线性数据,逻辑回归的拟合和计算都非常快,计算效率优于SVM和随机森林,在大型数据上尤其能够看得出区别。
- 逻辑回归返回的分类结果不是固定的0,1,而是以小数形式呈现的类概率数字:我们因此可以把逻辑回归返回的结果当成连续型数据来利用。比如在评分卡制作时,我们不仅需要判断客户是否会违约,还需要给出确定的”信用分“,而这个信用分的计算就需要使用类概率计算出的对数几率,而决策树和随机森林这样的分类器,可以产出分类结果,却无法帮助我们计算分数(当然,在sklearn中,决策树也可以产生概率,使用接口predict_proba调用就好,但一般来说,正常的决策树没有这个功能)。
逻辑回归的本质是一个返回对数几率的,在线性数据上表现优异的分类器,它主要被应用在金融领域。其数学目的是求解能够让模型对数据拟合程度最高的参数 θ \theta θ的值,以此构建预测函数 y ( x ) y(x) y(x),然后将特征矩阵输入预测函数来计算出逻辑回归的结果 y y y。虽然我们熟悉的逻辑回归通常被用于处理二分类问题,但逻辑回归也可以做多分类。
sklearn中的逻辑回归
逻辑回归相关的类 | 说明 |
---|---|
linear_model.LogisticRegression | 逻辑回归分类器(又叫logit回归,最大熵分类器) |
linear_model.LogisticRegressionCV | 带交叉验证的逻辑回归分类器 |
linear_model.logistic_regression_path | 计算Logistic回归模型以获得正则化参数的列表 |
linear_model.SGDClassifier | 利用梯度下降求解的线性分类器(SVM,逻辑回归等等) |
linear_model.SGDRegressor | 利用梯度下降最小化正则化后的损失函数的线性回归模型 |
metrics.log_loss | 对数损失,又称逻辑损失或交叉熵损失 |
metrics.confusion_matrix | 混淆矩阵,模型评估指标之一 |
metrics.roc_auc_score | ROC曲线,模型评估指标之一 |
metrics.accuracy_score | 精确性,模型评估指标之一 |
2.linear_model.LogisticRegression
二元逻辑回归的损失函数
损失函数的概念
我们曾经提到过两种模型表现:在训练集上的表现,和在测试集上的表现。我们建模,是追求模型在测试集上的表现最优,因此模型的评估指标往往是用来衡量模型在测试集上的表现的。然而,逻辑回归有着基于训练数据求解参数
θ
\theta
θ的需求,并且希望训练出来的模型能够尽可能地拟合训练数据,即模型在训练集上的预测准确率越靠近100%越好。
因此,我们使用”损失函数“这个评估指标,来衡量参数为
θ
\theta
θ的模型在拟合训练集时产生的信息损失的大小,并以此衡量参数
θ
\theta
θ的优劣。如果用一组参数建模后,模型在训练集上表现良好,那我们就说模型拟合过程中的损失很小,损失函数的值很小,这一组参数就优秀;相反,如果模型在训练集上表现糟糕,损失函数就会很大,模型就训练不足,效果较差,这一组参数也就比较差。即是说,我们在求解参数
θ
\theta
θ时,追求损失函数最小,让模型在训练数据上的拟合效果最优,即预测准确率尽量靠近100%。
逻辑回归的损失函数是由极大似然估计推导出来的,具体结果可以写作:
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
m
m是样本的个数,
y
i
y_i
yi是样本
i
i
i上真实的标签,
y
θ
(
x
i
)
y_\theta(x_i)
yθ(xi)是样本
i
i
i上,基于参数
θ
\theta
θ计算出来的逻辑回归返回值,
x
i
x_i
xi是样本
i
i
i各个特征的取值。我们的目标,就是求解出使
J
(
θ
)
J(\theta)
J(θ)最小的
θ
\theta
θ取值。注意,在逻辑回归的本质函数
y
(
x
)
y(x)
y(x)里,特征矩阵
x
x
x是自变量,参数是
θ
\theta
θ。但在损失函数中,参数
θ
\theta
θ是损失函数的自变量,
x
x
x和
y
y
y都是已知的特征矩阵和标签,相当于是损失函数的参数。不同的函数中,自变量和参数各有不同,因此大家需要在数学计算中,尤其是求导的时候避免混淆。
二元逻辑回归损失函数的数学解释,公式推导
二元逻辑回归的标签服从伯努利分布(即0-1分布),因此我们可以将一个特征向量为
x
x
x ,参数为
θ
\theta
θ的模型中的一个样本
i
i
i的预测情况表现为如下形式:
样本
i
i
i在由特征向量
x
x
x和参数
θ
\theta
θ组成的预测函数中,样本标签被预测为1的概率为:
P
1
=
P
(
y
^
i
=
1
∣
x
i
,
θ
)
=
y
θ
(
x
i
)
P_1=P(\hat{y}_i=1|x_i,\theta)=y_\theta(x_i)
P1=P(y^i=1∣xi,θ)=yθ(xi)
样本
i
i
i在由特征向量
x
x
x和参数
θ
\theta
θ组成的预测函数中,样本标签被预测为0的概率为:
P
0
=
P
(
y
^
i
=
0
∣
x
i
,
θ
)
=
1
−
y
θ
(
x
i
)
P_0=P(\hat{y}_i=0|x_i,\theta)=1-y_\theta(x_i)
P0=P(y^i=0∣xi,θ)=1−yθ(xi)
当
P
1
P_1
P1的值为1的时候,代表样本i的标签被预测为1,当
P
0
P_0
P0的值为1的时候,代表样本i的标签被预测为0。
我们假设样本i的真实标签
y
i
y_i
yi为1,此时如果
P
1
P_1
P1为1,
P
0
P_0
P0为0,就代表样本i的标签被预测为1,与真实值一致。此时对于单样本i来说,模型的预测就是完全准确的,拟合程度很优秀,没有任何信息损失。相反,如果
P
1
P_1
P1此时为0,
P
0
P_0
P0为1,就代表样本i的标签被预测为0,与真实情况完全相反。对于单样本i来说,模型的预测就是完全错误的,拟合程度很差,所有的信息都损失了。当
y
i
y_i
yi为0时,也是同样的道理。所以,当
y
i
y_i
yi为1的时候,我们希望
P
1
P_1
P1非常接近1,当
y
i
y_i
yi为0的时候,我们希望
P
0
P_0
P0非常接近1,这样,模型的效果就很好,信息损失就很少。
将两种取值的概率整合,我们可以定义如下等式:
P
(
y
^
i
∣
x
i
,
θ
)
=
P
1
y
i
∗
P
0
1
−
y
i
P(\hat{y}_i|x_i,\theta)=P_1^{y_i}*P_0^{1-y_i}
P(y^i∣xi,θ)=P1yi∗P01−yi
这个等式代表同时代表了
P
1
P_1
P1和
P
0
P_0
P0。当样本i的真实标签
y
i
y_i
yi为1的时候,
1
−
y
i
1-y_i
1−yi就等于0,
P
0
P_0
P0的0次方就是1,所以
P
(
y
^
i
∣
x
i
,
θ
)
P(\hat{y}_i|x_i,\theta)
P(y^i∣xi,θ)就等于
P
1
P_1
P1,这个时候,如果
P
1
P_1
P1为1,模型的效果就很好,损失就很小。同理,当
y
i
y_i
yi为0的时候,
P
(
y
^
i
∣
x
i
,
θ
)
P(\hat{y}_i|x_i,\theta)
P(y^i∣xi,θ)就等于
P
0
P_0
P0,此时如果
P
0
P_0
P0非常接近1,模型的效果就很好,损失就很小。所以,为了达成让模型拟合好,损失小的目的,我们每时每刻都希望
P
(
y
^
i
∣
x
i
,
θ
)
P(\hat{y}_i|x_i,\theta)
P(y^i∣xi,θ)的值等于1。而
P
(
y
^
i
∣
x
i
,
θ
)
P(\hat{y}_i|x_i,\theta)
P(y^i∣xi,θ)的本质是样本i由特征向量
x
i
x_i
xi和参数
θ
\theta
θ组成的预测函数中,预测出所有可能的
y
^
i
\hat{y}_i
y^i的概率,因此1是它的最大值。也就是说,每时每刻,我们都在追求
P
(
y
^
i
∣
x
i
,
θ
)
P(\hat{y}_i|x_i,\theta)
P(y^i∣xi,θ)的最大值。这就将模型拟合中的“最小化损失”问题,转换成了对函数求解极值的问题。
对一个训练集的
m
m
m个样本来说,我们可以定义如下等式来表达所有样本在特征矩阵
X
X
X和参数
θ
\theta
θ组成的预测函数中,预测出所有可能的
y
^
\hat{y}
y^的概率
P
P
P为:
P
=
∏
i
=
1
m
P
(
y
i
^
∣
x
i
,
θ
)
=
∏
i
=
1
m
(
P
1
y
i
∗
P
0
1
−
y
i
)
=
∏
i
=
1
m
(
y
θ
(
x
i
)
y
i
∗
(
1
−
y
θ
(
x
i
)
)
1
−
y
i
)
\begin{aligned} P &=\prod_{i=1}^mP(\hat{y_i}|x_i,\theta)\\ &=\prod_{i=1}^m(P_1^{y_i}*P_0^{1-y_i})\\ &=\prod_{i=1}^m(y_\theta(x_i)^{y_i}*(1-y_\theta(x_i))^{1-y_i}) \end{aligned}
P=i=1∏mP(yi^∣xi,θ)=i=1∏m(P1yi∗P01−yi)=i=1∏m(yθ(xi)yi∗(1−yθ(xi))1−yi)
对
P
P
P取对数可得
l
o
g
P
=
l
o
g
∏
i
=
1
m
(
y
θ
(
x
i
)
y
i
∗
(
1
−
y
θ
(
x
i
)
)
1
−
y
i
)
=
∑
i
=
1
m
l
o
g
(
y
θ
(
x
i
)
y
i
∗
(
1
−
y
θ
(
x
i
)
)
1
−
y
i
)
=
∑
i
=
1
m
(
l
o
g
(
y
θ
(
x
i
)
y
i
)
+
l
o
g
(
(
1
−
y
θ
(
x
i
)
)
1
−
y
i
)
)
=
∑
i
=
1
m
(
y
i
l
o
g
(
y
θ
(
x
i
)
)
+
(
1
−
y
i
)
l
o
g
(
1
−
y
θ
(
x
i
)
)
)
\begin{aligned} logP &=log\prod_{i=1}^m(y_\theta(x_i)^{y_i}*(1-y_\theta(x_i))^{1-y_i})\\ &=\sum_{i=1}^mlog(y_\theta(x_i)^{y_i}*(1-y_\theta(x_i))^{1-y_i})\\ &=\sum_{i=1}^m(log(y_\theta(x_i)^{y_i})+log((1-y_\theta(x_i))^{1-y_i}))\\ &=\sum_{i=1}^m(y_ilog(y_\theta(x_i))+(1-y_i)log(1-y_\theta(x_i))) \end{aligned}
logP=logi=1∏m(yθ(xi)yi∗(1−yθ(xi))1−yi)=i=1∑mlog(yθ(xi)yi∗(1−yθ(xi))1−yi)=i=1∑m(log(yθ(xi)yi)+log((1−yθ(xi))1−yi))=i=1∑m(yilog(yθ(xi))+(1−yi)log(1−yθ(xi)))
对
l
o
g
P
logP
logP取负,就可以将极大值问题转换为极小值问题,并且让参数
θ
\theta
θ作为函数的自变量,就得到了我们的损失函数 :
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)))
在这个函数上,我们只要追求最小值,就能让模型在训练数据上的拟合效果最好,损失最低。整个推导过程,其实就是“极大似然法”的推导过程。
重要参数penalty & C
正则化
正则化是用来防止模型过拟合的过程,常用的有L1正则化和L2正则化两种选项,分别通过在损失函数后加上参数向量
θ
\theta
θ的L1范式和L2范式的倍数来实现。这个增加的范式,被称为“正则项”,也被称为"惩罚项"。损失函数改变,基于损失函数的最优化来求解的参数取值必然改变,我们以此来调节模型拟合的程度。其中L1范式表现为参数向量中的每个参数的绝对值之和,L2范数表现为参数向量中的每个参数的平方和的开方值。
J
(
θ
)
L
1
=
C
∗
J
(
θ
)
+
∑
j
=
1
n
∣
θ
j
∣
(
j
≥
1
)
J
(
θ
)
L
2
=
C
∗
J
(
θ
)
+
∑
j
=
1
n
(
θ
j
)
2
(
j
≥
1
)
J(\theta)_{L1}=C*J(\theta)+\sum_{j=1}^n|\theta_j|(j\geq1)\\ J(\theta)_{L2}=C*J(\theta)+\sqrt{\sum_{j=1}^n(\theta_j)^2}(j\geq1)
J(θ)L1=C∗J(θ)+j=1∑n∣θj∣(j≥1)J(θ)L2=C∗J(θ)+j=1∑n(θj)2(j≥1)
其中
J
(
θ
)
J(\theta)
J(θ)是我们之前提过的损失函数,
C
C
C是用来控制正则化程度的超参数,
n
n
n是方程中特征的总数,也是方程中参数的总数,
j
j
j代表每个参数。在这里,
j
j
j要大于等于1,是因为我们的参数向量
θ
\theta
θ中,第一个参数是
θ
0
\theta_0
θ0,是我们的截距,它通常是不参与正则化的。
参数 | 说明 |
---|---|
penalty | 可以输入"l1"或"l2"来指定使用哪一种正则化方式,不填写默认"l2"。注意,若选择"l1"正则化,参数solver仅能使用求解方式”liblinear"和"saga“,若使用“l2”正则化,参数solver中所有的求解方式都可以使用。 |
C | 正则化强度的倒数,必须是一个大于0的浮点数,不填写默认1.0,即默认正则项与损失函数的比值是1:1。C越小,损失函数会越小,模型对损失函数的惩罚越重,正则化的效力越强,参数 θ \theta θ会逐渐被压缩得越来越小。 |
可以建立两个逻辑回归,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
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.coef_ != 0).sum(axis=1)#不为0的参数的个数
lrl2 = lrl2.fit(X,y)
lrl2.coef_
运行结果:
可以看见,当我们选择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, 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) # 4表示图例的位置在右下角
plt.show()
可见,至少在乳腺癌数据集下,两种正则化的结果区别不大。但随着C的逐渐变大,正则化的强度越来越小,模型在训练集和测试集上的表现都呈上升趋势,直到C=0.8左右,训练集上的表现依然在走高,但模型在未知数据集上的表现开始下跌,这时候就是出现了过拟合。我们可以认为,C设定为0.8会比较好。在实际使用时,基本就默认使用l2正则化,如果感觉到模型的效果不好,那就换L1试试看。
梯度下降:重要参数max_iter
现在有一个带两个特征并且没有截距的逻辑回归
y
(
x
1
,
x
2
)
y(x_1,x_2)
y(x1,x2),两个特征所对应的参数分别为
[
θ
1
,
θ
2
]
[\theta_1,\theta_2]
[θ1,θ2] 。下面这个平面就是我们的损失函数
J
(
θ
1
,
θ
2
)
J(\theta_1,\theta_2)
J(θ1,θ2) 在以
θ
1
,
θ
2
\theta_1,\theta_2
θ1,θ2和
J
J
J为坐标轴的三维立体坐标系上的图像。现在,我们寻求的是损失函数的最小值,也就是图像的最低点。
我在这个图像上随机放一个小球,松手,这个小球就会顺着这个平面滚落,直到滚到深蓝色的区域——损失函数的最低点。为了严格监控这个小球的行为,让小球每次滚动的距离有限,不让他一次性滚到最低点,并且最多只允许它滚动100步,还要记下它每次滚动的方向,直到它滚到图像上的最低点。
小球从高处滑落,在深蓝色的区域中来回震荡,最终停留在了图像凹陷处的某个点上.
小球在进入深蓝色区域后,并没有直接找到某个点,而是在深蓝色区域中来回震荡了数次才停下。这有两种可能:
- 小球已经滚到了图像的最低点,所以停下了,
- 由于我设定的步数限制,小球还没有找到最低点,但也只好在100步的时候停下了。也就是说,小球不一定滚到了图像的最低处。
但无论如何,小球停下的就是我们在现有状况下可以获得的唯一点了。如果我们够幸运,这个点就是图像的最低点,那我们只要找到这个点的对应坐标
(
θ
1
∗
,
θ
2
∗
,
J
m
i
n
)
(\theta_1^*,\theta_2^*,J_{min})
(θ1∗,θ2∗,Jmin),就可以获取能够让损失函数最小的参数取值[
θ
1
∗
,
θ
2
∗
\theta_1^*,\theta_2^*
θ1∗,θ2∗]了。
如此,梯度下降的过程就已经完成。
在这个过程中,小球其实就是一组组的坐标点
(
θ
1
,
θ
2
,
J
)
(\theta_1,\theta_2,J)
(θ1,θ2,J);小球每次滚动的方向就是那一个坐标点的梯度向量的方向,因为每滚动一步,小球所在的位置都发生变化,坐标点和坐标点对应的梯度向量都发生了变化,所以每次滚动的方向也都不一样;人为设置的100次滚动限制,就是sklearn中逻辑回归的参数max_iter,代表着能走的最大步数,即最大迭代次数。
所以梯度下降,其实就是在众多[
θ
1
,
θ
2
\theta_1,\theta_2
θ1,θ2]可能的值中遍历,一次次求解坐标点的梯度向量,不断让损失函数
J
J
J的取值逐渐逼近最小值,再返回这个最小值对应的参数取值
[
θ
1
∗
,
θ
2
∗
]
[\theta_1^*,\theta_2^*]
[θ1∗,θ2∗]的过程。
那梯度有什么含义呢?梯度是一个向量,因此它有大小也有方向。它的大小,就是偏导数组成的向量的大小,又叫做向量的模,记作
d
d
d。它的方向,几何上来说,就是损失函数
J
(
θ
)
J(\theta)
J(θ)的值增加最快的方向,就是小球每次滚动的方向的反方向。只要沿着梯度向量的反方向移动坐标,损失函数
J
(
θ
)
J(\theta)
J(θ)的取值就会减少得最快,也就最容易找到损失函数的最小值。
在逻辑回归中,我们的损失函数如下所示:
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
θ求偏导,就可以得到梯度向量在第
j
j
j组
θ
\theta
θ的坐标点上的表示形式:
∂
∂
θ
i
J
(
θ
)
=
d
j
=
∑
i
=
1
m
(
y
θ
(
x
i
)
−
y
i
)
x
i
j
\frac{\partial}{\partial\theta_i}J(\theta)=d_j=\sum_{i=1}^m(y_\theta(x_i)-y_i)x_{ij}
∂θi∂J(θ)=dj=i=1∑m(yθ(xi)−yi)xij
在这个公式下,只要给定一组
θ
\theta
θ的取值
θ
j
\theta_j
θj,再带入特征矩阵
x
x
x,就可以求得这一组
θ
\theta
θ取值下的预测结果
y
θ
(
x
i
)
y_\theta(x_i)
yθ(xi),结合真实标签向量
y
i
y_i
yi,就可以获得这一组
θ
j
\theta_j
θj取值下的梯度向量,其大小表示为
d
j
d_j
dj。之前说过,我们的目的是在可能的
θ
\theta
θ取值上进行遍历,一次次计算梯度向量,并在梯度向量的反方向上让损失函数
J
(
θ
)
J(\theta)
J(θ)下降至最小值。在这个过程中,我们的
θ
\theta
θ和梯度向量的大小
d
d
d都会不断改变,而我们遍历
θ
\theta
θ的过程可以描述为:
θ
j
+
1
=
θ
j
−
α
∗
d
j
=
θ
j
−
α
∗
∑
i
=
1
m
(
y
θ
(
x
i
)
−
y
i
)
x
i
j
\theta_{j+1}=\theta_j-\alpha*d_j=\theta_j-\alpha*\sum_{i=1}^m(y_\theta(x_i)-y_i)x_{ij}
θj+1=θj−α∗dj=θj−α∗i=1∑m(yθ(xi)−yi)xij
其中
θ
j
+
1
\theta_{j+1}
θj+1是第
j
j
j次迭代后的参数向量,
θ
j
\theta_j
θj是第
j
j
j次迭代是的参数向量,
α
\alpha
α被称为步长,控制着每走一步(每迭代一次)后
θ
\theta
θ的变化,并以此来影响每次迭代后的梯度向量的大小和方向。
步长不是任何物理距离,它甚至不是梯度下降过程中任何距离的直接变化,它是梯度向量的大小
d
d
d上的一个比例,影响着参数向量
θ
\theta
θ每次迭代后改变的部分。,在sklearn当中,我们设置参数max_iter最大迭代次数来代替步长,帮助我们控制模型的迭代速度并适时地让模型停下。max_iter越大,代表步长越小,模型迭代时间越长,反之,则代表步长设置很大,模型迭代时间很短。
来看看乳腺癌数据集下,max_iter的学习曲线:
l2 = []
l2test = []
Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)
for i in np.arange(1,201,10):
lrl2 = LR(penalty="l2",solver="liblinear",C=0.9,max_iter=i)
lrl2 = lrl2.fit(Xtrain,Ytrain)
l2.append(accuracy_score(lrl2.predict(Xtrain),Ytrain))
l2test.append(accuracy_score(lrl2.predict(Xtest),Ytest))
graph = [l2,l2test]
color = ["black","gray"]
label = ["L2","L2test"]
plt.figure(figsize=(20,5))
for i in range(len(graph)):
plt.plot(np.arange(1,201,10),graph[i],color[i],label=label[i])
plt.legend(loc=4)
plt.xticks(np.arange(1,201,10))
plt.show()
#我们可以使用属性.n_iter_来调用本次求解中真正实现的迭代次数
lr = LR(penalty="l2",solver="liblinear",C=0.9,max_iter=300).fit(Xtrain,Ytrain)
lr.n_iter_
求解中真正实现的迭代次数:
重要参数solver & multi_class
在sklearn中,我们使用参数multi_class来告诉模型,我们的预测标签是什么样的类型。
通过输入"ovr", “multinomial”, “auto"来告知模型,我们要处理的分类问题的类型。默认是"ovr”。
- ‘ovr’:表示分类问题是二分类,或让模型使用"一对多"的形式来处理多分类问题。
- ‘multinomial’:表示处理多分类问题,这种输入在参数solver是’liblinear’时不可用。
- ‘auto’:表示会根据数据的分类情况和其他参数来确定模型要处理的分类问题的类型。比如说,如果数据是二分类,或者solver的取值为"liblinear",“auto"会默认选择"ovr”。反之,则会选择"multinomial"。
求解器的选择,由参数"solver"控制,共有五种选择。其中“liblinear”是二分类专用,也是现在的默认求解器。