逻辑回归实例:从疝气病预测病马的死亡率

先了解大致模型建立的流程,接下来我会弄一些算法的原理及梯度上升的对比:

数据有三部分:

梯度算法公式:

附完整版代码:

from numpy import *
import numpy as np


def loadDataSet():
    dataMat = [];
    labelMat = []
    fr = open('D:\\machinelearn_data\\testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        print(int(lineArr[2]))
        # strip() 方法用于移除字符串头尾指定的字符(默认为空格)
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        # 第一列是1,另外加的,即形如[1,x1,x2]
        labelMat.append(int(lineArr[2]))
        #print(labelMat)
    return dataMat, labelMat  # 此时是数组


def sigmoid(inX):
    return 1.0 / (1 + exp(-inX))  # 返回一个0-1的100*1的数组


# 梯度上升
def gradAscent(dataMatIn, classLabels):
    dataMatrix = mat(dataMatIn)  # convert to NumPy matrix  # 转换成numpy矩阵(matrix),dataMatrix:100*3
    labelMat = mat(classLabels).transpose()  # convert to NumPy matrix # transpose转置为100*1
    m, n = shape(dataMatrix)  # 得到行和列数,0代表行数,1代表列数
    alpha = 0.001  # 步长
    maxCycles = 500  # 最大迭代次数
    weights = ones((n, 1))  # 3*1的矩阵,其权系数个数由给定训练集的维度值和类别值决定
    for k in range(maxCycles):  # heavy on matrix operations
        h = sigmoid(dataMatrix * weights)  # matrix mult # 利用对数几率回归,z = w0 +w1*X1+w2*X2,w0相当于b
        error = (labelMat - h)  # vector subtraction
        weights = weights + alpha * dataMatrix.transpose() * error  # matrix mult  # 一种极大似然估计的推到过程,但每次的权系数更新都要遍历整个数据集
    return weights


# 画出数据集和Logistic分类直线的函数
def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat, labelMat = loadDataSet()  # 加载数据集,训练数据和标签
    dataArr = array(dataMat)  # 进行数据处理,必须转换为numpy中的array
    n = 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 = arange(-3.0, 3.0, 0.1)
    # print(type(x))
    y = (-weights[0] - weights[1] * x) / weights[2]  # 换算后的简化形式
    y1 = y.T  # 转置换类型 或者其他api都可以试试

    # print(type(y))
    # m,b = np.polyfit(x,y)
    ax.plot(x, y1)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()


# 梯度上升算法
"""
设定循环迭代次数,权重系数的每次更新是荣国计算所有样本得出来的,当训练集过于庞大不利于计算
"""


def stocGradAscent0(dataMatrix, classLabels):
    m, n = shape(dataMatrix)
    alpha = 0.01  # x学习率
    weights = ones(n)  # initialize to all ones
    for i in range(m):
        h = sigmoid(sum(dataMatrix[i] * weights))
        error = classLabels[i] - h
        weights = weights + alpha * error * dataMatrix[i]
    return weights


# 随机梯度上升
"""
对梯度上升算法进行改进,权重系数的每次更新通过训练集的每个记录计算得到
可以在新样本到来时分类器进行增量式更新,因为随机梯度算法是个更新权重的算法
但是算法容易受到噪声点的影响。在大的波动停止后,还有小周期的波动
"""

"""
前者的h,error 都是数值,前者没有矩阵转换过程,后者都是向量,数据类型则变为numpy
"""
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    m, n = shape(dataMatrix)
    weights = ones(n)  # initialize to all ones
    for j in range(numIter):
        dataIndex = range(m)
        for i in range(m):
            alpha = 4 / (1.0 + j + i) + 0.0001  # apha decreases with iteration, does not
            randIndex = int(random.uniform(0, len(dataIndex)))  # go to 0 because of the constant
            h = sigmoid(sum(dataMatrix[randIndex] * weights))
            error = classLabels[randIndex] - h
            # 学习率:变化。随着迭代次数的增多,逐渐变下。
            # 权重系数更新:设定迭代次数,每次更新选择的样例是随机的(不是依次选的)。
            weights = weights + alpha * error * dataMatrix[randIndex]  # 分类函数
            # 为什么删除变量?
            #print(list(dataIndex)[randIndex])
            del (list(dataIndex)[randIndex])
    return weights


# 分类算法
def classifyVector(inX, weights):
    prob = sigmoid(sum(inX * weights))
    if prob > 0.5:
        return 1.0
    else:
        return 0.0


# 测试算法
"""
为了量化回归效果,使用错误率作为观察指标。根据错误率决定是否回退到训练阶段,通过改变迭代次数和步骤等参数来得到更好的回归系数。
"""


def colicTest():
    frTrain = open('D:\\machinelearn_data\\horseColicTraining.txt', encoding='utf8');
    frTest = open('D:\\machinelearn_data\\horseColicTest.txt', encoding='utf8')
    trainingSet = []
    trainingLabels = []
    # print(frTest)
    # print(frTrain)
    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(array(trainingSet), trainingLabels, 1000)
    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), 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)))


if __name__ == '__main__':
    # 入口函数:模型参数y=wx
    dataArr, labelMat = loadDataSet()
    #weights = gradAscent(dataArr, labelMat)  # dataArr:100*3,labelMat是一个列表
    weights = stocGradAscent1(array(dataArr),labelMat ,150)
    plotBestFit(weights)
    multiTest()
 

梯度优化示意图:

主要是对sigmoid函数的理解,如图,知道变量的变化范围,最优解,及跳跃函数的理解,就基本了解逻辑函数分类的原理了

不当之处,多多理解

猜你喜欢

转载自blog.csdn.net/qq_37928340/article/details/81095208