Logistic回归

利用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 weights

weights = 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 weights

weights = 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.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[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 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)))

运行结果

the error rate of this test is: 0.417910
the error rate of this test is: 0.268657
the error rate of this test is: 0.313433
the error rate of this test is: 0.358209
the error rate of this test is: 0.298507
the error rate of this test is: 0.373134
the error rate of this test is: 0.417910
the error rate of this test is: 0.328358
the error rate of this test is: 0.492537
the error rate of this test is: 0.388060
after 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()则不符合。(如果不同的特征都有自己的回归系数,应该就不会是线性拟合?)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值