机器学习入门☞Logistic回归

版权声明:本文为博主原创文章,转载请注明原文地址:http://blog.csdn.net/helloworld_ptt https://blog.csdn.net/helloworld_ptt/article/details/82662442

源代码与资源文件
#本文适用读者:#
了解朴素贝叶斯,并且python version 为 3.x

##一、利用Logistic回归进行分类的主要思想:

其根据现有数据对分类边界线建立回归公式,以此进行分类.这里的"回归"一词源于最佳拟合,表示要找到最佳拟合参数集.

##二、优缺点:

优点:计算代价不高,易于理解与实现
缺点:容易欠拟合,分类精度可能不高
使用数据类型:数值型和标称型数据

##三、数学基础:
###Sigmoid函数:
在这里插入图片描述
当z为0时,Sigmoid函数值为0.5.随着x的增大,对应的Sigmoid值将逼近与1:而随着x的减小,Sigmoid值将逼近与0,如下图:
在这里插入图片描述

###分类器的实现:
我们在每个特征上乘以一个回归系数,然后把所有结果值相加,将这个总值代入Sigmoid函数中,进而得到一个范围在0~1之间的数值.最后,结果大于0.5的数据被归入1类,小于0.5的就被归入0类.所以Logistic回顾也可以看成是一种概率估计
###梯度上升法:
如果梯度记为▽,则函数f(x,y)的梯度由下式表示:
在这里插入图片描述

梯度意味着x的变化量是f(x,y)对x的偏导,y的变化量是f(x,y)对y的偏导.其中,函数f(x,y)必须要在待计算的点上有定义并且可微,举一个栗子:
在这里插入图片描述

梯度上升算法到达每个点后都会重新估计移动的方向.即重新计算偏导. 从P0开始, 计算完该点的梯度, 函数就根据梯度移动到下一点P1. 在P1点, 梯度在此被重新计算, 并沿新的梯度方向移动到P2. 如此循环迭代,知道满足停止条件. 迭代过程中, 梯度算子总是保证我们能选取到最佳的移动方向
##四、程序清单:
###logistic回归梯度上升优化算法:
将以下代码写入logRegres.py文件中

import numpy as np
import matplotlib.pyplot as plt 
#loadDataSet函数用于读取txt数据文档,将文档中数据处理成两个向量dataMat,与labelMat
def loadDataSet():
    dataMat = []; 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])])
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat
       
def sigmoid(inX):
    return 1.0/(1+np.exp(-inX))
#gradAscent函数
def gradAscent(dataMatIn, classLabels):
    #转换为NumPy矩阵数据类型
    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 = sigmoid(dataMatrix * weights)
        error = (labelMat - h)
        weights = weights + alpha * dataMatrix.transpose() * error
    return weights

###图形化程序:
将以下代码写入logRegres.py文件中

def plotBestFit(wei):
    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:
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
        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 = np.arange(-3.0, 3.0, 0.1)
    #最佳拟合直线
    y = (-wei[0]-wei[1]*x)/wei[2]
    ax.plot(x,y)
    plt.xlabel('X1'); plt.ylabel('X2');
    plt.show()

测试一下:

import logRegres
import numpy as np
dataArr,labelMat = logRegres.loadDataSet()
weights = logRegres.gradAscent(dataArr,labelMat)
logRegres.plotBestFit(np.array(weights))

这里写图片描述
这是梯度上升算法迭代500次的结果:得到一条Logistic回归最佳拟合直线
###随机梯度上升算法:
将以下代码写入logRegres.py文件中

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
        weights = weights + alpha * error * dataMatrix[i]
    return weights

测试一下:

dataArr,labelMat = logRegres.loadDataSet()
weight = logRegres.stocGradAscent0(np.array(dataArr),labelMat)
logRegres.plotBestFit(weight)

结果:
这里写图片描述
###改进的随机梯度上升算法:
将以下代码写入logRegres.py文件中

def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    m,n = np.shape(dataMatrix)
    weights = np.ones(n)
    for j in range(numIter):        
        dataIndex = list(range(m))
        for i in range(m):
            # alpha 每次迭代时需要调整
            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])
    return weights

通过避免alpha参数的严格下降.来调整收敛的速度
测试一下:

weights = logRegres.stocGradAscent1(np.array(dataArr), labelMat)
logRegres.plotBestFit(weights)

结果:
这里写图片描述
我们可以看到,这个只遍历20次的与遍历500次的结果很接近了,说明优化是有效的
而且我们还可以通过修改迭代次数来获取更加精确的结果:

weights = logRegres.stocGradAscent1(np.array(dataArr), labelMat, 500)
logRegres.plotBestFit(weights)

结果:
这里写图片描述
##五、从疝气病症预测病马的死亡率

现在我们有horseColicTest.txt与horseColicTraining.txt两个文件,这两个文件已经经过预处理,但是数据集中是有30%缺失的,那么我们如何处理数据中的缺失值呢?

-使用可用特征的均值来填补缺失值
-使用特殊值来填补缺失值
-忽略有缺失值的样本
-使用相似样本的均值填补缺失值
-使用另外的机器学习算法预测缺失值
在本例中,我们将缺失值用0代替,因为sigmoid(0) = 0.5,这个结果对预测不具有倾向性,不会改变误差
###使用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)))

测试一下:

logRegres.multiTest()

结果:
这里写图片描述

在经过一系列调参之后:
得到最优的结果是

这里写图片描述

猜你喜欢

转载自blog.csdn.net/helloworld_ptt/article/details/82662442
今日推荐