逻辑斯谛回归(logistic regression)

时间:2021-07-14 23:50:48

理论讲解

对于二分类问题,输出标记为 y { 0 , 1 } ,0表示负向类,1表示正向类。logistic regression不是一个回归问题,而是一个分类问题。需要通过一个函数将线性回归模型 w T x + b 的输出值映射到 [ 0 , 1 ] 范围内,这个函数就是对数几率函数(logistic function),也称为sigmoid函数:

ϕ ( z ) = 1 1 + e z

对某个样本 x ,预测概率为
y = 1 1 + e ( w T x + b )
,即
w T x + b = l n y 1 y
,其中 y 是样本正例的可能性, 1 y 是反例可能性, y 1 y 作为正例的相对可能性,成为几率。对几率取对数则得到了对数几率 l n y 1 y
对于线性回归问题,定义的函数为所有模型误差的平方和。但是对于逻辑回归来说,这样定义所得的代价函数为非凸函数,容易陷入局部最优。代价函数为:
J ( w ) = 1 m i = 1 m [ y ( i ) l o g ( ϕ ( z ( i ) ) ) ( 1 y ( i ) ) l o g ( 1 ϕ ( x ( i ) ) ) ]

J ( ϕ ( z ) , y ) { l o g ( ϕ ( z ) )       i f   y = 1 l o g ( 1 ϕ ( z ) )       i f   y = 0

逻辑斯谛回归(logistic regression)
如图所示。若样本正确被划分为类别1中,代价将趋向于0;若样本正确被划分为类别0中,代价将趋向于0;反正将趋向于无穷大
代价函数的推导:
在构建模型时,定义最大似然函数 L ( w ) ,最大似然函数的入门参照: https://blog.csdn.net/winycg/article/details/80294225,公式如下:
L ( w a ) = i = 1 n p ( y ( i ) | x ( i ) ; w ) = i = 1 n ( ϕ ( z ( i ) ) ) y ( i ) ( 1 ϕ ( z ( i ) ) ) ) 1 y ( i )

将其取对数似然方程:
log L ( w ) = i = 1 n [ y ( i ) log ( ϕ ( z ( i ) ) ) + ( 1 y ( i ) ) log ( 1 ϕ ( z ( i ) ) ) ]

样本的最大似然函数值 log L ( θ ) 越大,表明预测越准确。在似然函数值非常小的时候,使用对数函数可以避免数值溢出;其次可以将各因子的连乘转换为和的形式,便于求导。将 L ( w ) 取反,就可以得到误差函数 J ( θ ) = 1 n log L ( w )

梯度下降更新公式推导:
首先计算sigmoid函数的偏导:

z ϕ ( z ) = e z ( 1 + e z ) 2 = 1 1 + e z ( 1 1 1 + e z ) = ϕ ( z ) ( 1 ϕ ( z ) )

计算对数似然函数对第 j 个权重的偏导:
w j J ( w ) = 1 n i = 1 n [ y ( i ) 1 ϕ ( z ( i ) ) ϕ ( z ( i ) ) ( 1 ϕ ( z ( i ) ) ) x j i ( 1 y ( i ) ) 1 1 ϕ ( z ( i ) ) ϕ ( z ( i ) ) ( 1 ϕ ( z ( i ) ) ) x j i ] = 1 n i = 1 n [ y ( i ) ( 1 ϕ ( z ( i ) ) ) x j i ( 1 y ( i ) ) ϕ ( z ( i ) ) x j i ] = 1 n i = 1 n [ ϕ ( z ( i ) ) y ( i ) ] x j i

w j := w j η J ( w ) w j = w j η i = 1 n [ ϕ ( z ( i ) ) y ( i ) ] x j i

多类别分类
逻辑斯谛回归(logistic regression)
现在我们有一个训练集, 好比上图表示的有三个类别, 我们用三角形表示 y=1, 方框表示 y=2, 叉叉表示 y=3。 我们下面要做的就是使用一个训练集, 将其分成三个二元分类问题。
先从用三角形代表的类别 1 开始, 实际上我们可以创建一个, 新的”伪”训练集, 类型 2 和类型 3 定为负类, 类型 1 设定为正类, 我们创建一个新的训练集, 如下图所示的那样, 我们要拟合出一个合适的分类器。
逻辑斯谛回归(logistic regression)
这里的三角形是正样本, 而圆形代表负样本。 可以这样想, 设置三角形的值为 1, 圆形的值为 0, 下面我们来训练一个标准的逻辑回归分类器, 这样我们就得到一个正边界。
为了实现这样的转变,将多个类中的一个类标记为正向类( y = 1 ),然后将其他所有类都标记为负向类,此模型记为 ϕ ( 1 ) ( z ) 。类似地第我们选择另一个类标记为正向类 y = 2 ,再将其它类都标记为负向类,将这个模型记作 ϕ ( 2 ) ( z ) ,依次类推
最后得到的一系列模型记为:

ϕ ( k ) ( z ) = p ( y = k | x ; w ) , k = 1 , 2 , 3 ,

需要做预测时,我们将所有的分类机都运行一遍,然后对每一个输入变量,都选择最高可能性的输出变量。即让3个分类器都输入 x ,选择一个使得 ϕ ( k ) ( z ) 最大的 k ,即
max k ϕ ( k ) ( z )

利用scikit-learn实现逻辑回归

在模型中,使用了L2正则化防止过拟合并减少模型复杂度,即误差函数为:

J ( w ) = 1 n i = 1 n [ y ( i ) log ( ϕ ( z ( i ) ) ) + ( 1 y ( i ) ) log ( 1 ϕ ( z ( i ) ) ) ] + λ 2 n j = 1 n w j
,一般偏置项 w 0 不做正则化处理, λ 为正则化系数。Logistic regression模型中的 C 为正则化系数的倒数:
C = 1 λ

在多类别分类数据集上使用Logistic Regression对象,默认使用一对多(One-vs-Rest, OvR)的方法。一共有3个截距项,其中第一个截距项为类别0相对于类别1,2的匹配结果,第二个截距项为类别1相对于类别0,2的匹配结果,第三个截距项为类别2相对于类别0,1的匹配结果。
权重数组包含三个权重系数向量,每一个权重向量对应一个分类。由于样本包含2个特征值,所以每个向量包括2个权重值,通过与数据集中的特征数据相乘来计算模型的净输入:
z = w 1 x 1 + w 2 x 2 + b

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression


# test_idx为测试数据编号
def plot_decision_regions(X, y, classifier, test_idx=None):

    # setup marker generator and color map
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'grey', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # plot the decision region
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, 0.02), np.arange(x2_min, x2_max, 0.02))
    z = classifier.predict(np.array([xx1.flatten(), xx2.flatten()]).T)
    z = z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, z, cmap=cmap, alpha=0.3)
    plt.xlim(x1_min, x1_max)
    plt.ylim(x2_min, x2_max)

    # plot class samples
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], cmap=cmap(idx), marker=markers[idx], label=cl, alpha=1)

    if test_idx:
        X_test, y_test = X[test_idx, :], y[test_idx]
        plt.scatter(X_test[:, 0], X_test[:, 1], c='cyan', alpha=1.0,
                    linewidth=1, marker='^', s=55, label='test set')
    plt.legend(loc='best')
    plt.title('Adaline-梯度下降法', fontproperties='SimHei')
    plt.xlabel('经标准化处理的萼片宽度', fontproperties='SimHei')
    plt.ylabel('经标准化处理的花瓣宽度', fontproperties='SimHei')


iris = datasets.load_iris()
X = iris.data[:, [2, 3]]  # 维度:(150,2)
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=0)

sc = StandardScaler()
sc.fit(X_train)  # 计算训练数据的均值和标准差
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)

X_combined_std = np.vstack((X_train_std, X_test_std))
y_combined = np.hstack((y_train, y_test))
LR = LogisticRegression(C=1000.0, random_state=0)
LR.fit(X_train_std, y_train)
plot_decision_regions(X=X_combined_std,
                      y=y_combined,
                      classifier=LR,
                      test_idx=range(105, 150))
print(LR.predict_proba(X_test_std[0:2, :]))  
''' 展示2个样本对于3个类别的准确率: [[2.05743774e-11 6.31620264e-02 9.36837974e-01] [6.08753106e-04 9.99285569e-01 1.05678028e-04]] '''
print(LR.coef_)
''' 权重向量: [[-7.34015187 -6.64685581] [ 2.54373335 -2.3421979 ] [ 9.46617627 6.44380858]] '''
print(LR.intercept_)
''' 截距项: [-9.31757401 -0.89462847 -8.85765974] '''
print('Test Accuracy:', LR.score(X_test_std, y_test))
# Test Accuracy: 0.9777777777777777
plt.show()

逻辑斯谛回归(logistic regression)