1、模型原理
(另一台电脑上,待补充)
回顾下线性回归的损失函数,由于线性回归是连续的,所以可以使用模型误差的的平方和来定义损失函数。但是逻辑回归不是连续的,自然线性回归损失函数定义的经验就用不上了。不过我们可以用最大似然法来推导出我们的损失函数。
2、Python3中sklearn关于Logistic回归的代码实现
(1)概述
在scikit-learn中,与逻辑回归有关的主要是这3个类。LogisticRegression, LogisticRegressionCV 和logistic_regression_path。
其中LogisticRegression和LogisticRegressionCV的主要区别是:
LogisticRegressionCV使用了交叉验证来选择正则化系数C。而LogisticRegression需要自己每次指定一个正则化系数。
即LogisticRegression不做交叉验证 ,也就是整个输入作为训练集来训练模型参数。而LogisticRegressionCV则会将训练集分成若干份,每次选择一部分训练集来训练模型,一部分样本做验证集来测试模型优劣,多次验证后选择最好的模型参数。
所以两者肯定有差异。一般来说,会用后面一个。不过如果你用了其他一些网格搜索方法(比如 GridSearchCV),自带交叉验证的话,那么用第一个就可以了。
除了交叉验证,以及选择正则化系数C以外, LogisticRegression和LogisticRegressionCV的使用方法基本相同。
logistic_regression_path类则比较特殊,它拟合数据后,不能直接来做预测,只能为拟合数据选择合适逻辑回归的系数和正则化系数。主要是用在模型选择的时候。一般情况用不到这个类,所以后面不再讲述logistic_regression_path类。
此外,scikit-learn里面有个容易让人误解的类RandomizedLogisticRegression,虽然名字里有逻辑回归的词,但是主要是用L1正则化的逻辑回归来做特征选择的,属于维度规约的算法类,不属于我们常说的分类算法的范畴。
(2)LogisticRegression和LogisticRegressionCV参数介绍
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=’liblinear’, max_iter=100, multi_class=’ovr’, verbose=0, warm_start=False, n_jobs=1)
sklearn.linear_model.LogisticRegressionCV(Cs=10, fit_intercept=True, cv=None, dual=False, penalty=’l2’, scoring=None, solver=’lbfgs’, tol=0.0001, max_iter=100, class_weight=None, n_jobs=1, verbose=0, refit=True, intercept_scaling=1.0, multi_class=’ovr’, random_state=None)
关键参数介绍:
-penalty, 字符型,可选‘l1’ or ‘l2’, 默认为 ‘l2’,这个参数是选择正则化项的,分别对应的L1正则化和L2正则化。
在调参时如果我们主要的目的只是为了解决过拟合,一般penalty选择L2正则化就够了。但是如果选择L2正则化发现还是过拟合,即预测效果差的时候,就可以考虑L1正则化。另外,如果模型的特征非常多,我们希望一些不重要的特征系数归零,从而让模型系数稀疏化的话,也可以使用L1正则化。
penalty参数的选择会影响我们损失函数优化算法的选择。即参数solver的选择,如果是L2正则化,那么4种可选的算法{‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’}都可以选择。但是如果penalty是L1正则化的话,就只能选择‘liblinear’了。这是因为L1正则化的损失函数不是连续可导的,而{‘newton-cg’, ‘lbfgs’,‘sag’}这三种优化算法时都需要损失函数的一阶或者二阶连续导数。而‘liblinear’并没有这个依赖。
具体使用了这4个算法有什么不同以及有什么影响,在solver参数作出说明。
-solver, 字符型,可选‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’, ‘saga’, LR默认为'liblinear',LRCV默认为 ‘lbfgs’,这个参数决定了我们对逻辑回归损失函数的优化方法,有4种算法可以选择,分别是:
a) liblinear:使用了开源的liblinear库实现,内部使用了坐标轴下降法来迭代优化损失函数。
b) lbfgs:拟牛顿法的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
c) newton-cg:也是牛顿法家族的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
d) sag:即随机平均梯度下降,是梯度下降法的变种,和普通梯度下降法的区别是每次迭代仅仅用一部分的样本来计算梯度,适合于样本数据多的时候。
d) saga:随机优化SAG的变种。
从上面的描述可以看出,newton-cg, lbfgs和sag这三种优化算法时都需要损失函数的一阶或者二阶连续导数,因此不能用于没有连续导数的L1正则化,只能用于L2正则化。而liblinear通吃L1正则化和L2正则化。
同时,sag每次仅仅使用了部分样本进行梯度迭代,所以当样本量少的时候不要选择它,而如果样本量非常大,比如大于10万,sag是第一选择。但是sag不能用于L1正则化,所以当你有大量的样本,又需要L1正则化的话就要自己做取舍了。要么通过对样本采样来降低样本量,要么回到L2正则化。
从上面的描述,大家可能觉得,既然newton-cg, lbfgs和sag这么多限制,如果不是大样本,我们选择liblinear不就行了嘛!错,因为liblinear也有自己的弱点!我们知道,逻辑回归有二元逻辑回归和多元逻辑回归。对于多元逻辑回归常见的有one-vs-rest(OvR)和many-vs-many(MvM)两种。而MvM一般比OvR分类相对准确一些。郁闷的是liblinear只支持OvR,不支持MvM,这样如果我们需要相对精确的多元逻辑回归时,就不能选择liblinear了。也意味着如果我们需要相对精确的多元逻辑回归不能使用L1正则化了。
具体OvR和MvM有什么不同我们下一节讲。
官方说明:
对于小型数据集,'liblinear'是一个不错的选择,而'sag'和'saga'对大的数据集来说速度更快。
对于多类问题,只有'newton-cg','sag','saga'和'lbfgs'能处理多项式损失(可能就是我们常说的MvM); 'liblinear'仅限于OvR的情况。
'newton-cg','lbfgs'和'sag'只能处理L2正则化,而'liblinear'和'saga'可以处理L1正则化,原因在上面已经提到。
“liblinear”在LogisticRegressionCV中可能会更慢,因为它不处理热启动。
请注意,“sag”和“saga”快速收敛仅在具有大致相同比例的特征上得到保证。可以使用sklearn.preprocessing中的缩放器预处理数据。
-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了。
-class_weight,可以自己设置为dict形式(即{0:0.2,1:0.8}此种形式,为每个类别赋权)或者为‘balanced’,默认为None。这个参数是来确定类别权重的。
当默认None不填的时候,即不考虑权重,或者说所有类型的权重一样。
当自定义dict的时候,则按照自定义的权重。
当选择‘balanced’的时候,那么类库会根据训练样本量来计算权重。某种类型样本量越多,则权重越低,样本量越少,则权重越高。
那么class_weight有什么作用呢?在分类模型中,我们经常会遇到两类问题:
第一种是误分类的代价很高。比如对合法用户和非法用户进行分类,将非法用户分类为合法用户的代价很高,我们宁愿将合法用户分类为非法用户,这时可以人工再甄别,但是却不愿将非法用户分类为合法用户。这时,我们可以适当提高非法用户的权重。
第二种是样本是高度失衡的,比如我们有合法用户和非法用户的二元样本数据10000条,里面合法用户有9995条,非法用户只有5条,如果我们不考虑权重,则我们可以将所有的测试集都预测为合法用户,这样预测准确率理论上有99.95%,但是却没有任何意义。这时,我们可以选择balanced,让类库自动提高非法用户样本的权重。
提高了某种分类的权重,相比不考虑权重,会有更多的样本分类划分到高权重的类别,从而可以解决上面两类问题。
当然,对于第二种样本失衡的情况,我们还可以考虑用下一节讲到的样本权重参数: sample_weight,而不使用class_weight。sample_weight在下一节讲。
-sample_weight,这个参数不是在模型训练时需要设定的参数,而是在fit时,可能会用到的。为数组array格式。
由于样本可能存在不失衡的问题,导致样本不是总体样本的无偏估计,从而可能导致我们的模型预测能力下降。遇到这种情况,我们可以通过调节样本权重来尝试解决这个问题。调节样本权重的方法有两种,第一种是在class_weight使用balanced。第二种是在调用fit函数时,通过sample_weight来自己调节每个样本权重。
在scikit-learn做逻辑回归时,如果上面两种方法都用到了,那么样本的真正权重是class_weight*sample_weight.
其它通用参数介绍:
-dual,布尔型,默认值是False。
Ture时,表示使用dual formulation,仅仅适用于liblinear且L2正则化时。
False时,表示使用primal formulation,当n_samples > n_features,首选False。
-tol,浮点型,默认值为1e-4,该参数用于指定判断算法收敛的阈值。
-fit_intercept,布尔型,默认值为True,指定是否应将常量(即平常所说的偏差或截距)添加到决策函数中。
-intercept_scaling,浮点型,默认为1。
只有当使用liblinear且fit_intercept设置为ture的时候,该参数才有用。
在这种情况下,x变为[x,intercept_scaling],即一个“合成”特征被附加到实例向量中, 该“合成”特征的常数值等于intercept_scaling。
截距变为intercept_scaling * synthetic_feature_weight。
注意! 合成特征权重与所有其他特征一样,需经过L1 / L2正则化。 为了减小正则化对合成特征权重(并因此对截距)的影响,必须增加intercept_scaling。
-random_state,可选,可以是int整数型,也可以是RandomState instance, 或者是 None。默认是None。只有当solver选择‘sag’ 或者是‘liblinear’时使用。
该参数表示在随机数据混洗时使用的伪随机数生成器的种子。
如果是int,则random_state是随机数生成器使用的种子;
如果是RandomState实例,则random_state是随机数生成器;
如果为None,则随机数生成器是np.random使用的RandomState实例。
-max_iter,整数型,默认值为100。仅适用于solver选择newton-cg,sag和lbfgs时,表示求解器收敛的最大迭代次数。
-verbose,整数型,默认值为0,适用于solver选择liblinear或bfgs时,将verbose设置为任何正数以表示冗长度。
-n_jobs,整数型,默认值为1,仅适用于multi_class=ovr时,用于指定并行运算的CPU数量。且,需要注意的是,如果solver选择liblinear,则不管multi_class设置为ovr或multinomial,这个参数都会被忽略。
如果给定值为-1,则使用所有CPU。
LogisticRegression个性化参数介绍:
-C,浮点型,默认值为1.0。该参数表示正则化的惩罚系数。应该是一个正的浮点数。
-warm_start,布尔型,默认值为False。
设置为True时,下次训练是以追加的形式进行,否则,就会重新全部计算。
warm_start对于liblinear没用,支持lbfgs,newton-cg,sag,saga。
LogisticRegressionCV个性化参数介绍:
-Cs,一个整数型或浮点型数的列表,默认为10。
Each of the values in Cs describes the inverse of regularization strength. If Cs is as an int, then a grid of Cs values are chosen in a logarithmic scale between 1e-4 and 1e4. Like in support vector machines, smaller values specify stronger regularization.
-cv,可以是整数型,或者是一个交叉验证生成器,默认为None.
默认的交叉验证生成器是分层K-Folds。
如果设定为某一整数,则它代表使用的折叠数(即我们说的10折交叉验证之类的。)
-refit,布尔型,默认为Ture。
If set to True, the scores are averaged across all folds, and the coefs and the C that corresponds to the best score is taken, and a final refit is done using these parameters.
Otherwise the coefs, intercepts and C that correspond to the best scores across folds are averaged.
我的理解是,如果选择ture,则coefs和c的值是在多次交叉验证中,选择表现最好的那组参数值。如果是false,则coefs和c的值是取多次交叉验证过程中,得到的多组参数值的平均数。(望指正!)
参考文献:
官方说明文档LogisticRegression
官方说明文档LogisticRegressionCV
刘建平博客:scikit-learn 逻辑回归类库使用小结 以及 逻辑回归原理小结