逻辑回归算法梳理
逻辑回归与线性回归的联系与区别
区别:
- 逻辑回归解决的是分类问题,线性回归解决的是回归问题
- 逻辑回归的因变量是离散值,线性回归的因变量是连续值(屁话)
- 逻辑回归的因变量假设是服从伯努利分布的,而线性回归的因变量假设是服从正态分布的.
- 逻辑回归的损失函数采用的是最大似然,或者交叉熵,线性回归则会采用均方误差等方法(凑数的)
联系: - 逻辑回归是一种广义的线性回归,逻辑回归相当于对因变量p做$log\frac{p}{1-p}$之后做线性回归
- 都可以用梯度下降法求解(屁话)
- 都是判别式模型
- 损失函数都是凸函数,凸函数有个特点是局部最优就是全局最优
逻辑回归的原理
原理最浅显的应该就是说在线性回归的基础上作用一个sigmoid函数以使其能将值域落在[0,1]之间,以此来表示分类概率.
但是为什么用sigmoid好像很多博客里并没有提到,或者换句话说,为什么不用其他的也能将值域落在[0,1]之间且连续可微的函数?
简单的说,就是因为了一个假设,逻辑回归假设因变量服从伯努利分布.
伯努利分布与高斯分布都属于指数分布,在给定a,b,t时,y的概率分布表示为:
其中v为分布的自然参数;T(y)是充分统计量,通常T(y)=y
将伯努利分布表示为下式
则b(y)=1,$v=log\frac{\phi}{1-\phi}$,T(y)=y,$-a(v)=log(1-\phi)$
$\rightarrow \phi=\frac{1}{1+e^{-v}}$, 并且$a(v)=log(1+e^v)$
假设:(1)$y|x;\theta 服从 expFamily(v)$
(2) 给定x,输出E[T(y)|x]
(3)$v=\theta^Tx$
对于伯努利分布,有:
可以试着推一下softmax,很有趣!!
这应该才是真正的逻辑回归的原理吧
逻辑回归损失函数推导及优化
逻辑回归可以用极大似然作为目标函数,也可以对其取负对数用交叉熵来表示损失函数.
推导优化就是还是采用梯度下降的方法,就是一些求导计算,许多博客都有,这里不再赘述.
重点是为什么这里损失函数不能用均方误差等回归的损失函数?
分类问题概率化会使其因变量具有回归问题因变量的连续的性质,为什么我们不能就将其考虑成回归问题呢?
看一下这个sigmoid函数,有没有注意到它的问题???
这是一个非凸函数!!!如果采用均方误差的方法,目标函数还是非凸的,这会导致我们问题会陷入一系列局部最优解.
但是为什么cros entropy就可以了呢?看一下损失函数
可以画张图看看,这两个都是凸函数.
所以不采用均方误差的形式.
逻辑回归的工程应用经验
参考:https://www.jianshu.com/p/821194a77d22
样本处理
- 样本太大怎么处理
- 对特征离散化,离散化后用one-hot编码处理成0,1值,再用LR处理会较快收敛
- 如果一定要用连续值的话,可以做scaling
- 工具的话有spark Mllib,它损失了一小部分的准确度达到速度的提升
- 如果没有并行化平台,想做大数据就试试采样。需要注意采样数据,最好不要随机取,可以按照日期/用户/行为,来分层抽样
- 怎样使样本不平衡
- 如果样本不均衡,样本充足的情况下可以做“下采样”—-抽样,样本不足的情况下 做“上采样”—-对样本少的做重复
- 修改损失函数,给不同权重。比如负样本少,就可以给负样本大一点的权重
- 采样后的predict结果,用作判定请还原
关于特征处理
- 离散化优点:映射到高维空间,用linear的LR(快,且兼具更好的分割性);稀疏化,0,1向量内积乘法运算速度快,计算结果方便存储,容易扩展;离散化后,给线性模型带来一定的非线性;模型稳定,收敛度高,鲁棒性好;在一定程度上降低了过拟合风险
- 通过组合特征引入个性化因素:比如uuid+tag
- 注意特征的频度: 区分特征重要度,可以用重要特征产出层次判定模型
正则化与模型评估指标
正则化项
正则化项其实也蛮有意思,在判别模型中正则化项被认为是一种对权重的约束,或者说是避免权值过大或是过于复杂化.但是在生成模型中,正则化项会被认为是一种模型的先验信息(或者说是参数的先验分布).
这里涉及贝叶斯线性回归的问题就不细讲了(建议看PRML).
回到正则化项来讲,常见的有L1和L2正则化.L0正则化也有,相当于限制了参数的个数,但是这类条件属于NP-hard问题,求解比较困难.
L1与L2解的稀疏性问题:
这是经常能看到的一张图,一般不画图感觉很难解释清楚.这里的线都是等高线.假设L1/L2的值不变,我们会发现这个经验风险(绿色圈)与L1的交点更倾向于坐标轴,而经验风险(绿色圈)与L2的交点会倾向于中间,并且尽管两张图交点的位置不同,但它们的求和的结构风险值是一样.所以,我们可以解释,当结构风险值一样的时候,L1更倾向于稀疏(即靠近坐标轴上).而我们说L2更加平滑.
之前,看到群里提问,有说到过拟合的问题(训练效果佳,测试集下效果不佳),谈谈我的看法:
过拟合总的来说就是模型表达不充分的原因,现在常用的深度学习采用的是自动学习数据中的特征,所以一旦出现了模型在训练集中充分表达,而在测试集中表达不足的情况,大家想到的就是增加数据,让测试集中的一些数据特征也能被学习得到,这导致数据越来越多.实际上解决这种问题,不能并不能一上来就搞数据,毕竟在实际应用中数据是很难搞到的.还是要先从数据开始分析,分析我们的训练集数据和测试集数据,看看需不需要一些约束条件,像前面说的在贝叶斯线性回归中就是会假设参数的先验分布为高斯分布等.如果能用正则项解决就用正则项(一般人都是正则项解决不了了才会考虑加数据),如果不能可以考虑一下集成学习bagging的方法.如果还不行可以从模型的角度出发,看看是不是模型上有没有需要改进的.如果最后实在没办法,我们再考虑加数据.
模型评估指标
逻辑回归是一种分类问题,最常见的就是要计算混淆矩阵
混淆矩阵:
这个东西也常在Topk问题,目标检测问题中出现,谨记!!
之后会有精确率(Precision)和召回率(Recall)
注意准确率(accuracy)
我们以后常用的会是Precision和Recall,而accuracy会受数据不均衡影响没有什么卵用.
Precision和Recall会有个特点就是此消彼长
这还没完,它们还要用到P-R曲线(即Precision作为纵坐标,Recall作为横坐标),其曲线如下图所示:
不同的学习器往往对应于不同的曲线,若曲线能将另一个曲线包住,则说明前者强于后者.但在另外一种状况下,两曲线是相交的,此时评价方法有:
- “平衡点”(Break-Even Point,简称BEP),是比较当P=R的时候大小,大则优
- F1 score:$F1=\frac{2PR}{P+R}$,可以理解为P与R的几何平均
P-R曲线并不是完美的,P-R曲线在测试集样本中的正负样本的分布变化的时候会变化.因此引入了ROC,ROC的特点就是在测试集分布变化时仍然保持不变.
ROC的横纵坐标分别是:FPR(FP rate)和TPR(TP rate)
为了将ROC曲线能够数值化表示,引入了AUC,即为ROC下方的面积
显然这个面积的数值不会大于1。又由于ROC曲线一般都处于y=x这条直线的上方(y=x其实就是相当于随机分类器了),所以AUC的取值范围在0.5和1之间。使用AUC值作为评价标准是因为很多时候ROC曲线并不能清晰的说明哪个分类器的效果更好,而作为一个数值,对应AUC更大的分类器效果更好。
AUC最大的应用应该就是在CTR的离线评估.为什么AUC可以用来评价CTR?
- CTR是把分类器输出的概率当作点击率的概率,业界常用的就是LR模型,利用sigmoid函数将特征输入与概率输出关联起来,这个输出的概率就是点击率的预估值.内容的召回往往是根据CTR的排序来决定的
- AUC量化了ROC曲线表达的分类能力.这种分类能力是与概率、阈值紧密相关的,分类能力越好(AUC越大),那么输出概率越合理,排序的结果越合理.
我们不仅希望分类器能给出是否点击的分类信息,更需要分类器给出准确的概率值,作为排序的依据.所以这里的AUC就直观地反映了CTR的准确性(也就是CTR的排序能力)
其实还有一些评估标准,比如AP、mAP,见信息检索常用的评价标签MAP
逻辑回归的优缺点
优点:
- 形式简单,可解释性强
- 训练快,计算快(sigmoid的求导的特殊性)
- 内存资源占用小
缺点: - 准确率不高,容易欠拟合
(欢迎补充)样本不均衡问题解决办法
- 基于数据的方法——主要就是采样:包括欠采样和过采样
欠采样:从多数类样本集$S_{maj}中随机选取较少的样本(有放回或无放回)$.造成的问题,会丢弃一些样本,可能会损失本分有用信息,造成模型只学到了整体模式的一部分.(可以Easy Ensemble算法:每次从多数类$S_{maj}$中上随机抽取一个子集E(|E|≈|S_{min}|),然后用E+$S_{min}$训练该级的分类器;然后将$S_{maj}$中能够被当前分类器正确判别的样本剔除掉,继续下一级的操作,重复若干次得到级联结构;最终的输出结果就是各级分类器结果的融合)
过采样:从少数类样本集$S_{min}$中随机重复抽取样本(有放回)以得到更多样本.造成的问题是简单的复制样本,会导致过拟合.(可以用SMOTE算法生成一些新合成的样本)
此外,数据扩充也是一种过采样的方法.Hard Negative Mining则是一种欠采样方法,把比较难的样本抽出来用于迭代分类器(RCNN中有出现)。
- 基于算法的方法
可以改变模型训练时的目标函数,如代价敏感学习中不同类别有不同的权重来矫正这种不平衡性。
当样本数目极其不均衡时,也可以将问题转化为单类学习(one-class learning)、异常检测(iForest).
(1) 也可以用Ensemble的算法方法
(2)将任务转换成异常检测问题。譬如有这样一个项目,需要从高压线的航拍图片中,将松动的螺丝/零件判断为待检测站点,即负样本,其他作为正样本,这样来看,数据倾斜是非常严重的,而且在图像质量一般的情况下小物体检测的难度较大,所以不如将其转换为无监督的异常检测算法,不用过多的去考虑将数据转换为平衡问题来解决。
(3) Focal loss (在目标检测任务中用过,没错又是何凯明..)
sklearn参数
反正这一部分,我记不住,仅供查询1
2
3
4
5class 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)
- penalty=’l2’ : 字符串‘l1’或‘l2’,默认‘l2’。用来指定惩罚的基准(正则化参数)。只有‘l2’支持‘newton-cg’、‘sag’和‘lbfgs’这三种算法。 如果选择‘l2’,solver参数可以选择‘liblinear’、‘newton-cg’、‘sag’和‘lbfgs’这四种算法;如果选择‘l1’的话就只能用‘liblinear’算法。
- dual=False : 对偶或者原始方法。Dual只适用于正则化相为l2的‘liblinear’的情况,通常样本数大于特征数的情况下,默认为False。(不懂?????)
- C=1.0 : C为正则化系数λ的倒数,必须为正数,默认为1。和SVM中的C一样,值越小,代表正则化越强。
- fit_intercept=True : 是否存在截距,默认存在。
- intercept_scaling=1 : 仅在正则化项为‘liblinear’,且fit_intercept设置为True时有用。
- solver=’liblinear’ : solver参数决定了我们对逻辑回归损失函数的优化方法,有四种算法可以选择。
a) liblinear:使用了开源的liblinear库实现,内部使用了坐标轴下降法来迭代优化损失函数。
b) lbfgs:拟牛顿法的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
c) newton-cg:也是牛顿法家族的一种,利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
d) sag:即随机平均梯度下降,是梯度下降法的变种,和普通梯度下降法的区别是每次迭代仅仅用一部分的样本来计算梯度,适合于样本数据多的时候。 - multi_class=’ovr’ : 分类方式。
(a)ovr即one-vs-rest(OvR),multinomial是many-vs-many(MvM)。如果是二元逻辑回归,ovr和multinomial并没有任何区别,区别主要在多元逻辑回归上。ovr不论是几元回归,都当成二元回归来处理。mvm从从多个类中每次选两个类进行二元回归。如果总共有T类,需要T(T-1)/2次分类。OvR相对简单,但分类效果相对略差(大多数样本分布情况)。而MvM分类相对精确,但是分类速度没有OvR快。如果选择了ovr,则4种损失函数的优化方法liblinear,newton-cg,lbfgs和sag都可以选择。但是如果选择了multinomial,则只能选择newton-cg, lbfgs和sag了。 - class_weight=None : 类型权重参数。用于标示分类模型中各种类型的权重。默认不输入,即所有的分类的权重一样。选择‘balanced’自动根据y值计算类型权重。
自己设置权重,格式:{class_label: weight}。例如0,1分类的二元模型,设置class_weight={0:0.9, 1:0.1},这样类型0的权重为90%,而类型1的权重为10%。 - random_state=None : 随机数种子,默认为无。仅在正则化优化算法为sag,liblinear时有用。
- max_iter=100 : 算法收敛的最大迭代次数。
- tol=0.0001 : 迭代终止判据的误差范围。
- verbose=0 : 日志冗长度int:冗长度;0:不输出训练过程;1:偶尔输出; >1:对每个子模型都输出
- warm_start=False : 是否热启动,如果是,则下一次训练是以追加树的形式进行(重新使用上一次的调用作为初始化)。布尔型,默认False。
- n_jobs=1 : 并行数,int:个数;-1:跟CPU核数一致;1:默认值。
1 | LogisticRegression类的常用方法 |
例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28import numpy as np
from sklearn import linear_model, datasets
from sklearn.cross_validation import train_test_split
# 1.加载数据
iris = datasets.load_iris()
X = iris.data[:, :2] # 使用前两个特征
Y = iris.target
#np.unique(Y) # out: array([0, 1, 2])
# 2.拆分测试集、训练集。
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3, random_state=0)
# 设置随机数种子,以便比较结果。
# 3.标准化特征值
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
# 4. 训练逻辑回归模型
logreg = linear_model.LogisticRegression(C=1e5)
logreg.fit(X_train, Y_train)
# 5. 预测
prepro = logreg.predict_proba(X_test_std)
acc = logreg.score(X_test_std,Y_test)