机器学习实战—逻辑回归

逻辑回归进行分类

有这么几个关键词:最佳拟合曲线,利用逻辑回归模型进行分类,最佳拟合参数(w和b),sigmoid函数(S函数),最优化方法,梯度上升(下降),随机梯度下降法,参数迭代公式(梯度,步长)
梯度上升找到最佳参数:
伪代码
每个回归系数初值定为1
for i in steps:
计算整个数据集的梯度
w=w+alpha*梯度
更新回归系数

#梯度上升算法的实现
import numpy as np
def loadDataSet():
    dataMat=[]#创建数据空列表
    labelMat=[]#创建类别空列表
    fr=open('logRegres_testSet.txt')#打开训练集文本
    for line in fr.readlines():#读取每行
        lineArr=line.strip().split()#分割数据
        #合并每行数据(不包括类别列),并在每一行的前面添加一列1
        dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
        labelMat.append(int(lineArr[2]))#合并类别
    return dataMat,labelMat

#定义S函数
def sigmoid(inX):
    return 1.0/(1+np.exp(-inX))

#定义梯度上升算法
def gradAscent(dataMatIn,classLabels):
    dataMatrix=np.mat(dataMatIn)#list型转换为mat型(矩阵型)
    labelMat=np.mat(classLabels).transpose()#list型转换为mat型并转置
    m,n=np.shape(dataMatrix)#得到矩阵的行列数
    alpha=0.001#定义步长
    maxCycles=500#定义迭代步数
    weights=np.ones((n,1))#定义参数矩阵初值(全1)
    for k in range(maxCycles):#步数循环
        h=sigmoid(dataMatrix*weights)#求S函数的值
        error=(labelMat-h)#求误差
        weights=weights+alpha*dataMatrix.transpose()*error#更新参数数值
    return weights

#画出决策边界
def plotBestFit(wei):
    import matplotlib.pyplot as plt
    weights=wei.getA()#getA():返回自己,但是作为ndarray返回,即一个矩阵
    dataMat,labelMat=loadDataSet()#得到数据和类别
    dataArr=np.array(dataMat)#得到矩阵
    n=np.shape(dataArr)[0]#得到行数
    xcord1=[];ycord1=[]
    xcord2=[];ycord2=[]
    for i in range(n):#循环数据行数
        if int(labelMat[i])==1:
            #如果类别为1,将dataArr[i,1]的数据添加给xcord1,...
            xcord1.append(dataArr[i,1])
            ycord1.append(dataArr[i,2])
        else:#否则,将dataArr[i,1]的数据添加给xcord2,...
            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=np.arange(-3.0,3.0,0.1)#创建-3到3,间隔为0.1的点
    y=(-weights[0]-weights[1]*x)/weights[2]#由x求出Y
    ax.plot(x,y)#绘制分界线
    plt.xlabel('X1');plt.ylabel('Y1')
    plt.show()

对上述梯度上升(下降)算法的解释,在这里有算法在每次更新回归系数时,都要遍历整个数据集。
命令窗口输入:

data,label=loadDataSet()

weights=gradAscent(data,label)

weights
Out[4]: 
matrix([[ 4.12414349],
        [ 0.48007329],
        [-0.6168482 ]])

plotBestFit(weights)

图形显示:
逻辑回归决策边界

训练算法-随机梯度上升(SGD)

对之前的梯度算法就行改进,一次仅用一个样本点来更新回归系数,就是随机梯度上升算法。
伪代码
所有回归系数初始化为1
对数据集中每个样本
计算该样本的梯度
w=w+alpha*梯度
更新回归系数

#s随机梯度上升算法
def stocGradAscent0(dataMatrix,classLabels): 
    m,n=np.shape(dataMatrix)
    alpha=0.001
    weights=np.ones(n)
    for i in range(m):
        h=sigmoid(sum(dataMatrix[i]*weights))
        error=classLabels[i]-h
        weights=weights+alpha * error * dataMatrix[i]
    #提前修改weights的类型
    temp=np.mat(weights)
    weights=temp.transpose()
    return weights
#随机梯度算法中,出现的数据都是数值格式,而之前的梯度算法中基本都是numpy数组格式
#在这里输出的weights时1*3的列表,需要在使用画图操作前进行np.mat()操作和转置操作
#而GD输出的weights是3*1的数组(array)

命令程序:

data,labels=loadDataSet()

weights=stocGradAscent0(np.array(data),labels)

weights
Out[82]: 
matrix([[ 0.963951  ],
        [ 0.9826866 ],
        [ 0.49153886]])

plotBestFit(weights)

SGD结果
发现结果并没有之前好的,原因在于之前的结果是迭代了500次之后,而现在的SGD仅仅遍历了数据行数。当然我们可以发现SGD中的步长因子是0.01,而不是0.001(GD),SGD在用0.001时效果更差。
下一步对SGD进行改进。

#改进的SGD算法
def stocGradAscent1(dataMatrix,classLabels,numIter=150):
    m,n=np.shape(dataMatrix)
    weights=np.ones(n)
    for j in range(numIter):#迭代次数
    #对于range(m)不存在的操作,需要用list(range(m))
        dataIndex=list(range(m))
        for i in range(m):
            alpha=4/(1.0+j+i)+0.01
            #随机选取一个样本点(第几行)
            randIndex=int(np.random.uniform(0,len(dataIndex)))
            h=sigmoid(sum(dataMatrix[randIndex]*weights))
            error=classLabels[randIndex]-h
            weights=weights+alpha*error*dataMatrix[randIndex]
            del(dataIndex[randIndex])#下次迭代前删除该值
    temp=np.mat(weights)
    weights=temp.transpose()
    return weights
 #改进后的算法在于这两处:1,每次迭代的时候alpha都会改变,不断减小但不会为0
 #通过随机选取样本更新回归系数,每次随机选一个,并在进行下一迭代前删掉该值

得到的结果是:
修改后的SGD150次迭代

上面是150迭代结果,下面是500次迭代结果
修改后的SGD500次迭代

实例:从疝气病病症预测病马的死亡率

数据的前期处理,如果数据(特征数据)存在缺失,应该采取的处理措施:
使用可用特征的均值填补缺失的特征数据,使用特殊值来填补缺失值,忽略有缺失值的样本,使用相似样本的均值填补缺失值,使用另外的机器学习算法预测缺失值。
如果是类别值缺失,那么该数据行应该丢弃,因为类别值很难确定用哪个类别来填补。
现在数据已经没有问题,可以利用来预测。前面的数据已经可以通过训练集得到回归系数,所以只要我们再利用测试集的数据乘上回归系数,再取S函数,就可以判断死亡与否,继而得到死亡率。

#利用以上算法从疝气病症预测病马的死亡率
#因为上面的算法已经得出了回归系数,所以只要将测试集的数据乘上回归系数代入S函数即可
def classifyVector(inX,weights):
    prob=sigmoid(sum(inX*weights))#S函数
    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=[]
        #注:每一行数据有22个数据,其中最后一个表示类别
        for i in range(21):#因为有21个特征(0~20),特征数据赋给lineArr
            lineArr.append(float(currLine[i]))
        trainingSet.append(lineArr)#今儿赋给trainingSet
        trainingLabels.append(float(currLine[21]))#类别数据转赋
    #通过训练集求回归系数,也即是求出映射关系
    trainWeights=stocGradAscent1(np.array(trainingSet),trainingLabels,500)
    errorCount=0#分类错误数初始化
    numTestVec=0.0#已测试数据数目初始化
    for line in frTest.readlines():#读取测试集每一行数据
        numTestVec+=1.0#测试数据数目递增
        currLine=line.strip().split('\t')#每行数据的切割
        lineArr=[]
        for i in range(21):#只取每行数据前21个特征数据
            lineArr.append(float(currLine[i]))
        if int(classifyVector(np.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)))

要知道,利用python打开文件后,一般都要对数据进行格式化处理,基本上都是切割,定义两个空列表,分别将数据中的特征列和类别列添加到其中,即分成两个部分。
结果:

multiTest()
__main__:24: RuntimeWarning: overflow encountered in exp
the error rate of this test is0.373134
the error rate of this test is0.283582
the error rate of this test is0.313433
the error rate of this test is0.238806
the error rate of this test is0.417910
the error rate of this test is0.402985
the error rate of this test is0.358209
the error rate of this test is0.432836
the error rate of this test is0.343284
the error rate of this test is0.313433
after 10 iterations the average error rate is: 0.347761

总结:逻辑回归是一种分类算法,利用S函数,将参数和特征代入,实现分类。而任务主要在于寻找回归系数,用的方法是最优化。其中最常用的是梯度上升(下降),GD和SGD。SGD是一种在线学习算法,与之对应的一次处理所有数据被称为批处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值