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时,学习略随着迭代次数增加,也不是严格下降的

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

posted on 2014-07-22 14:32  fxjwind  阅读(789)  评论(0编辑  收藏  举报