理解Logistic回归算法原理与Python实现

一般的机器学习的实现大致都是这样的步骤: 1.准备数据,包括数据的收集,整理等等 2.定义一个学习模型(learning function model),也就是最后要用来去预测其他数据的那个模型 3.定义损失函数(loss function),就是要其做优化那个,以确定模型中参数的那个函数。 4.选择一个优化策略(optimizer),用来根据损失函数不断优化模型的参数。 5.根据训练数据(train data)训练模型(learning function model) 6.根据测试数据(test data)求得模型预测的准确率。

而Logistic回归同样遵循这个步骤,上面的步骤中一,五,六自然是不用说的,剩下的Logistic回归算法与其他的机器学习算法的区别也只在于第二步—学习模型的选择。所以下面主要解释Logistic回归到底确定了一个什么样的模型,然后简单说下损失函数与优化策略。 先来简要介绍一下Logistic回归:Logistic回归其实只是简单的对特征(feature)做加权相加后结果输入给Sigmoid函数,经过Sigmoid函数后的输出用来确定二分类的结果。所以Logistic回归的优点在于计算代价不高,容易理解和实现。缺点是很容易造成欠拟合,分类的精度不高。还有一个很重要的地方是神经网络中的一个神经元其实可以理解为一个Logistic回归模型。

Sigmoid函数

首先说下Sigmoid函数,因为它在Logistic回归起着重要的作用,Sigmoid函数是一个在生物学中常见的S型的函数,也称为S型生长曲线。Sigmoid函数由下列公式定义:

下面是两种尺度下的Sigmoid函数图:

可以看到,在横坐标跨度足够大时,sigmoid函数看起来很像一个阶跃函数。 除此之外,sigmoid函数还有如下特点: 一个良好的阈值函数(最大值趋近于1,最小值趋近于0),连续,光滑,严格单调,且关于(0,0.5)中心对称。

Logistic回归模型

Logistic回归为了解决二分类问题,需要的是一个这样的函数:函数的输入应当能从负无穷到正无穷,函数的输出0或1。这样的函数很容易让人联想到单位阶跃函数:

就是上面这个东西,但是单位阶跃函数在跳跃点上从0瞬间跳跃到1,这个瞬间跳跃的过程决定了它并不是连续的,所以它并不是最好的选择,对的,Logistic回归最后选择了上面提到的sigmoid函数。由于sigmoid函数是按照0.5中心对称的,所以只需将它的输出大于0.5的数据作为“1类”,小于0.5的数据作为“0类”就这样实现了二分类的问题。 确定了sigmoid函数输出怎么处理的问题,那么sigmoid函数的输入又是什么? 其实只是每一个特征(feature)上都乘以一个回归系数,然后把所有的结果值相加,定义sigmoid函数输入为z,那么:

其中

就是特征了,而

就是需要训练得到的参数。我们都将它用向量的形式表达即为:

所以Logistic回归模型的形式可以写成:

至此,Logistic回归模型就确定好了:

损失函数与优化策略

或者:

上面上个公式也可以称之为Logistic回归的损失函数(loss function)。

那么对于第一个损失函数,可以采用(随机)梯度上升来作为优化策略,对于第二个损失函数,用(随机)梯度下降就好了。

Python实现

这个例子来源于《机器学习实战》,在这里可以下载电子版。 这个例子使用Logistic回归与随机梯度上升算法来预测病马的生死,下面会贴出源码并简单说明,但是如果想要使用例程中的数据,可以下载整个例程

from numpy import *

def loadDataSet():
    dataMat = []; labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat

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))
    for k in range(maxCycles):              #heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     #matrix mult
        error = (labelMat - h)              #vector subtraction
        weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
    return 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')
    x = 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 stocGradAscent0(dataMatrix, classLabels):
    m,n = shape(dataMatrix)
    alpha = 0.01
    weights = ones(n)   #initialize to all ones
    for i in range(m):
        h = sigmoid(sum(dataMatrix[i]*weights))
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatrix[i]
    return weights

def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    m,n = shape(dataMatrix)
    weights = ones(n)   #initialize to all ones
    for j in range(numIter):
        dataIndex = range(m)
        for i in range(m):
            alpha = 4/(1.0+j+i)+0.0001    #apha decreases with iteration, does not 
            randIndex = int(random.uniform(0,len(dataIndex)))#go to 0 because of the constant
            h = sigmoid(sum(dataMatrix[randIndex]*weights))
            error = classLabels[randIndex] - h
            weights = weights + alpha * error * dataMatrix[randIndex]
            del(dataIndex[randIndex])
    return weights

def classifyVector(inX, weights):
    prob = sigmoid(sum(inX*weights))
    if prob > 0.5: return 1.0
    else: return 0.0

def colicTest():
    frTrain = open('horseColicTraining.txt'); frTest = open('horseColicTest.txt')
    trainingSet = []; trainingLabels = []
    for line in frTrain.readlines():
        currLine = line.strip().split('\t')
        lineArr =[]
        for i in range(21):
            lineArr.append(float(currLine[i]))
        trainingSet.append(lineArr)
        trainingLabels.append(float(currLine[21]))
    trainWeights = stocGradAscent1(array(trainingSet), trainingLabels, 1000)
    errorCount = 0; numTestVec = 0.0
    for line in frTest.readlines():
        numTestVec += 1.0
        currLine = line.strip().split('\t')
        lineArr =[]
        for i in range(21):
            lineArr.append(float(currLine[i]))
        if int(classifyVector(array(lineArr), trainWeights))!= int(currLine[21]):
            errorCount += 1
    errorRate = (float(errorCount)/numTestVec)
    print "the error rate of this test is: %f" % errorRate
    return errorRate

def multiTest():
    numTests = 10; errorSum=0.0
    for k in range(numTests):
        errorSum += colicTest()
    print "after %d iterations the average error rate is: %f" % (numTests, errorSum/float(numTests))

其中定义的函数分别为如下功能: loadDataSet():数据准备; sigmoid():定义sigmoid函数; gradAscent():梯度上升算法; plotBestFit():画出决策边界; stocGradAscent0():随机梯度上升算法; stocGradAscent1():一种改进的随机梯度上升算法; classifyVector():一回归系数和特征向量作为输入来计算对应的sigmoid值; colicTest():打开测试集和训练集,并对数据进行格式化处理; multiTest():调用colicTest()10次并求结果的平均值。

所以运行上述代码后,在Python提示窗中输入:

>>> import logRegres
>>> reload(logRegres)
<module 'logRegres' from 'F:\学习资料\机器学习与计算机视觉资料\《机器学习实战》电子书和源码\machinelearninginaction\Ch05\logRegres.pyc'>
>>> logRegres.multiTest()

最后程序输出:

the error rate of this test is: 0.358209
the error rate of this test is: 0.283582
the error rate of this test is: 0.298507
the error rate of this test is: 0.417910
the error rate of this test is: 0.388060
the error rate of this test is: 0.298507
the error rate of this test is: 0.328358
the error rate of this test is: 0.313433
the error rate of this test is: 0.402985
the error rate of this test is: 0.432836
after 10 iterations the average error rate is: 0.352239

0.352239就是最后的错误率了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏专知

【论文推荐】最新6篇目标检测相关论文—场景文本检测 、显著对象、语义知识转移、混合监督目标检测、域自适应、车牌识别

【导读】专知内容组整理了最近六篇目标检测(Object Detection)相关文章,为大家进行介绍,欢迎查看! 1. Rotation-Sensitive R...

6186
来自专栏自然语言处理

逻辑回归模型算法研究与案例分析

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

6873
来自专栏AI研习社

基于深度学习的医疗影像论文汇总(Deep Learning Papers on Medical Image Analysis)

看到好东西,怎么能不分享呢。 第一次在知乎翻译,由于水平有限(不是谦虚的那种有限,是真的有限),有不准确的地方还望包涵,最重要的是,还望大佬们多多指正! B...

5628
来自专栏专知

【论文推荐】最新6篇图像分割相关论文—隐马尔可夫随机场、级联三维全卷积、信号处理、全卷积网络、多源域适应、循环分割

【导读】专知内容组整理了最近六篇图像分割(Image Segmentation)相关文章,为大家进行介绍,欢迎查看! 1.Combination of Hidd...

3636
来自专栏专知

【论文推荐】最新六篇图像分割相关论文—控制、全卷积网络、子空间表示、多模态图像分割

【导读】专知内容组整理了最近六篇图像分割(Image Segmentation)相关文章,为大家进行介绍,欢迎查看! 1.Virtual-to-Real: Le...

4055
来自专栏专知

【论文推荐】最新七篇图像分割相关论文—域适应深度表示学习、循环残差卷积、二值分割、图像合成、无监督跨模态

3605
来自专栏专知

【论文推荐】最新七篇对抗自编码相关论文—人口异常检测、图像到图像转换、人脸属性、前列腺癌检测、情感转移

2434
来自专栏专知

【论文推荐】最新七篇图像分类相关论文—条件标签空间、生成对抗胶囊网络、深度预测编码网络、生成对抗网络、数字病理图像、在线表示学习

【导读】专知内容组整理了最近七篇图像分类(Image Classification)相关文章,为大家进行介绍,欢迎查看! 1. Learning Image C...

4407
来自专栏Deep Learning in Ads

基于Field的DeepFM稀疏化实现

DeepFM是一个集成了FM和DNN的神经网络框架,思路和Google的Wide&Deep相似,都包括wide和deep两部分。W&D模型的wide部分是广...

4148
来自专栏专知

【专知荟萃25】文字识别OCR知识资料全集(入门/进阶/论文/综述/代码/专家,附查看)

OCR文字,车牌,验证码识别 专知荟萃 入门学习 论文及代码 文字识别 文字检测 验证码破解 手写体识别 车牌识别 实战项目 视频 入门学习 端到端的OCR...

1.4K8

扫码关注云+社区