机器学习——Logistic回归

定义

回归:假设现有一些数据点,用一条直线对这些点进行拟合(最佳拟合直线),拟合的过程就称作回归。

利用logistic回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类

logistic回归主要是进行二分类预测,也即是对于0~1之间的概率值,当概率大于0.5预测为1,小于0.5预测为0.

理论基础

  1. sigmoid方程
  • 在一个二分类问题中:
    • 能接受所有的输入然后预测出类别预测出类别。
    • The function spit out: 0 or 1.
    • 海维塞得阶跃函数(Heaviside step function),或者直接称为单位阶跃函数。
    • 海维塞得阶跃函数的问题在于: 该函数在跳跃点上从0瞬间跳跃到1,这个瞬间跳跃过程有时很难处理。
    • Sigmoid函数也有类似的性质(可以输出0或者1的性质),且数学上更易处理
  • 为了实现 Logistic 回归分类器,可以在每个特征上都乘以一个回归系数(如下公式所示),然后把所有结果值相加,将这个总和代入Sigmoid函数中,进而得到一个范围在 0~1 之间的数值。任何大于0.5的数据被分入1 类,小于
    0.5即被归入0类。Logistic回归也可以被看成是一种概率估计。
    z = ω 0 x 0 + ω 1 x 1 + ω 2 x 2 + . . . + ω n x n z = \omega_0x_0+\omega_1x_1+\omega_2x_2+...+\omega_nx_n z=ω0x0+ω1x1+ω2x2+...+ωnxn
  1. 使用最优化方法查找回归系数

为了寻找最佳的回归系数 ω \omega ω,这里使用梯度上升法。

梯度上升法基于的思想是:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。如果梯度记为∇,则函数f(x,y)的梯度由下式表示:
Δ f ( x , y ) = [ ∂ f ( x , y ) ∂ x ∂ f ( x , y ) ∂ y ] \Delta f(x,y) = \left[ \begin{matrix} \frac {\partial f(x,y)}{\partial x} \\ \frac {\partial f(x,y)}{\partial y}\end{matrix} \right] Δf(x,y)=[xf(x,y)yf(x,y)]

这个梯度意味着要沿x的方向移动 ∂ f ( x , y ) ∂ y \frac {\partial f(x,y)}{\partial y} yf(x,y)

沿y的方向移动 ∂ f ( x , y ) ∂ x \frac {\partial f(x,y)}{\partial x} xf(x,y)

其中,函数f (x,y)必须要在待计算的点上有定义并且可微。

梯度上升算法到达每个点后都会重新估计移动的方向。从P0开始,计算完该点的梯度,函数就根据梯度移动到下一点P1。在P1点,梯度再次被重新计算,并沿新的梯度方向移动到P2。如此循环迭代,直到满足停止条件。迭代的过程中,梯度算子总是保证我们能选取到最佳的移动方向。

梯度算子总是指向函数值增长最快的方向。这里所说的是移动方向,而未提到移动量的大小。该量值称为步长,记做α。用向量来表示的话,梯度上升算法的迭代公式如下:
ω : = ω + α Δ ω f ( ω ) \omega := \omega + \alpha \Delta_\omega f(\omega) ω:=ω+αΔωf(ω)
该公式将一直被迭代执行,直至达到某个停止条件为止,比如迭代次数达到某个指定值或算法达到某个可以允许的误差范围。

注:一般我们听到的都是梯度下降法,两着并没有什么区别,只是迭代公式符号发生改变
ω : = ω − α Δ ω f ( ω ) \omega := \omega - \alpha \Delta_\omega f(\omega) ω:=ωαΔωf(ω)

实例

  1. 训练梯度上升算法

(1)假设有100个样本点,每个样本有两个特征:x1和x2,此外为方便考虑,额外添加一个x0 = 1,将线性函数 z = ω T x + b z = \omega^Tx+b z=ωTx+b转为 z = ω T x z = \omega^Tx z=ωTx

#梯度上升法更新最优拟合参数
#@dataMatIn:数据集
#@classLabels:数据标签
def gradAscent(dataMatIn,classLabels):
    #将数据集列表转为Numpy矩阵
    dataMatrix = np.mat(dataMatIn)
    #将数据集标签列表转为Numpy矩阵,并转置
    labelMat = np.mat(classLabels).transpose()
    labelMat = np.array(list(map(float,labelMat)))
    #获取数据集矩阵的行数和列数
    col,row = np.shape(dataMatrix)
    #学习步长
    alpha = 0.001
    #最大迭代数
    maxCycles = 500
    #初始化权值参数向量每个维度为1.0
    weights = np.ones((row,1))
    #循环迭代次数
    for k in range(maxCycles):
        #求当前的digmoid函数预测概率
        h = sigmoid(dataMatrix*weights)
        #计算真实类别和预测类别的差值
        #对logistic回归函数的对数释然函数的参数项求偏导
        error = (labelMat - h)
        #更新权值参数
        weights = weights + alpha*dataMatrix.transpose()*error
    return weights

(2)绘制决策边界


  1. 随机梯度上升
  • 梯度上升法每次更新回归系数都需要遍历整个数据集(最大化所有训练样本的似然函数,求得全局最优解),当样本数量较小时,该方法尚可,但是当样本数据集非常大且特征非常多时,那么批量梯度下降法的计算复杂度就会特别高(迭代速度相当慢)。
  • 随机梯度上升:一种改进的方法是一次仅用一个样本点来更新回归系数(最优化每条样本的似然函数,虽然不是每次迭代得到的似然函数都是向着全局,但大体方向是对的、最终结果往往在全局最优附近、适合于大规模训练样本)。
    • 在新样本到来时对分类器进行增量式更新,随机梯度上升法是一个在线学习算法
#随机梯度上升算法
def stoGradAscent(dataMatrix,classLabels):
    #为方便计算,转为Numpy数组
    dataMat = np.array(dataMatrix)
    #将数据集标签列表转为Numpy矩阵,并转置
    labelMat = np.mat(classLabels).transpose()
    labelMat = np.array(list(map(float,labelMat)))
    #获取数据集的行和列
    col,row = np.shape(dataMat)
    #初始化权值向量各个参数为1.0
    weights = np.ones(row)
    #设置步长为0.01
    alpha = 0.01
    #循环col次,每次选取数据集一个样本更新参数
    for i in range(col):
        # 求当前样本的digmoid函数值
        h = sigmoid(dataMat[i] + weights)
        # 计算当前样本的残差(代替梯度)
        error = (labelMat[i] - h)
        # 更新权值参数
        weights = weights + alpha * dataMat[i] * error
    return weights
  1. 回归概率预测
def classifyVector(inX,weights):
    #计算logistic回归预测概率
    prob = sigmoid(np.sum(inX*weights))
    #大于0.5预测为1
    if prob > 0.5:
        return 1.0
    else:
        return 0.0

  1. 病马数据预测
def colicTest():
    #打开训练数据集
    frTrain = open('horseColicTraining.txt')
    #打开测试数据集
    frTest = open('horseColicTest.txt')
    #新建两个空列表,用于保存训练数据集和标签
    trainingSet = []
    trainingLabels = []
    for line in frTrain.readlines():
        #对当前行进行特征分割
        currLine = line.strip().split()
        #新建列表存储每个样本的特征向量
        lineArr = []
        #遍历每个样本的特征
        for i in range(21):
            #将每个样本的特征存入lineArr列表
            lineArr.append(float(currLine[i]))
        #将该样本标签存入标签列表
        trainingLabels.append(currLine[21])
        #将该列表的特征向量添加到数据集列表
        trainingSet.append(lineArr)
    #调用梯度上升法更新logistic回归的权值参数
    trainWeights = stoGradAscent(trainingSet,trainingLabels)
    #统计测试数据集预测样本数量和样本总数
    errorCount = 0
    numTestVec = 0.0
    #遍历测试数据集的每个样本
    for line in frTest.readlines():
        #样本总数加1
        numTestVec += 1.0
        #对当前行进行处理,分割出各个特征集样本标签
        currLine = line.strip().split()
        #新建特征向量
        lineArr = []
        #将各个特征构成特征向量
        for i in range(21):
            lineArr.append(float(currLine[i]))
        #利用分类预测函数对样本进行预测,并于样本标签进行比较
        if classifyVector(lineArr,trainWeights) != currLine[21]:
            #如果预测错误,错误加1
            errorCount += 1
    #计算测试集总的预测错误率
    errorRate = (float(errorCount)/numTestVec)
    print('the error rate of this test is :',errorRate)
    return errorRate

#多次测试算法求取误差平均值
def multTest():
    #设置测试次数为10次,并统计错误率总和
    numTests = 10
    errorRateSum = 0.0
    for k in range(numTests):
        errorRateSum += colicTest()
    print('after ',numTests,' iterations the average error rate is : ',errorRateSum/float(numTests))

总结

  • logistic回归的目的是寻找一个非线性函数sigmoid的最佳拟合参数,从而来相对准确的预测分类结果
  • 为了找出最佳的函数拟合参数,最常用的优化算法为梯度上升法,为了节省计算资源,通常选择随机梯度上升法来迭代更新拟合参数。
  • 随机梯度上升法是一种在线学习算法,它可以在新数据到来时完成参数的更新,而不需要重新读取整个数据集来进行批处理运算
  • logistic回归算法,其具有计算代价不高,易于理解和实现等优点;logistic回归算法容易出现欠拟合,以及分类精度不太高的缺点。
  • logistic回归和朴素贝叶斯一样,都是基于概率分类:将x分类
    到使P(Y|x)最大的那个Y类,x服从logitic分布

sklearn中的logistic

from sklearn import linear_model
from sklearn import metrics
from sklearn.metrics import accuracy_score

# 加载数据
def loadData(filename):
    fr = open(filename)
    dataSet = []
    Labels = []
    for line in fr.readlines():
        currLine = line.strip().split('\t')
        dataSet.append([float(lineArr) for lineArr in currLine[:-1]])
        Labels.append(float(currLine[-1]))
    return dataSet,Labels

if __name__ == '__main__':
    trainingSet,trainingLabels = loadData('horseColicTraining.txt')
    testSet,testLabels = loadData('horseColicTest.txt')

    #训练一个logistic回归模型,设置迭代次数为1000(默认为100,会导致结果不收敛,从而触发警告)
    logistic_model = linear_model.LogisticRegression(max_iter=1000)
    logistic_model = logistic_model.fit(trainingSet,trainingLabels)

    predicted=logistic_model.predict(testSet)
    deathCount = 0
    for i in predicted:
        if i == 0:
            deathCount += 1
    deathRate = float(deathCount)/len(predicted)
    score = logistic_model.score(testSet,testLabels)
    print('The accuracy of logistic is :',score)
    print('the death rate of this test is :', deathRate)

你可能感兴趣的:(机器学习,回归,逻辑回归)