机器学习实战学习笔记(四)分类—Logistic回归(python3实现)

来源:互联网 发布:usb数据延长线 编辑:程序博客网 时间:2024/05/01 03:41

概述

回归一词语来源于最佳拟合,表示要找到最佳拟合参数集,Logistic回归的主要思想就是根据现有数据对分类边界线建立回归公式,以此进行分类。Logistics回归的优势在于计算代价不高,易于理解和实现,但是非常容日前泥河,精度可能存在问题。

数学原理

Sigmoid函数:g(x)=1/(1+e^(-x)),该函数在x=0时,函数值0.5,随着x的增大,函数值逼近1,反之逼近0。如果横坐标足够大的话,Sigmoid函数看起来很像一个阶跃函数(实际上就是)。为了实现Logistic回归分类器,我们可以在每一个特征上乘以一个回归系数,然后把所有结果值相加,然后将这个总和带入Sigmoid函数,得到一个范围在0~1的数值,大于0.5归于1类,小于0.5归于0类。之后的问题在于确定这个系数

基于最优化方法的最佳回归系数的确定

Sidmoid函数的输入:z=xw^T,x是分类器输入的数据,w是最佳系数

1.梯度上升法

该方法基于“要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻”的思想,梯度算子总是指向函数值增长最快的方向,移动量的值(步长)用α表示,梯度算法的迭代公式可以表示为w=w+α*(该点梯度值),直到某个条件(比如迭代次数达到某个指定值或者算法达到某个可悲允许的误差范围)

2.训练算法:使用梯度上升找到最佳参数

假设每个样本点包含两个数值型特征:X1和X2

伪代码:

每个回归系数初始化为1

重复R次:

计算整个数据集的梯度

使用alpha x gradient 更新回归系数的向量

返回回归系数

python3代码如下:

import mathimport numpy as npimport random"""逐行读取文本文件中的数据,每行两个值再加上第三个对应的类别标签"""def loadDataSet():    dataMat=[]    labelMat=[]    fr=open('testSet.txt')    i=1    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"""Sigmoid函数,用于梯度上升算法"""def sigmoids(inX):    for line in inX:        line[0][0]=1.0/(1+math.exp(-line[0][0]))    return inX"""梯度上升算法输入:特征值和标签列表输出:回归系数矩阵"""def gradAscent(dataMatIn,classLabels):    dataMatrix=np.mat(dataMatIn)    labelMat=np.mat(classLabels).transpose()    m,n=np.shape(dataMatrix)    alpha=0.001    maxCycles=500    weights=np.ones((n,1))    for k in range(maxCycles):        h=sigmoids(dataMatrix*weights)        error=(labelMat-h)        weights=weights+alpha*dataMatrix.transpose()*error    return weights


3.算法改进——随机梯度上升

改进在于一次仅用一个样本点来更新回归系数,新样本到来时候可以对分类器进行增量更新,所以随机梯度上升算法是一个在线学习算法。python3代码如下:

def sigmoid(inX):    return 1.0/(1+math.exp(-inX))

"""随机梯度上升算法输入:特征值和标签列表输出:回归系数矩阵"""def stocGradAscent0(dataMatrix,classLabels):    m,n=np.shape(dataMatrix)    alpha=0.01    weights=np.ones(n)    for i in range(m):        h=sigmoid(sum(dataMatrix[i]*weights))        error=classLabels[i]-h        d=dataMatrix[i]        weights[0]=weights[0]+alpha*error*float(dataMatrix[i][0])        weights[1] = weights[1] + alpha * error * float(dataMatrix[i][1])        weights[2] = weights[2] + alpha * error * float(dataMatrix[i][2])    return weights

评价一个优化算法要看它是否能在若干次迭代后达到收敛,随机梯度上升算法经过多次迭代后不在出现大幅度的波动,但由于总存在一些不能正确分类的样本点(数据集线性不可分),每次迭代总是会造成系数的剧烈变动,为了解决这个问题,同时使收敛速度更快,我们可以做如下优化:

-每次迭代都调整一下alpha的值,减小但是不至于减小至0(添加一个常数项,若问题动态变化,可适当加大),以达到缓解数据波动或者高频波动;这里面需要注意的是一定要避免alpha严格下降,但趋于无穷次时保持平稳最佳(递减函数具有极限)

-通过随机选取样本来更新系数,以减少周期性的波动(每次随机选取一个做迭代然后删去)

python3代码如下:

"""改进的随机梯度上升算法"""def stocGradAscent1(dataMatrix,classLabels,numIter=150):    m,n=np.shape(dataMatrix)    weights=np.ones(n)    for j in range(numIter):        dataIndex=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[randIndex]*weights))            error=classLabels[randIndex]-h            weights[0] = weights[0] + alpha * error * float(dataMatrix[randIndex][0])            weights[1] = weights[1] + alpha * error * float(dataMatrix[randIndex][1])            weights[2] = weights[2] + alpha * error * float(dataMatrix[randIndex][2])    return weights

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

1.准备数据:处理数据中的缺失值

处理数据中的缺失值一般有以下几种做法:

a.使用可用特征的均值来填补缺失值

b.使用特殊值来填补缺失值,例如-1

c.忽略有缺失值的样本

d.使用相似样本的均值填补缺失值

e.使用另外的机器学习算法预测缺失值

在logistic回归预测中我们一般将缺失值填充为0,这样在更新系数的时候就不会对系数进行更新,但是特殊情况还是要特殊分析。

2.测试算法

使用logistics回归方法进行分类,先把测试集上每个特征向量乘以最优化方法得来的回归系数,再讲该乘积结果求和,最后输入到Sigmoid函数中即可。本例Python3代码如下:

"""预测病马"""#以回归系数和特征向量作为输入计算对应的Sigmoid值,并条件返回0 1def classifyVector(inX,weights):    prob=sigmoid(sum(inX*weights))    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=[]        for i in range(21):            lineArr.append(float(currLine[i]))            trainingSet.append(lineArr)            trainingLabels.append(float(currLine[i]))    trainingWeights=stocGradAscent1(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):            lineArr.append(float(currLine[i]))        if int(classifyVector(array(lineArr),trainingWeights))!=int(currLine[21]):            errorCount+=1    errorRate=(float(errorCount)/numTestVec)    print("the error rate of this test is: %f" % errorRate)    return errorRate#调用10次上面的方法求均值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)))





原创粉丝点击