码迷,mamicode.com
首页 > 其他好文 > 详细

机器学习实战3:逻辑logistic回归:病马实例

时间:2016-06-25 23:00:12      阅读:511      评论:0      收藏:0      [点我收藏+]

标签:

  本文介绍logistic回归,和改进算法随机logistic回归,及一个病马是否可以治愈的案例。例子中涉及了数据清洗工作,缺失值的处理。

  一 引言

  1 sigmoid函数,这个非线性函数十分重要,f(z) = 1 / (1 + e^(-z) ), 画图如下:

      技术分享

  这个函数可以很好的把数轴上的值映射到0,1区间,所以很好的解决了分类问题。下面是代码:

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

 

  2 梯度上升法是我们常用的最优化方法,公式技术分享。就是说沿这梯度方向迭代,alpha是步长,控制收敛速度;delta是对各个变量的偏微分;

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

  所有的数据集迭代500次,步长是0.001,目的是确认参数weights,weights会在500次左右收敛,误差较小。

  

  二 逻辑回归算法

  思路:根据梯度上升发,求出了最优化的参数weights,带入logistics分类器,y = (-weights[0]-weights[1]*x)/weights[2],预测测试样本即可

  inX*weights大于0.5,则分类到1,否则分类到0;主意,inX和weights都是向量;

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

  下面python代码主要利用了matplotlib这个包,模仿matlab画出了图;

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()

  效果还不错,只有两个实例分错了;

技术分享

 

  三 logistics改进:随机梯度上升

  改进算法1

  上面的logistics缺陷:每次迭代都要遍历所有的数据集样本,这样迭代500次1000000个样本的数据集,压力很大;

  提出增量的方法,每遍历一个样本就修改一次weighs;

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

  可以看出效果不如非增量的,这是可以接受的,因为增量的只遍历了一遍所有样本,时间上快了很多。

技术分享

  改进算法2

  上面的改进算法1,虽然在迭代15000次后三个参数均趋于收敛,但很明显x1 x2参数存在波动(原因是有些样本点不能正确分类,数据集也不是全线性不可分的所以误差很大),为了避免这种波动,提出了改进算法2;

    技术分享

  改进点:

    1迭代150次改进的增量算法1,这样还是比迭代200次全集时间要约简不少,并且准确率不低;

    2步长alpha不是固定的,这样可以开始收敛速度大,后来越来越准确的时候收敛速度慢点,后面加0.0001是防止alpha为0。步长为0原地不动迭代就没有意义;

    3为了避免上图的波动情况,随机选取样本点训练,然后再原数据集中删除,避免重复使用;下图可以看出,选用随机点可以避免周期性波动,波动确实可以变小;

技术分享

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

  分类结果:

技术分享

 

  四 实例: 病马治愈问题

  先说明下,数据清洗是必要的工作,确实值是我们经常需要处理的;

  缺失值的解决方案:

    1使用特征的均值;

    2使用-1等特殊值填充;

    3删除有缺失值的样本;不推荐,有的数据的获得是不可恢复的

    4使用相似样本的值来填充;

    5使用其它算法计算确实值,比如kmeans等;

    若样本的类属性缺失,监督学习中一般采用直接删除的方法;

 

  主函数是multiTest(),原理和上面一样,整体过程如下:

    训练分类器,获得线性分类器的参数weighs;

    对测试样本应用分类器,classifyVector方法返回0或1;

    统计错误率;

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))

 

  五 总结

  1 logistic分类器只适用于数值属性,不能处理非数值型数据集;

  2 logistic分类器的目的是寻找一个非线性函数sigmoid的最佳拟合参数;求解过程用到了最优化方法梯度上升法;

 

机器学习实战3:逻辑logistic回归:病马实例

标签:

原文地址:http://www.cnblogs.com/rongyux/p/5616954.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!