Logistic回归是一种广义线性回归模型,解决的是分类问题。其思想是运用对数几率函数将线性回归 ( − ∞ , + ∞ ) (-\infty,+\infty) (−∞,+∞)的实数预测值转化为 ( 0 , 1 ) (0,1) (0,1)之间的值,并视该值为正反例的概率对类别进行预测。
对数几率函数(logistic function)
y = 1 1 + e − z y=\dfrac{1}{1+e^{-z}} y=1+e−z1
其中 z ∈ ( − ∞ , + ∞ ) z\in(-\infty,+\infty) z∈(−∞,+∞), y ∈ { 0 , 1 } y\in\{0,1\} y∈{0,1}, z = w T x + b z=w^Tx+b z=wTx+b表示线性回归模型。经过对数变换可得
ln y 1 − y = w T x + b \ln\frac{y}{1-y}=w^Tx+b ln1−yy=wTx+b
y y y代表正例的可能性, 1 − y 1-y 1−y代表反例的可能性, y 1 − y \dfrac{y}{1-y} 1−yy称为几率(odds), ln ( y 1 − y ) \ln(\dfrac{y}{1-y}) ln(1−yy)称为对数几率(log odds,亦称logit)。所以这个模型也叫对数几率回归模型(Logistic Regression)。
将 y y y视为后验概率估计 p ( y = 1 ∣ x ) p(y=1|x) p(y=1∣x), 1 − y 1-y 1−y视为 p ( y = 0 ∣ x ) p(y=0|x) p(y=0∣x),则有
p ( y = 1 ∣ x ) = e w T x + b 1 + e w T x + b p ( y = 0 ∣ x ) = 1 1 + e w T x + b \begin{array}{l} p(y=1|x)=\dfrac{e^{w^Tx+b}}{1+e^{w^Tx+b}} \\ \\ p(y=0|x)=\dfrac{1}{1+e^{w^Tx+b}} \end{array} p(y=1∣x)=1+ewTx+bewTx+bp(y=0∣x)=1+ewTx+b1
通过极大似然法来估计 w w w和 b b b,即令每个样本属于其真实标记的概率越大越好。
ℓ ( w , b ) = ∑ i = 1 m ln p ( y i ∣ x i    ; w , b ) \ell(w,b)=\sum_{i=1}^{m}{\ln p(y_i|x_i\;;w,b)} ℓ(w,b)=i=1∑mlnp(yi∣xi;w,b)
令 β = ( w    ; b ) , x ^ = ( x    ; 1 ) \beta=(w\;;b), \hat x=(x\;;1) β=(w;b),x^=(x;1),则 w T x + b = β T x ^ w^Tx+b=\beta^T\hat x wTx+b=βTx^。令 p 1 ( x ^    ; β ) = p ( y = 1 ∣ x ^    ; β ) , p 0 ( x ^    ; β ) = p ( y = 0 ∣ x ^    ; β ) p_1(\hat x\;;\beta)=p(y=1|\hat x\;;\beta), p_0(\hat x\;;\beta)=p(y=0|\hat x\;;\beta) p1(x^;β)=p(y=1∣x^;β),p0(x^;β)=p(y=0∣x^;β),则
ln p ( y i ∣ x i    ; w , b ) = ln ( y i p 1 ( x ^ i    ; β ) + ( 1 − y i ) p 0 ( x ^ i    ; β ) ) = ln ( y i e β T x ^ 1 + e β T x ^ + 1 − y i 1 + e β T x ^ ) = ln ( y i e β T x ^ i + 1 − y i ) − ln ( 1 + e β T x ^ i ) = { − ln ( 1 + e β T x ^ i ) , y i = 0 β T x ^ i − ln ( 1 + e β T x ^ i ) , y i = 1 \begin{array}{l} \ln p(y_i|x_i\;;w,b)=\ln(y_ip_1(\hat x_i\;;\beta)+(1-y_i)p_0(\hat x_i\;;\beta)) \\ \\ =\ln(\dfrac{y_ie^{\beta^T\hat x}}{1+e^{\beta^T\hat x}}+\dfrac{1-y_i}{1+e^{\beta^T\hat x}}) \\ \\ =\ln(y_ie^{\beta^T\hat x_i}+1-y_i)-\ln(1+e^{\beta^T\hat x_i}) \\ \\ =\begin{cases} -\ln(1+e^{\beta^T\hat x_i}),\quad y_i=0 \\ \beta^T\hat x_i-\ln(1+e^{\beta^T\hat x_i}),\quad y_i=1 \\ \end{cases} \end{array} lnp(yi∣xi;w,b)=ln(yip1(x^i;β)+(1−yi)p0(x^i;β))=ln(1+eβTx^yieβTx^+1+eβTx^1−yi)=ln(yieβTx^i+1−yi)−ln(1+eβTx^i)={−ln(1+eβTx^i),yi=0βTx^i−ln(1+eβTx^i),yi=1
所以就变成了最小化
ℓ ( β ) = ∑ i = 1 m ( − y i β T x ^ i + ln ( 1 + e β T x ^ i ) ) \ell(\beta)=\sum_{i=1}^{m}{(-y_i\beta^T\hat x_i+\ln(1+e^{\beta^T\hat x_i}))} ℓ(β)=i=1∑m(−yiβTx^i+ln(1+eβTx^i))
ℓ ( β ) \ell(\beta) ℓ(β)是关于 β \beta β的高阶可导连续凸函数,根据凸优化理论,梯度下降法、牛顿法等可求得其最优解
β ∗ = arg min β ℓ ( β ) \beta^*=\mathop{\arg\min_\beta}\ell(\beta) β∗=argβminℓ(β)
以梯度下降法为例,第 t + 1 t+1 t+1轮的更新公式
β t + 1 = β t − α ∂ ℓ ( β ) ∂ β t \beta_{t+1}=\beta_t-\alpha\dfrac{\partial \ell(\beta)}{\partial\beta_t} βt+1=βt−α∂βt∂ℓ(β)
迭代直到阈值即可求出 β \beta β的数值解。
多分类学习的思想是"拆解法",将多分类任务拆为若干个二分类任务求解。
One vs. One,简称OvO。
给定数据集 D = { ( x i , y i ) } i = 1 m , y i ∈ { C 1 , C 2 , … , C N } D=\{(x_i,y_i)\}_ {i=1}^m,y_i\in\{C_1,C_2,\ldots,C_N\} D={(xi,yi)}i=1m,yi∈{C1,C2,…,CN},将这N个类别两两配对,从而产生N(N-1)/2个二分类任务,训练得到N(N-1)/2个分类器。将新样本同时提交给所有分类器,将得到N(N-1)/2个分类结果,最终结果可投票产生:即把被预测得最多的类别作为最终分类结果。
One vs. Rest,简称OvR。
每次将一个类的样例作为正例、所有其他类的样例作为反例,可训练得到N个分类器。对于新样本,若仅有一个分类器预测为正类,则最终分类结果为正类;若有多个分类器预测为正类,则通常考虑各分类器的预测置信度,选择置信度最大的类别标记作为分类结果。
Many vs. Many,简称MvM。
每次将若干个类作为正类,若干个其他类作为反类,但正、反类构造必须有特殊的设计,最常用的是"纠错输出码"(Error Correcting Output Codes,简称ECOC)。
ECOC分两步:
类别划分通过"编码矩阵"指定,编码矩阵常用二元码和三元码。二元码将每个类别指定为正类和负类,三元码还有一个停用类,表示该学习器不使用这一类的样本进行训练。
比如上图中,数据集有4(N)个分类,第一步编码做了5(M)次划分,训练出5个分类器 f 1 , f 2 , … , f 5 f_1,f_2,\ldots,f_5 f1,f2,…,f5,训练 f 1 f_1 f1的数据集是将第2类划分为正类,第1、3、4类划分为负类。5个分类器分别对测试样本作出的预测组成了预测编码(-1,-1,+1,-1,+1),这个预测编码再与每个类别的编码计算距离,比如第1类的编码是(-1,+1,-1,+1,+1),预测编码与第1类编码的欧氏距离就是 ( − 1 − ( − 1 ) ) 2 + ( − 1 − 1 ) 2 + ( 1 − ( − 1 ) ) 2 + ( − 1 − 1 ) 2 + ( 1 − 1 ) 2 = 2 3 \sqrt{(-1-(-1))^2+(-1-1)^2+(1-(-1))^2+(-1-1)^2+(1-1)^2}=2\sqrt3 (−1−(−1))2+(−1−1)2+(1−(−1))2+(−1−1)2+(1−1)2=23。
sklearn中关于实现Logistic回归的类是sklearn.linear_model.LogisticRegression,官方文档:https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression
下面是该类各参数、属性和方法的介绍,基本翻译自官方文档:
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=None, l1_ratio=None)
注意sklearn.linear_model.LogisticRegression()中提供了正则化惩罚项的参数,正则化是避免模型训练过拟合的重要手段,即在目标函数中加入一个正则化项
min f Ω ( f ) + C ∑ i = 1 m ℓ ( f ( x i ) , y i ) \min_f\Omega(f)+C\sum_{i=1}^{m}\ell(f(x_i),y_i) fminΩ(f)+Ci=1∑mℓ(f(xi),yi)
其中 Ω ( f ) \Omega(f) Ω(f)称为"结构风险",用于描述模型 f f f的某些性质; ∑ i = 1 m ℓ ( f ( x i ) , y i ) \sum_{i=1}^{m}\ell(f(x_i),y_i) ∑i=1mℓ(f(xi),yi)称为"经验风险",用于描述模型与训练数据的契合程度(也就是本模型中的 ℓ ( β ) \ell(\beta) ℓ(β)); C C C用于对二者进行折中。正则化可理解为对不希望得到的结果施以惩罚,降低过拟合的风险。 Ω ( f ) \Omega(f) Ω(f)称为正则化项, C C C为正则化常数。 L p L_p Lp范数是常用的正则化项( ∣ ∣ x ∣ ∣ p = ∑ i = 1 n ∣ x i ∣ p p ||x||_p=\sqrt[p]{\sum_{i=1}^{n}|x_i|^p} ∣∣x∣∣p=p∑i=1n∣xi∣p)。
Logistic回归在信用违约方面的运用是比较普遍的,信贷评分卡的基础模型就是Logistic回归模型。本例数据来源于机器学习竞赛平台Kaggle,一个关于信用违约的数据。数据地址:https://www.kaggle.com/singh001avinash/default-credit-card
数据一共10000个样例,3个字段。分类字段为default,一共分为了两类。数据集无缺失值,无错误值。字段及解释如下
该数据集特征数较少,仅作为Logistic回归的示范。 其中student字段取值为"Yes"和"No",需要先做哑变量处理。
import pandas as pd
import numpy as np
import os
from sklearn.linear_model import LogisticRegression
from sklearn import model_selection
from sklearn import metrics
import matplotlib.pyplot as plt
# 读取数据
path = os.path.join(os.getcwd(), 'credit_default.csv')
data = pd.read_csv(path)
# 设置正例和负例,便于后面画ROC曲线
data.default = data.default.map({'No': 0, 'Yes': 1})
# 哑变量处理
dummies = pd.get_dummies(data.student, prefix='student')
data.drop('student', axis=1, inplace=True)
data_new = pd.concat([data, dummies], axis=1)
x = data_new[data_new.columns[1:]]
y = data_new[data_new.columns[0]] # 本例第一列为分类标签
# 拆分为训练集和测试集
x_train, x_test, y_train, y_test = model_selection.train_test_split(x, y, test_size=0.25)
# 训练模型
lr = LogisticRegression()
lr.fit(x_train, y_train)
# 模型评估
# 准确率
print('模型准确率:', lr.score(x_test, y_test))
# ROC曲线
# y_score为模型预测正例的概率
y_score = lr.predict_proba(x_test)[:, 1]
# 计算不同阈值下,fpr和tpr的组合之,fpr表示1-Specificity,tpr表示Sensitivity
fpr, tpr, threshold = metrics.roc_curve(y_test, y_score)
# 计算AUC
roc_auc = metrics.auc(fpr, tpr)
# 绘制面积图
plt.stackplot(fpr, tpr, color='steelblue', alpha=0.5, edgecolor='black')
# 添加ROC曲线的轮廓
plt.plot(fpr, tpr, color='black', lw=1)
# 添加对角线作为参考线
plt.plot([0, 1], [0, 1], color='red', linestyle='--')
plt.text(0.5, 0.3, 'ROC curve (area=%0.2f)' % roc_auc)
plt.xlabel('1-Specificity')
plt.ylabel('Sensitivity')
plt.show()
最终得到模型的准确率为97%,但是AUC并不大。
参考文献:
[1]周志华.《机器学习》.清华大学出版社,2016-1
[2]https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html#sklearn.linear_model.LogisticRegression