Logistic回归

来源:互联网 发布:mac os x iso安装 编辑:程序博客网 时间:2024/05/16 12:00

利用Logistic回归进行分类的思想:根据现有数据对分类边界线建立回归公式
优点:计算代价不高,易于理解和实现
缺点:容易欠拟合,分类精度可能不高
适用数据类型:数值型和标称型数据
Sigmoid函数这里写图片描述
Sigmod函数的输入Z这里写图片描述
采用向量的写法 这里写图片描述
梯度上升法:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻
函数f(x,y)的梯度上升的迭代公式:w=w+α∇wf(w)
学习率:学习率决定了参数移动到最优值的速度快慢。如果学习率过大,很可能会越过最优值;反而如果学习率过小,优化的效率可能过低,长时间算法无法收敛

  • logistic回归梯度上升优化算法
import numpy as np#打开文件,并逐行读取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])) #类别特征值    return dataMat, labelMat#定义sigmoid分类函数def sigmoid(inX):    return 1.0/(1+np.exp(-inX))#梯度上升:设置迭代次数,每次将特征矩阵乘以回归系数进行sigmoid处理,得到预测类别(0-1)。计算真实类别和预测类别的误差值,#将特征矩阵*误差值得到误差矩阵,再乘以学习率,得到回归系数误差值,加上原来的回归系数,得到新的回归系数,再进行迭代计算#把最终得到的回归系数放入直线中 这条直线为不同类别之间的分割线#缺点:每次更新回归系数都需要遍历整个数据集,计算复杂度太高def gradAscent(dataMatIn, classLabels):    dataMatrix = np.mat(dataMatIn) #将列表转换为矩阵 100*3    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):        # 将特征乘以回归系数,再使用sigmoid,所得值为0到1,又因为真实类别特征为0和1,所以相减可以看作是两者之间的误差        h = sigmoid(dataMatrix * weights)         error = labelMat - h #用类别特征减去 sigmoid后的特征值 即计算真实类别和预测类别的差值,即误差        weights = weights + alpha * dataMatrix.transpose() * error #新的回归系数+=特征矩阵*误差矩阵*学习率    return weights

测试dataArr, labelMat = loadDataSet()
gradAscent(dataArr, labelMat)

结果
matrix([[ 4.12414349],
[ 0.48007329],
[-0.6168482 ]])

  • 画出数据集和Logistic回归最佳拟合直线的函数
def plotBestFit(weights):    import matplotlib.pyplot as plt    dataMat, labelMat = loadDataSet()     #print(type(dataMat)) #<class 'list'>    dataArr = np.array(dataMat) #<class 'numpy.ndarray'>    n = np.shape(dataArr)[0] #获取数据的条数    xcord1 = []; ycord1 = []    xcord2 = []; ycord2 = []    for i in range(n):        if int(labelMat[i]) == 1: #如果数据为类别1,将数据的特征赋给xcord1,ycord1            xcord1.append(dataArr[i, 1])            ycord1.append(dataArr[i, 2])        else: #如果数据为类别0,将数据的特征赋给xcord2,ycord2            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, 1.0) #根据图表 判定x的范围    y = (-weights[0]-weights[1] * x)/weights[2]  # 0 = w0x0 + w1x1 + w2x2  x0=1?  w0x0的作用?  sigmoid函数为0?    ax.plot(x,y)    plt.xlabel('X1')    plt.ylabel('X2')    plt.show()

测试

weights = gradAscent(dataArr, labelMat)#print(weights.getA()[0])  [ 4.12414349]  print(type(weights))   <class 'numpy.matrixlib.defmatrix.matrix'>#print(weights[0]) [[ 4.12414349]]   print(type(weights.getA()))   <class 'numpy.ndarray'>#print(type(weights))  <class 'numpy.ndarray'>plotBestFit(weights.getA()) #矩阵通过这个getA()这个方法可以将自身返回成一个n维数组对象  <class 'numpy.ndarray'>

结果
这里写图片描述

  • 随机梯度上升算法
#较之于上边的算法,该方法一次仅用一个样本点来更新回归系数#变量h和误差error都为向量,而上边的算法都是数值;上边的算法没有矩阵的转换过程,所有变量的数据类型都为numpy数组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)) #sum()? 上个算法使用特征矩阵减去h 而在本算法使用类别特征值减h 所以要用一个数        error = classLabels[i] - h        weights = weights + alpha*error*dataMatrix[i]    return weightsweights = stocGradAscent0(np.array(dataArr), labelMat)plotBestFit(weights)

结果
这里写图片描述
- 改进的随机梯度上升算法

#两处优化:1 alpha会随着迭代进行调整,2随即获取样本更新回归系数,一方面可以减少周期性波动,二是可以使函数收敛更快def stocGradAscent1(dataMarix, classLabels, numIter=150):    m,n = np.shape(dataMarix)    weights = np.ones(n)    for j in range(numIter):        dataIndex = list(range(m))        for i in range(m):            #alpha随着迭代次数不断减小,但不会变为0, 当j << max(i)时,alpha就不是严格下降            alpha = 4/(1.0 + j + i) + 0.01            #随即获取样本来更新回归系数,能够减少周期新波动,使函数收敛更快            randIndex = int(np.random.uniform(0, len(dataIndex)))            h = sigmoid(sum(dataMarix[randIndex]*weights))             error = classLabels[randIndex] -h            weights = weights + alpha * error * dataMarix[randIndex]            del(dataIndex[randIndex])    return weightsweights = stocGradAscent1(np.array(dataArr), labelMat,500)plotBestFit(weights)

结果
这里写图片描述
- Logistic回归分类函数

def classifyVector(inX, weights):    prob = sigmoid(sum(inX*weights))    if prob > 0.5 :  return 1.0    else: return 0.0def 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[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):            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 errorRatedef 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)))

运行结果

the error rate of this test is: 0.417910the error rate of this test is: 0.268657the error rate of this test is: 0.313433the error rate of this test is: 0.358209the error rate of this test is: 0.298507the error rate of this test is: 0.373134the error rate of this test is: 0.417910the error rate of this test is: 0.328358the error rate of this test is: 0.492537the error rate of this test is: 0.388060after 10 iterations the average error rate is: 0.365672
  • 遗留问题
    1.在plotBestFit()函数中,计算Logistic回归最佳拟合直线时,根据方程0 = w0x0 + w1x1 + w2x2 x0=1,可是数据集只有两个特征X1 和X2 那W0和X0的作用是什么?为什么要把X0设为1
    2.在stocGradAscent0()函数中,计算预测值时的代码为h = sigmoid(sum(dataMatrix[i] * weights)),计算误差的代码为error = classLabels[i] - h 误差 = 真实类别的特征值 - 该数据的特征值与回归系数的乘积之和 ,预测值 == 该数据的特征值与回归系数的乘积之和的sigmoid值 ???,如果只是为了得到一个相关的数字,那min()和max()为什么不行

  • 猜想

    1.w0x0是为了满足y = ax + b ?w0x0就是这里的b。如果不对,还请各位大牛指教!!
    2.因为每个特征的回归系数是一样的,所以使用sum()能够保证一条数据中的每个特征值都有参与,而min()和max()则不符合。(如果不同的特征都有自己的回归系数,应该就不会是线性拟合?)

  • 最后
    希望各位大佬多多指教,如果能帮我解决上面的两个问题就更好了!!!!

原创粉丝点击