本内容将介绍机器学习中的 Logistic 回归 及 Python 代码实现,和 Softmax 回归

  Logistic 回归(logistic regression,也称逻辑回归和对数几率回归)是一种经典的分类模型,属于广义的线性回归分析模型。虽然名称中包含了“回归”,但是实际上它不是回归模型,而是分类模型。

一、Logistic 回归

  在阅读本内容前,需要了解 线性回归模型 的基本概念。如果您还不了解,可以参阅 机器学习系列:线性回归模型。

  在 机器学习系列:线性回归模型 中介绍了如何使用线性模型进行回归预测。但是否可以进行分类预测呢?

Python构造logistic模型 logistic模型 python_Logistic 回归,线性回归模型产生的预测值 Python构造logistic模型 logistic模型 python_softmax 回归_02 是实值,于是我们需要将实值 Python构造logistic模型 logistic模型 python_Python构造logistic模型_03 转换为 Python构造logistic模型 logistic模型 python_softmax 回归_04

Python构造logistic模型 logistic模型 python_softmax 回归_05

即当 Python构造logistic模型 logistic模型 python_Python构造logistic模型_06 时输出 Python构造logistic模型 logistic模型 python_Python构造logistic模型_07(即正例),当 Python构造logistic模型 logistic模型 python_Logistic 回归_08 是输出 Python构造logistic模型 logistic模型 python_逻辑回归_09(即反例),当 Python构造logistic模型 logistic模型 python_softmax 回归_10 时可输出 Python构造logistic模型 logistic模型 python_逻辑回归_09Python构造logistic模型 logistic模型 python_Python构造logistic模型_07,如图-1所示。




Python构造logistic模型 logistic模型 python_Python构造logistic模型_13

图-1 单位阶跃函数与对数几率函数


  但从图-1 可看出,单位阶跃函数不连续。可以使用对数几率函数(logistic function)对其进行替换:

Python构造logistic模型 logistic模型 python_Python构造logistic模型_14

Python构造logistic模型 logistic模型 python_Python构造logistic模型_03 值转化为一个接近 Python构造logistic模型 logistic模型 python_逻辑回归_09Python构造logistic模型 logistic模型 python_Python构造logistic模型_07Python构造logistic模型 logistic模型 python_对数几率回归_18 值,并且其输出值在 Python构造logistic模型 logistic模型 python_softmax 回归_10

  我们知道线性回归模型为

Python构造logistic模型 logistic模型 python_Python构造logistic模型_20

其中 Python构造logistic模型 logistic模型 python_softmax 回归_21Python构造logistic模型 logistic模型 python_softmax 回归_22Python构造logistic模型 logistic模型 python_Logistic 回归_23。将其代入式(2),得到

Python构造logistic模型 logistic模型 python_softmax 回归_24



二、损失函数

2.1 损失函数

  对于二分类问题,单个样本的损失函数为

Python构造logistic模型 logistic模型 python_softmax 回归_25

等价于

Python构造logistic模型 logistic模型 python_Python构造logistic模型_26

其也称作为交叉熵代价函数

  对于训练集所有样本,其损失函数为

Python构造logistic模型 logistic模型 python_softmax 回归_27

  将式(6)代入式(7)得

Python构造logistic模型 logistic模型 python_Python构造logistic模型_28

  然后可以采用 梯度下降法(Gradient descent method) 或者 牛顿法(Newton method)求使 Python构造logistic模型 logistic模型 python_对数几率回归_29 取最小值的 Python构造logistic模型 logistic模型 python_Python构造logistic模型_30

Python构造logistic模型 logistic模型 python_Python构造logistic模型_31Python构造logistic模型 logistic模型 python_对数几率回归_29

2.2 最大似然估计

Python构造logistic模型 logistic模型 python_逻辑回归_33

Python构造logistic模型 logistic模型 python_逻辑回归_34

Python构造logistic模型 logistic模型 python_softmax 回归_35

  将式(9)和式(10)可简化为

Python构造logistic模型 logistic模型 python_逻辑回归_36

  则对应的似然函数为

Python构造logistic模型 logistic模型 python_Logistic 回归_37

Python构造logistic模型 logistic模型 python_对数几率回归_38

  则对数似然函数为

Python构造logistic模型 logistic模型 python_对数几率回归_39

Python构造logistic模型 logistic模型 python_逻辑回归_40 取最大值时的 Python构造logistic模型 logistic模型 python_Python构造logistic模型_30,我们可以使用 梯度上升法 求得最优的 Python构造logistic模型 logistic模型 python_Python构造logistic模型_30

  对比式(8)和式(14),我们发现存在以下关系

Python构造logistic模型 logistic模型 python_对数几率回归_43

Python构造logistic模型 logistic模型 python_Python构造logistic模型_30 时,求解 Python构造logistic模型 logistic模型 python_逻辑回归_40 的最大值或求解 Python构造logistic模型 logistic模型 python_softmax 回归_46 的最小值,两者实际上是一致的。

三、根据梯度下降法求解最优 Python构造logistic模型 logistic模型 python_Python构造logistic模型_30

  如果你还不了解梯度下降法,可以参阅 机器学习系列:梯度下降法及 Python 实现。

Python构造logistic模型 logistic模型 python_对数几率回归_48 中的每个 Python构造logistic模型 logistic模型 python_softmax 回归_49 求偏导数(即梯度),得到(注意:这里的 Python构造logistic模型 logistic模型 python_对数几率回归_50 的底为 Python构造logistic模型 logistic模型 python_对数几率回归_51

Python构造logistic模型 logistic模型 python_softmax 回归_52

Python构造logistic模型 logistic模型 python_softmax 回归_53 的具体求解过程,在下面的 3.1 求解 Python构造logistic模型 logistic模型 python_逻辑回归_54 会进行介绍。

Python构造logistic模型 logistic模型 python_softmax 回归_49

Python构造logistic模型 logistic模型 python_softmax 回归_56

其中 Python构造logistic模型 logistic模型 python_对数几率回归_57

3.1 Python构造logistic模型 logistic模型 python_softmax 回归_53

Python构造logistic模型 logistic模型 python_softmax 回归_53

Python构造logistic模型 logistic模型 python_softmax 回归_53 的求解需要用到 Python构造logistic模型 logistic模型 python_Logistic 回归_61。先来看一下 Python构造logistic模型 logistic模型 python_Logistic 回归_61

Python构造logistic模型 logistic模型 python_逻辑回归_63

Python构造logistic模型 logistic模型 python_对数几率回归_64

Python构造logistic模型 logistic模型 python_softmax 回归_65

Python构造logistic模型 logistic模型 python_softmax 回归_66

Python构造logistic模型 logistic模型 python_softmax 回归_67

Python构造logistic模型 logistic模型 python_对数几率回归_68

Python构造logistic模型 logistic模型 python_对数几率回归_69

Python构造logistic模型 logistic模型 python_Python构造logistic模型_70

Python构造logistic模型 logistic模型 python_softmax 回归_53 的求解过程:
Python构造logistic模型 logistic模型 python_逻辑回归_72

Python构造logistic模型 logistic模型 python_Python构造logistic模型_73

Python构造logistic模型 logistic模型 python_对数几率回归_74

Python构造logistic模型 logistic模型 python_逻辑回归_75

Python构造logistic模型 logistic模型 python_逻辑回归_76

Python构造logistic模型 logistic模型 python_逻辑回归_77



四、Python 代码实现

  下面使用批量梯度下降法拟合一个 Logistic 回归模型。代码如下(Python 3.x):

import numpy as np
import matplotlib.pyplot as plt


class LogisticRegression:
    def __init__(self):
        self.weights = None
        pass

    def __str__(self):
        return 'weights: {}'.format(self.weights)

    def _sigmoid(self, inx):
        """
        计算公式:1/(1 + exp(-inx))
        """
        return 1.0/(1+np.exp(-inx))

    def train(self, input_data, label_data, learning_rate, iteration):
        """
        进行模型训练

        :param input_data: 训练数据,特征值
        :param label_data: 训练数据,标签值
        :param learning_rate: 熟悉速率
        :param iteration: 迭代次数
        """
        # 使用 np.mat() 将 list 数据变更为 matrix,函数 transpose() 进行转置操作
        input_data_mat = np.mat(input_data)
        label_data_mat = np.mat(label_data).transpose()
        m, n = np.shape(input_data_mat)
        # 初始化 weights 为 1
        self.weights = np.ones((n, 1))
        # 使用批量梯度下降法进行训练
        for i in range(iteration):
            # 计算预测输出
            h = self._sigmoid(input_data_mat * self.weights)
            # 计算损失
            error = h - label_data_mat
            # 更新权值(阅读时,需要对矩阵操作有一定了解)
            self.weights -= (learning_rate * input_data_mat.transpose() * error)

    def get_weights(self):
        return self.weights


def load_data_set(file_name):
    """
    从文件中获取数据集

    :param file_name: 文件名
    :return: 返回从文件中获取的数据集
            input_data 存储特征值,label_data 存储标签值
    """
    input_data, label_data = [], []
    fr = open(file_name)
    for line in fr.readlines():
        cur_line = line.strip().split()
        # 在每列数据的第一列添加 1.0,供计算偏置 b 时使用
        input_data.append([1.0, float(cur_line[0]), float(cur_line[1])])
        label_data.append(int(cur_line[2]))
    return input_data, label_data


def plot_best_fit(input_data, label_data, weights):
    input_data_arr = np.array(input_data)
    x_cord_01, y_cord_01, x_cord_02, y_cord_02 = [], [], [], []
    for i in range(len(input_data)):
        if label_data[i] == 1:
            x_cord_01.append(input_data_arr[i][1])
            y_cord_01.append(input_data_arr[i][2])
        else:
            x_cord_02.append(input_data_arr[i][1])
            y_cord_02.append(input_data_arr[i][2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(x_cord_01, y_cord_01, s=30, c='red', marker='s')
    ax.scatter(x_cord_02, y_cord_02, s=30, c='green')
    x = np.arange(-3.0, 3.0, 0.1)
    y = (-weights[0] - weights[1]*x)/weights[2]
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()


def test_logistic_regression():
    # 测试 Logistic regression model,并且绘制出拟合图形
    input_data, label_data = load_data_set('testSet.txt')
    logistic_regression = LogisticRegression()
    logistic_regression.train(input_data, label_data, 0.001, 500)
    print(logistic_regression)
    plot_best_fit(input_data, label_data, logistic_regression.get_weights())


if __name__ == "__main__":
    test_logistic_regression()

运行以上代码,将打印如下信息及绘制如下图形:

weights: [[ 4.12414349]
 [ 0.48007329]
 [-0.6168482 ]]




Python构造logistic模型 logistic模型 python_Python构造logistic模型_78


五、多分类

  上面主要介绍了 Logistic 回归用于解决二分类问题。实际上,可以对 Logistic 回归进行扩展,用于解决多分类问题。下面将介绍两种方法。

5.1 多个 Logistic 回归

  将多分类任务拆分为若干个二分类任务进行求解。具体来说,先对问题进行拆分,然后为拆出的每个二分类任务训练一个分类器;在预测时,对这些分类器的预测结果进行集成以获得最终的多分类结果。最常用的拆分策略为:“一对一”(One vs One)、“一对其余”(One vs Rest)和“多对多”(Many vs Many)。

Python构造logistic模型 logistic模型 python_softmax 回归_79 个类别,“一对一”将为任意两个类别训练一个分类器,将存在 Python构造logistic模型 logistic模型 python_逻辑回归_80 个分类器。在预测时,将得到 Python构造logistic模型 logistic模型 python_逻辑回归_80

Python构造logistic模型 logistic模型 python_softmax 回归_79 个分类器。在预测时,根据这 Python构造logistic模型 logistic模型 python_softmax 回归_79

5.2 多项 Logistic 回归

  多项 Logistic 回归 也称为 Softmax 回归

Python构造logistic模型 logistic模型 python_对数几率回归_18 的取值集合是 Python构造logistic模型 logistic模型 python_softmax 回归_85,那么样本输出为 Python构造logistic模型 logistic模型 python_逻辑回归_86

Python构造logistic模型 logistic模型 python_逻辑回归_87

  参照二分类,可知损失函数为

Python构造logistic模型 logistic模型 python_Python构造logistic模型_88

其中,Python构造logistic模型 logistic模型 python_Python构造logistic模型_89 表示样本个数,Python构造logistic模型 logistic模型 python_softmax 回归_79 表示类别的个数;Python构造logistic模型 logistic模型 python_对数几率回归_91 函数表示:当 Python构造logistic模型 logistic模型 python_对数几率回归_92

Python构造logistic模型 logistic模型 python_对数几率回归_93。这里就不再详细介绍求解过程了。

5.3 选择原则

  解决多分类问题时,选择上面介绍的两种方法的具体原则:

  • 如果各类别之间是互斥的,适合选择使用 softmax 回归分类器;
  • 如果各类别之间不完全互斥,适合选择使用多个 Logistic 回归分类器。


参考:
[1] 周志华《机器学习》
[2] 李航《统计学习方法》
[3] 《机器学习实战》