《机器学习实战》学习笔记七:Logistics回归(梯度上升法)

1 Logistics回归概念

回归是指将一对数据拟合为一条直线的过程,而Logistics回归则是将回归用于分类,其主要思想为:根据现有的数据对分类边界线建立回归公式,依次为依据进行分类,在这里最关键的一步是寻找最佳的拟合参数,这一步将会用到一些最优化的方法,如梯度上升等。

2 一些数学基础

2.1 Sigmoid函数

本文以二分类为例,说到二分类问题,我们首先想到的是0,1的问题,那么首先要找到一个函数,一个值为0或1的函数,这里想到了一个高等数学中遇到的单位阶跃函数:它的值只有0和1,但是这个函数存在0到1之间的跳跃,这个跳跃很难处理,庆幸的是,数学上还有另一个函数,和他有类似的性质,那就是Sigmoid函数,Sigmoid函数公式如下:

S(x)=11+ex S ( x ) = 1 1 + e − x

其图像为:
《机器学习实战》学习笔记七:Logistics回归(梯度上升法)_第1张图片
可见当坐标轴足够大时,Sigmoid就有类似阶跃函数的性质

2.2 梯度上升法

Sigmoid的输入记为z,z由以下公式得出:

z=w0x0+w1x1+w2x2+...+wnxn z = w 0 x 0 + w 1 x 1 + w 2 x 2 + . . . + w n x n

若采用向量法上述公式可以写成: z=wTx z = w T x
公式中 x x 为分类器的输入数据, w w 为我们需要找到的最佳参数,为了能够准确地找到这一参数,需要一些最优化的知识,这里就用到了梯度上升法这一最优化方法。
顾名思义,梯度上升法就是沿着函数梯度的方向向上搜索,直至找到函数的最大值,也就是我们所需要的最优参数。这这里需要明确两个概念:梯度和步长。
梯度:某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(模的变化)。
梯度的表达式为:
f(x,y)=[f(x,y)x,f(x,y)y] ▽ f ( x , y ) = [ ∂ f ( x , y ) ∂ x , ∂ f ( x , y ) ∂ y ]

步长:在梯度方向上移动一步的距离,用 α α 表示
由以上两个变量我们可以得出梯度上升算法的迭代公式如下:
w=w+αwf(w) w = w + α ▽ w f ( w )

3 算法实现

3.1 梯度上升法

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): #sigmoid函数
    return 1.0/(1+exp(-inX))
def gradAscent(dataMatIn,classLabels):#梯度上升
    dataMatrix = mat(dataMatIn)  #转换成矩阵
    labelMat = mat(classLabels).transpose() #转置
    m,n = shape(dataMatrix)     #矩阵的维度
    alpha = 0.001               #步长
    maxCycles = 500             #循环次数
    weights = ones((n,1))       #n*1的矩阵
    for k in range(maxCycles):
        h = sigmoid(dataMatrix * weights) # m*1的矩阵
        error = (labelMat - h)            # m*1的矩阵
        weights = weights + alpha * dataMatrix.transpose() * error
        # n*m的矩阵乘以m*1的矩阵得到n*1的矩阵,然后以weights相加
    return weights
dataArr,LabelMat = loadDataSet()

3.2 绘制数据集和拟合直线

根据上述算法计算出的结果,绘图如下:
《机器学习实战》学习笔记七:Logistics回归(梯度上升法)_第2张图片

绘图代码部分:

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

4 算法改进

4.1 随机梯度上升

梯度上升算法在每次更新回归系数时都需要遍历整个数据集,该方法在处理100个左右的数据时尚可,但是当数据集超过一定的数量时(如有十亿样本和成千上万的特征时),那么该方法的计算复杂度就太高了。一种改进方法是依次仅才采用一个样本点来更新回归系数,该方法称为随机梯度上升法。是一种在线学习方法,即可以再新样本到来时对分类器进行增量式更新。
随机梯度上升算法代码如下:

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

可以看出随机梯度上升算法和梯度上升算法在代码上十分相似,但也有一些区别:第一,梯度上升算法的变量h和误差error都是向量,而随机梯度上升算法则是数值;第二随机梯度上升算法没有矩阵转换的过程,所有变量的数据类型都是NumPy数组,而梯度上升算法数据类型则是矩阵。
对该算法绘图如下:
《机器学习实战》学习笔记七:Logistics回归(梯度上升法)_第3张图片
可以看出在迭代次数少的情况下(随机梯度算法迭代了200次,而梯度上升迭代了500次),随机梯度上升算法的效果是不如梯度上升的

4.2 改进的随机梯度上升算法

随机梯度上升算法对于3个不同的系数迭代200次,回归系数和迭代次数的关系如下:
《机器学习实战》学习笔记七:Logistics回归(梯度上升法)_第4张图片
可见回归系数的值存在周期性的波动,原因是存在一些不能正确分类的样本点,在迭代的时候会引发系数剧烈的改变,另外算法的收敛速度也较慢。
在这里对随机梯度上升算法进行了两处改进:一是时步长alpha在每次迭代的时候都调整一次,这样做会缓解波动;第二个地方是通过随机选取样本来更新回归系数。这样做将会减少周期性的波动,具体的实现代码如下:

def stocGradAscent1(dataMatrix,classLabels,numIter=150):
    m,n = shape(dataMatrix)
    weights = ones(n)
    for j in range(numIter):
        dataIndex = list(range(m))  #python 3 改法
        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])  #每次迭代都要删除随机选出的值
            #按书上的写 python 3 在这里会报错
    return weights

回归系数的变化如下:
《机器学习实战》学习笔记七:Logistics回归(梯度上升法)_第5张图片
可见改进算法的系数并没有出现周期性的波动,而且收敛速度也快了很多。
对结果绘图如下:
《机器学习实战》学习笔记七:Logistics回归(梯度上升法)_第6张图片
在算法精度上,迭代了150次的改进算法的精度和迭代500次的梯度上升算法相当,这个算法大大地减少了计算量。

你可能感兴趣的:(python,机器学习,《机器学习实战》学记笔记)