Logistic Regression(逻辑回归)属于监督学习算法, 它是一种概率估计, 通过最优化算法(如梯度上升算法)来确定最佳回归系数, 根据回归系数建立分类边界线, 对训练集进行分类.

 优点

 计算代价不高, 易于理解和实现

 缺点

 容易欠拟合, 分类精度可能不高

 适用数据类型

 数值型, 标称型

基础概念

1.回归在数学上来说是给定一个点集, 能够用一条曲线去拟合之; 如果这个曲线是一条直线, 那就被称为线性回归, 如果曲线是一条二次曲线, 就被称为二次回归. [1]

2.Heaviside step function(海维塞德阶跃函数, 单位阶跃函数), 它的输出只有 0 和 1, 且存在跳跃点, 如图:

线性回归一阶二阶自由度 一阶回归和二阶回归_线性回归

3. Sigmoid 函数 是一个 S 形函数, 公式为f(x)=1/(1*exp(-x)), 它能连续逼近 0 和 1, 故可用来替代 Heaviside step function.

4. 梯度上升算法, 确保函数值沿着最快增长方向进行迭代, 具体参考[1] (待补充)

算法描述 1. 在只有两个分类的情况下, 我们希望有一个函数, 能够接收一定的输入, 然后通过输出 0 或 1 来表示当前输入是属于哪个分类;2. 文中使用的是 Sigmoid 函数, 对于计算出来的 f(z), 来对 z 进行分类, f(z) > 0.5 时为 1 类, f(z) < 0.5 时为 0 类; 如果使用 Heaviside step function, 那么算出来的结果不是 0 就是 1, 很难进行回归系数调整;3. 问题转为用函数来拟合 Sigmoid函数 的输入 z, 而 z = W0*X0 + W1*X1 + ... + Wn*Xn ①; 故本算法的核心就是求出最佳的 (W0, W1, W2..., Wn), 使得 ① 中求出的 z 代入 Sigmoid 函数后得到的分类正确率尽可能高;4. 本文先假设 (W0, W1, W2.., Wn) 全为 1, 计算出在此回归系数下各个 X1, X2 对应的 Sigmoid 函数的值, 再根据这个值按梯度方向调整回归系数, 直至误差小于一定值或达到循环次数为止. (代码 33-37 行)

算法流程图代码

# -*- coding: utf-8 -* 
from numpy import *

# 加载数据, 前两列是点所属的 X1, X2 坐标, 最后一列是该点所属分类
def loadDataSet():
    dataMat = []; labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        # 因为线性回归化式为 H(x) = W0 + W1*X1 + W2*X2 
        # 即为 (W0, W1, W2)*(1, X1, X2), 其中 (W0, W1, W2) 即为所求回归系数 W
        # 为了方便计算, 读出 X1, X2 后要在前面补上一个 1.0
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat


# sigmoid 函数
def sigmoid(inX):
    return 1.0/(1+exp(-inX))


# 梯度上升算法计算出最佳回归系数
def gradAscent(dataMatIn, classLabels):
    dataMatrix = mat(dataMatIn)             # convert to NumPy matrix
    labelMat = mat(classLabels).transpose() # convert to NumPy matrix
    m,n = shape(dataMatrix)
    alpha = 0.001                           # 步长
    maxCycles = 500                         # 循环次数
    weights = ones((n,1))                   # 回归系数初始化为 1

    # 循环 maxCycles 次, 每次都沿梯度向真实值 labelMat 靠拢
    for k in range(maxCycles):              # heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     # matrix mult
        error = (labelMat - h)              # vector subtraction
        # dataMatrix.transpose()* error 就是梯度f(w)
        weights = weights + alpha * dataMatrix.transpose()* error # matrix mult
    return weights


# 1. 画出各个训练点
# 2. 根据 weights(即回归的各个参数) 画出直线, 以便直观的看到划分是否正确
def plotBestFit(weights):
    import matplotlib.pyplot as plt
    # 画点
    dataMat,labelMat=loadDataSet()
    dataArr = array(dataMat)
    n = shape(dataArr)[0] 
    xcord1 = []; ycord1 = []
    xcord2 = []; ycord2 = []
    for i in range(n):
        if int(labelMat[i])== 1:
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
        else:
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
    ax.scatter(xcord2, ycord2, s=30, c='green')

    # 画线
    x1 = arange(-3.0, 3.0, 0.1)   # x1 取值区间为 [-3.0, 3.0), 步长为 0.1
    # 根据公式 0 = W0*X0 + W1*X1 + W2*X2 及 X0 = 1 
    x2 = (-weights[0]-weights[1]*x1)/weights[2]
    ax.plot(x1, x2)
    plt.xlabel('X1'); plt.ylabel('X2');

    # 显示
    plt.show()

    
if __name__ == "__main__":
    dataAttr, labelMat = loadDataSet()
    weights = gradAscent(dataAttr, labelMat)
    plotBestFit(weights.getA())
# -*- coding: utf-8 -* 
from numpy import *

# 加载数据, 前两列是点所属的 X1, X2 坐标, 最后一列是该点所属分类
def loadDataSet():
    dataMat = []; labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        # 因为线性回归化式为 H(x) = W0 + W1*X1 + W2*X2 
        # 即为 (W0, W1, W2)*(1, X1, X2), 其中 (W0, W1, W2) 即为所求回归系数 W
        # 为了方便计算, 读出 X1, X2 后要在前面补上一个 1.0
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat


# sigmoid 函数
def sigmoid(inX):
    return 1.0/(1+exp(-inX))


# 梯度上升算法计算出最佳回归系数
def gradAscent(dataMatIn, classLabels):
    dataMatrix = mat(dataMatIn)             # convert to NumPy matrix
    labelMat = mat(classLabels).transpose() # convert to NumPy matrix
    m,n = shape(dataMatrix)
    alpha = 0.001                           # 步长
    maxCycles = 500                         # 循环次数
    weights = ones((n,1))                   # 回归系数初始化为 1

    # 循环 maxCycles 次, 每次都沿梯度向真实值 labelMat 靠拢
    for k in range(maxCycles):              # heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     # matrix mult
        error = (labelMat - h)              # vector subtraction
        # dataMatrix.transpose()* error 就是梯度f(w)
        weights = weights + alpha * dataMatrix.transpose()* error # matrix mult
    return weights


# 1. 画出各个训练点
# 2. 根据 weights(即回归的各个参数) 画出直线, 以便直观的看到划分是否正确
def plotBestFit(weights):
    import matplotlib.pyplot as plt
    # 画点
    dataMat,labelMat=loadDataSet()
    dataArr = array(dataMat)
    n = shape(dataArr)[0] 
    xcord1 = []; ycord1 = []
    xcord2 = []; ycord2 = []
    for i in range(n):
        if int(labelMat[i])== 1:
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
        else:
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
    ax.scatter(xcord2, ycord2, s=30, c='green')

    # 画线
    x1 = arange(-3.0, 3.0, 0.1)   # x1 取值区间为 [-3.0, 3.0), 步长为 0.1
    # 根据公式 0 = W0*X0 + W1*X1 + W2*X2 及 X0 = 1 
    x2 = (-weights[0]-weights[1]*x1)/weights[2]
    ax.plot(x1, x2)
    plt.xlabel('X1'); plt.ylabel('X2');

    # 显示
    plt.show()

    
if __name__ == "__main__":
    dataAttr, labelMat = loadDataSet()
    weights = gradAscent(dataAttr, labelMat)
    plotBestFit(weights.getA())

运行结果

待补充1. 随机梯度上升2. 改进的随机梯度上升3. 处理数据中的缺失值 4. 为什么有这个算法

说明本文为《Machine Leaning in Action》第五章(Logistic regression)读书笔记, 代码稍作修改及注释.