机器学习实战笔记:Logistic回归

    Logistic回归的一般过程为:

  1. 收集数据;
  2. 准备数据:要求是数值型
  3. 分析数据;
  4. 训练算法:训练的目的是找到最佳的分类回归系数w和b
  5. 测试算法;
  6. 使用:输入数据并基于训练好的回归系数对样本进行分类

    基于梯度上升法的优化方法确定回归系数:

    w:=w+α▽f(w),其中w是要优化的参数,α是更新步长,▽是梯度。

    

"""自定义训练数据集"""
def loadDataSet():
    dataMat=[]   #矩阵[x0,x1,x2],x0是b对应的x,值恒为1
    labelMat=[]  #标签向量
    fr=open("testSet.txt")
    for line in fr.readlines():
        lineArr=line.strip().split()  #strip()移除字符串头尾指定字符,默认空格;split()通过指定分隔符将字符串切片,默认为空格
        dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])  #因为文件中读入的是字符串,所以将字符串转化为float类型
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat

"""定义sigmoid函数"""
def sigmoid(inX):
    return 1.0/(1+exp(-inX))

"""梯度上升法"""
def gradAscent(dataMatIn,classLabels):
    dataMatrix=mat(dataMatIn)  #用dataMatIn创建特征矩阵
    labelMat=mat(classLabels).transpose()  #调换矩阵的坐标顺序,对于二维矩阵来说,transpose()就是转置
    m,n=shape(dataMatrix)  #m是样本数,n是特征数
    alpha=0.001    #梯度上升步长
    maxCycles=500  #最大迭代次数
    weights=ones((n,1)) #权重向量b,初始化为全1
    for k in range(maxCycles):
        h=sigmoid(dataMatrix*weights)  #对w1*x1+w2*x2求对数几率回归
        error=(labelMat-h)  #预测值和真实标签之间的误差
        weights=weights+alpha*dataMatrix.transpose()*error  #梯度上升更新权重
    return weights

解出回归系数之后就是根据系数(权重weights),画出决策边界:

"""画出数据集和Logistic回归的最佳拟合线的函数"""
def  plotBestFit(weights):
    dataMat,labelMat=loadDataSet()
    dataArr=array(dataMat)  #将矩阵转化为数组
    n=shape(dataMat)[0]     #n为样本数
    xcord1=[];ycord1=[]
    xcord2=[];ycord2=[]
    for i in range(n):      #遍历所有样本
        if int(labelMat[i])== 1:    #如果是正样本
            xcord1.append(dataArr[i,1])   #将正样本的x1属性的值加入xcord1
            ycord1.append(dataArr[i,2])   #将正样本的y1属性的值加入ycord1
        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]   #设置sigmoid函数为0,求解X2和X1的关系式,X0=1恒成立
    ax.plot(x,y)  #画线函数
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()



"""测试"""
if __name__=='__main__':
    dataArr,labelMat=loadDataSet()
    weights=gradAscent(dataArr,labelMat)
    plotBestFit(weights.getA())   #getA()作用和mat()相反,是将矩阵转化为数组

结果输出为:

    优化算法:

    梯度上升算法每次更新回归系数都要遍历整个数据集,这对于大容量样本来说是不能接受的。改进的办法是,每次都仅用一个样本点来更新回归系数,该方法称为随机梯度上升。

"""随机梯度上升"""
def stocGradAscent0(dataMatrix,classLabels):
    m,n=shape(dataMatrix)  #m是样本数,n是特征数
    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

    比较上述两种拟合直线可以发现,随机梯度上升导致了分类器错分了三分之一的样本。然而这种比较是有问题的,因为第一种梯度上升法中所得的结果是在数据集上迭代了500次才得到的。而一个判断优化算法优劣的可靠方法是看它是否收敛,也就是说参数是否达到了稳定值不再不断地变化。

     随机梯度上升导致每次迭代是会引发系数的剧烈改变,我们期望算法能避免来回波动,从而收敛到某个值,另外,收敛速度也需要加快。

      改进的随机梯度上升算法如下:

"""改进的梯度上升算法"""
def stocGradAscent1(dataMatrix,classLabels,numIter=150):
    m,n=shape(dataMatrix)  #m是样本数,n是特征数
    weights=ones(n)
    for j in range(numIter):
        dataIndex=list(range(m))
        for i in range(m):
            alpha=4/(1.0+j+i)+0.01
            randIndex=int(random.uniform(0,len(dataIndex)))
            h=sigmoid(sum(dataMatrix[i]*weights))    #随机梯度上升
            error=classLabels[randIndex]-h
            weights=weights+alpha*error*dataMatrix[randIndex]
            del(dataIndex[randIndex])
    return weights

    改进之处:

  1. alpha在每次迭代时都会调整,可以缓减数据波动或者高频波动,此外alpha会随着迭代次数不断减小但永远不会减小到0
  2. 通过随机采样来更新回归系数,有利于减少周期性波动。每次随即从列表中选出一个值,然后从列表中删掉该值后再进行下一次迭代。
    以上就是Logisitic回归模型的构造方法以及参数求解。构造出模型函数后就可以根据模型函数对样本进行分类。

猜你喜欢

转载自blog.csdn.net/qq_29599907/article/details/80545102