zoukankan      html  css  js  c++  java
  • Machine Learning in Action -- Logistic regression

    这个系列,重点关注如何实现,至于算法基础,参考Andrew的公开课

    相较于线性回归,logistic回归更适合用于分类

    因为他使用Sigmoid函数,因为分类的取值是0,1

    image

    对于分类,最完美和自然的函数,当然是Heaviside step function,即0-1阶跃函数,但是这个函数中数学上有时候比较难处理

    所以用Sigmoid函数来近似模拟阶跃函数,

    image

    可以看到Sigmoid在增大坐标尺度后,已经比较接近于阶跃函数

    其中,

    image

    而logistic回归就是要根据训练集找到,最优的w向量

    下面就通过源码来看看如何用梯度下降来解logistic问题,

    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])]) #加入一个数据点,其中‘1.0’代表截距
            labelMat.append(int(lineArr[2])) #每个数据点的lable,用于训练
        return dataMat,labelMat
    
    def sigmoid(inX):
        return 1.0/(1+exp(-inX))
    
    def gradAscent(dataMatIn, classLabels):
        dataMatrix = mat(dataMatIn)  #首先将array转换为matrix
        labelMat = mat(classLabels).transpose()  #将lables转秩,因为一个lable对应于dataMatrix中的一行,即一个数据点
        m,n = shape(dataMatrix)
        alpha = 0.001   #学习率
        maxCycles = 500  #迭代次数
        weights = ones((n,1))   #初始化weights向量
        for k in range(maxCycles):
            h = sigmoid(dataMatrix*weights)  #这里是矩阵计算,最终h是个列向量,表示每个数据点的预估值
            error = (labelMat - h)  #和真实值比较,算出error列向量
            weights = weights + alpha * dataMatrix.transpose()* error #这个公式是通过梯度下降推导出来的
        return weights #获得最终的weights参数

    这里需要注意,numpy支持矩阵计算,所以

    h = sigmoid(dataMatrix*weights), 其实是完成n×m矩阵和n×1矩阵乘,然后执行n次sigmoid,得到h列向量

    至于那个公式,是由于由梯度下降求出的weight迭代公式如下,

    image

    得到weights后,进行predict很容易,直接把数据点和weights代入sigmoid函数算出h,以0.5为界近似成0或1

    这种原始的梯度下降算法的问题,就是计算量比较大,对于每个weight的迭代都需要遍历数据集一遍,所以如果weight和数据集比较大,很低效

     

    stochastic gradient ascent

    对于随机梯度下降,每次只用一个数据点来迭代weights

    def stocGradAscent0(dataMatrix, classLabels):
        m,n = shape(dataMatrix)
        alpha = 0.01
        weights = ones(n)
        for i in range(m):
            h = sigmoid(sum(dataMatrix[i]*weights)) #只取一个数据点
            error = classLabels[i] - h
            weights = weights + alpha * error * dataMatrix[i]
        return weights

    但这个简单的随机算法有些问题,

    首先只迭代训练集一遍,很可能没有达到收敛,所以准确率不够
    其次,每次是依次选取数据点,所以weights会产生周期性的波动
    最后,收敛速度不够

    def stocGradAscent1(dataMatrix, classLabels, numIter=150):
        m,n = shape(dataMatrix)
        weights = ones(n)
        for j in range(numIter):  #增加迭代次数
            for i in range(m):
                alpha = 4/(1.0+j+i)+0.01   #动态改变学习率
                randIndex = int(random.uniform(0,len(dataIndex))) #随机选取数据点
                h = sigmoid(sum(dataMatrix[randIndex]*weights))
                error = classLabels[randIndex] - h
                weights = weights + alpha * error * dataMatrix[randIndex]
                del(dataIndex[randIndex])
        return weights

    对于动态改变学习率,
    可以看到,学习率会随着迭代次数变大,不断变小,但不会为0,因为有常数项,可以缓解数据波动,并保持多次迭代后仍然对数据有一定的影响
    并且当i>>j时,学习略随着迭代次数增加,也不是严格下降的

    而随机选取数据点,用于解决周期性波动问题

  • 相关阅读:
    滑雪
    CSS被误删了 心态炸了。
    About Me
    偶数个3|递归|递推
    luogu P3200 [HNOI2009]有趣的数列|Catalan数|数论
    Sumdiv|同余|约数|拓展欧几里得算法
    博弈论
    友链——大佬们的博客
    【翻译】PalmOS 的PDB格式文件
    用acme.sh给ssl证书续期
  • 原文地址:https://www.cnblogs.com/fxjwind/p/3860517.html
Copyright © 2011-2022 走看看