目录
从线性回归到逻辑回归
逻辑回归是用来做分类任务的。分类任务的目标是找一个函数,把观测值匹配到相关的类和标签上。学习算法必须用成对的特征向量和对应的标签来估计匹配函数的参数,从而实现更好的分类效果。在二元分类(binary classification)中,分类算法必须把一个实例配置两个类别。二元分类案例包括,预测患者是否患有某种疾病,典型的图片猫狗分类。多元分类中,分类算法需要为每个实例都分类一组标签。
1.逻辑回归与线性回归
普通的线性回归假设响应变量呈正态分布,也称为高斯分布(Gaussian distribution )或钟形曲线(bell curve)。正态分布数据是对称的,且均值,中位数和众数(mode)是一样的。而在某些问题里,响应变量不是正态分布的。比如,掷一个硬币获取正反两面的概率分布是伯努力分布(Bernoulli distribution),又称两点分布或者0-1分布。表示一个事件发生的概率是 ,不发生的概率是 ,概率在$ {0,1} $ 之间。线性回归假设解释变量值的变化会引起响应变量值的变化,如果响应变量的值是概率的,这条假设就不满足了。
在逻辑回归里,响应变量描述了类似于掷一个硬币结果为正面的概率。如果响应变量等于或超过了指定的临界值,预测结果就是正面,否则预测结果就是反面。响应变量是一个像线性回归中的解释变量构成的函数表示,称为逻辑函数(logistic function)。一个值在{0,1}之间的逻辑函数如下所示:
逻辑回归(Logistic Regression)分类算法是将线性函数的结果映射到了sigmoid函数中。sigmoid函数的公式如下:
sigmoid的函数输出是介于{0,1}之间的,中间值是0.5; 则说明当前数据属于A类; 则说明当前数据属于B类。sigmoid函数看成样本数据的概率密度函数。逻辑回归(Logistic Regression)本质上也是线性回归。
逻辑回归的之所以有回归两个字,是因为逻辑回归其实就是从线性回归变过来的。唯一的变化是在线性回归外面包了一层函数,将线性回归的值压缩到( 0 , 1 )之间。当输出的值大于等于0.5的时候则判断为1, 当小于0.5的时候则判断为0
逻辑回归(Logistic Regression)分类算法的核心步骤如下:
- 构造 predict 函数,一般采用Sigmoid函数;
- 构造 loss 函数, 一般采用对数损失函数
- 使用优化方法(梯度下降法、牛顿法等)最小化 loss 函数
- 反复迭代优化方法
- 输出分类类别
逻辑回归(Logistic Regression)分类算法的核心优势如下:
- 计算伸缩性: 基于线性回归,计算复杂度可控;
- 参数依赖性: 可调节参数较少;
- 普适性能力: 适用于连续型和离散型数据集;
- 抗噪音能力: 对缺失数据和异常数据比较敏感,需要特别关注;
- 结果解释性: 理论明确,解释性好。
2. 二元逻辑回归的损失函数
回顾下线性回归的损失函数,由于线性回归是连续的,所以可以使用模型误差的的平方和来定义损失函数。但是逻辑回归不是连续的,自然线性回归损失函数定义的经验就用不上了。不过我们可以用最大似然法来推导出我们的损失函数。
我们知道,按照二元逻辑回归的定义,假设我们的样本输出是0或者1两类。那么我们有:
把这两个式子写成一个式子,就是:
其中y的取值只能是0或者1。
用矩阵法表示,即为:
,其中E为单位矩阵。
得到了y的概率分布函数表达式,我们就可以用似然函数最大化来求解我们需要的模型系数θ。
为了方便求解,这里我们用对数似然函数最大化,对数似然函数取反即为我们的损失函数J(θ)。其中:
似然函数的代数表达式为:
其中m为样本的个数。
对似然函数对数化取反的表达式,即损失函数表达式为:
损失函数用矩阵法表达更加简洁:
其中E为单位矩阵,∙∙为内积。
3. 二元逻辑回归的损失函数的优化方法
对于二元逻辑回归的损失函数极小化,有比较多的方法,最常见的有梯度下降法,坐标轴下降法,等牛顿法等。这里推导出梯度下降法中θθ每次迭代的公式。由于代数法推导比较的繁琐,我习惯于用矩阵法来做损失函数的优化过程,这里给出矩阵法推导二元逻辑回归梯度的过程。
对于 ,我们用J(θ)对θ向量求导可得:
这一步我们用到了矩阵求导的链式法则,和下面三个矩阵求导公式:
(g(z)为sigmoid函数)
对于刚才的求导公式我们进行化简可得:
从而在梯度下降法中每一步向量θθ的迭代公式如下:
其中,α为梯度下降法的步长。
实践中,我们一般不用操心优化方法,大部分机器学习库都内置了各种逻辑回归的优化方法,不过了解至少一种优化方法还是有必要的。
4. 二元逻辑回归的正则化
逻辑回归也会面临过拟合问题,所以我们也要考虑正则化。常见的有L1正则化和L2正则化。
逻辑回归的L1正则化的损失函数表达式如下,相比普通的逻辑回归损失函数,增加了L1的范数做作为惩罚,超参数α作为惩罚系数,调节惩罚项的大小。
二元逻辑回归的L1正则化损失函数表达式如下:
其中 为θ的L1范数。
逻辑回归的L1正则化损失函数的优化方法常用的有坐标轴下降法和最小角回归法。
二元逻辑回归的L2正则化损失函数表达式如下:
其中 为θ的L2范数。
逻辑回归的L2正则化损失函数的优化方法和普通的逻辑回归类似。
5. sklearn相关
在scikit-learn中,与逻辑回归有关的主要是这3个类。LogisticRegression
, LogisticRegressionCV
和logistic_regression_path
。其中LogisticRegression
和LogisticRegressionCV
的主要区别是LogisticRegressionCV
使用了交叉验证来选择正则化系数C。而LogisticRegression
需要自己每次指定一个正则化系数。除了交叉验证,以及选择正则化系数C以外, LogisticRegression
和LogisticRegressionCV
的使用方法基本相同。
logistic_regression_path
类则比较特殊,它拟合数据后,不能直接来做预测,只能为拟合数据选择合适逻辑回归的系数和正则化系数。主要是用在模型选择的时候。一般情况用不到这个类。
此外,scikit-learn
里面有个容易让人误解的类RandomizedLogisticRegression
,虽然名字里有逻辑回归的词,但是主要是用L1正则化的逻辑回归来做特征选择的,属于维度规约的算法类,不属于我们常说的分类算法的范畴。
这里主要围绕LogisticRegression
和LogisticRegressionCV
中的重要参数的选择来来展开,这些参数的意义在这两个类中都是一样的。
5.1.正则化选择参数:penalty
LogisticRegression
和LogisticRegressionCV
默认就带了正则化项。penalty
参数可选择的值为"l1"
和"l2"
.分别对应L1的正则化和L2的正则化,默认是L2的正则化。
在调参时如果我们主要的目的只是为了解决过拟合,一般penalty选择L2正则化就够了。但是如果选择L2正则化发现还是过拟合,即预测效果差的时候,就可以考虑L1正则化。另外,如果模型的特征非常多,我们希望一些不重要的特征系数归零,从而让模型系数稀疏化的话,也可以使用L1正则化。
penalty
参数的选择会影响我们损失函数优化算法的选择。即参数solver的选择,如果是L2正则化,那么4种可选的算法'newton-cg', 'lbfgs', 'liblinear', 'sag'}
都可以选择。但是如果penalty
是L1正则化的话,就只能选择‘liblinear’了。这是因为L1正则化的损失函数不是连续可导的,而{'newton-cg', 'lbfgs','sag'}
这三种优化算法时都需要损失函数的一阶或者二阶连续导数。而'liblinear'
并没有这个依赖。
5.2 优化算法选择参数:solver
solver
参数决定了我们对逻辑回归损失函数的优化方法,有4种算法可以选择,分别是:
liblinear
:使用了开源的liblinear库实现,内部使用了坐标轴下降法来迭代优化损失函数。lbfgs
:拟牛顿法的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。newton-cg
:也是牛顿法家族的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。sag
:即随机平均梯度下降,是梯度下降法的变种,和普通梯度下降法的区别是每次迭代仅仅用一部分的样本来计算梯度,适合于样本数据多的时候。
从上面的描述可以看出,newton-cg
, lbfgs
和sag
这三种优化算法时都需要损失函数的一阶或者二阶连续导数,因此不能用于没有连续导数的L1正则化,只能用于L2正则化。而liblinear
通吃L1正则化和L2正则化。
同时,sag
每次仅仅使用了部分样本进行梯度迭代,所以当样本量少的时候不要选择它,而如果样本量非常大,比如大于10万,sag
是第一选择。但是sag
不能用于L1正则化,所以当你有大量的样本,又需要L1正则化的话就要自己做取舍了。要么通过对样本采样来降低样本量,要么回到L2正则化。
5.3. 分类方式选择参数:multi_class
multi_class
参数决定了我们分类方式的选择,有ovr
和multinomial
两个值可以选择,默认是 ovr
。
ovr
即前面提到的one-vs-rest(OvR),而multinomial
即前面提到的many-vs-many(MvM)。如果是二元逻辑回归,ovr
和multinomial
并没有任何区别,区别主要在多元逻辑回归上。
OvR的思想很简单,无论你是多少元逻辑回归,我们都可以看做二元逻辑回归。具体做法是,对于第K类的分类决策,我们把所有第K类的样本作为正例,除了第K类样本以外的所有样本都作为负例,然后在上面做二元逻辑回归,得到第K类的分类模型。其他类的分类模型获得以此类推。
而MvM则相对复杂,这里举MvM的特例one-vs-one(OvO)作讲解。如果模型有T类,我们每次在所有的T类样本里面选择两类样本出来,不妨记为T1类和T2类,把所有的输出为T1和T2的样本放在一起,把T1作为正例,T2作为负例,进行二元逻辑回归,得到模型参数。我们一共需要T(T-1)/2次分类。
从上面的描述可以看出OvR相对简单,但分类效果相对略差(这里指大多数样本分布情况,某些样本分布下OvR可能更好)。而MvM分类相对精确,但是分类速度没有OvR快。
如果选择了ovr
,则4种损失函数的优化方法liblinear
,newton-cg
, lbfgs
和sag
都可以选择。但是如果选择了multinomial
,则只能选择newton-cg
, lbfgs
和sag
了。
5.4 类型权重参数: class_weight
class_weight
参数用于标示分类模型中各种类型的权重,可以不输入,即不考虑权重,或者说所有类型的权重一样。如果选择输入的话,可以选择balanced
让类库自己计算类型权重,或者我们自己输入各个类型的权重,比如对于0,1的二元模型,我们可以定义class_weight
={0:0.9, 1:0.1},这样类型0的权重为90%,而类型1的权重为10%。
如果class\_weight
选择balanced
,那么类库会根据训练样本量来计算权重。某种类型样本量越多,则权重越低,样本量越少,则权重越高。
那么class_weight
有什么作用呢?在分类模型中,我们经常会遇到两类问题:
- 第一种是误分类的代价很高。比如对合法用户和非法用户进行分类,将非法用户分类为合法用户的代价很高,我们宁愿将合法用户分类为非法用户,这时可以人工再甄别,但是却不愿将非法用户分类为合法用户。这时,我们可以适当提高非法用户的权重。
- 第二种是样本是高度失衡的,比如我们有合法用户和非法用户的二元样本数据10000条,里面合法用户有9995条,非法用户只有5条,如果我们不考虑权重,则我们可以将所有的测试集都预测为合法用户,这样预测准确率理论上有99.95%,但是却没有任何意义。这时,我们可以选择
balanced
,让类库自动提高非法用户样本的权重。
提高了某种分类的权重,相比不考虑权重,会有更多的样本分类划分到高权重的类别,从而可以解决上面两类问题。
5.5 样本权重参数: sample_weight
由于样本不平衡,导致样本不是总体样本的无偏估计,从而可能导致我们的模型预测能力下降。遇到这种情况,我们可以通过调节样本权重来尝试解决这个问题。调节样本权重的方法有两种,第一种是在class_weight
使用balanced
。第二种是在调用fit函数时,通过sample_weight
来自己调节每个样本权重。
在scikit-learn做逻辑回归时,如果上面两种方法都用到了,那么样本的真正权重是class_weight
*sample_weight
.