机器学习实战 - Logistic回归

本文介绍了Logistic回归在二类分类中的应用,使用Sigmoid函数替代阶跃函数进行平滑处理。通过梯度上升法求解最大似然估计的参数,进而确定分类概率。文中详细解释了为何选择梯度上升法,并通过实例展示了Logistic回归的实现过程,包括数据预处理、模型训练和效果评估。在大数据场景下,还探讨了随机梯度上升法作为优化策略的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

假设我们有 一些数据点,我们用一条直线对其进行拟合,那么拟合的过程就称为回归。

实际上Logistic回归经常用于二类分类,也就是一般只用于只存在两种诸如“是”与“不是”等的问题,我们需要这么一个函数,能接收所有输入然后预测出类别。要找到只存在两种分类的函数,阶跃函数是个不错的选择,但是有一个问题,阶跃函数在跳跃点处如何处理?所以我们引入另一个函数——Sigmoid函数代替阶跃函数,Sigmoid函数的定义如下:

h(z)=11+ez
这里我们需要确定输入的参数 z 来得到相应的σ值,假设我们将两种结果映射成数字上的0和1,根据sigmoid函数的图像:

这里写图片描述

我们可以利这个式子来进行分类:这里写图片描述

由上面的图像和公式都可以得出,这里不存在阶跃函数中的跳跃点,可以接受任何输入,那么 z 是什么?实际上,z与函数的自变量有关,我们也可以称这些自变量为“特征”,一个自变量就是一个特征。 z 的定义如下:

z=θ0x0+θ1x1+θ2x2+...+θnxn
这里的 xi 就是我们函数的第 i 个自变量,或者说是描述某个问题所使用的“特征”。

我们将使用梯度上升法来求解二分类问题,很多博客和文章甚至于本书都没有简述为什么要使用梯度上升法来解决这个问题,这里我们来描述一下,让读者更加清晰。首先,我们得知道梯度是什么,在数学上的定义是,梯度是某个函数关于所有自变量求偏导得到的一个向量,如果我们对函数中的某一个变量进行求偏导,得到的在某个点上的偏导数就是该函数“沿着这个特征变量变化速率最快的方向”,默认为上升(也就是增加幅度最大的方向),加个负号就变成了下降幅度最大的方向。现在我们不取某一个特征,而是取所有特征组成的梯度向量来使用,就变成了该函数综合考虑所有的特征之后“整体”变化最快的方向,我们换个术语可以理解为“最大化收益”。梯度上升法就是求函数最大值的方法,不过其步骤是一步一步逼近最大值,相同的,梯度下降法就是求函数最小值的方法。

我们结合之前的讨论,可以综合得出我们所需要求的函数是有关得到相应分类概率的函数:

P(y|x)=(11+ez)y(111+ez)1y
也就是在输入 x 后得到类别为y的概率,这里的y只取0或1,实际上:

P(y|x)=(11+ez)y=1
P(y|x)=(111+ez)y=0

换句话说,当得到的类别是1的使用我们使用的是第一个式子,类别为0的使用我们使用的是第二个式子,所以总公式很好的综合了两种情况,现在我们要求得就是使得这个概率最大化,所以我们要利用梯度上升法来一步一步逼近最大值。

在知道了为何要使用梯度上升法之后,我们转过来就是要使用梯度上升法确定 z 也就是确定所有的θi

现在假设我们有这样的数据,这些数据是二维平面上的一些点,每个点都有自己的分类,这里被映射成0跟1,点的分布如下图所示:

这里写图片描述

其中 X1,X2 是这些点的两个特征,通常我们会额外的增加一个特征 X0 并且默认初始化所有的 X0 为1,通常 θ0 决定的是线的偏移量,其它的决定的是线的倾斜度吗,视情况而定,我们现在就是要确定 θ0,θ1,θ2 从而得到 z=X0θ0+X1θ1+X2θ2
借用一下别人的图:

这里写图片描述
这里写图片描述

我们新建一个文件命名为logRegres.py(整个程序在python3.6中运行):

from numpy import *

def loadDateSet():
    dataMat = []
    labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split('\t')
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        labelMat.append(float(lineArr[2]))
    return dataMat, labelMat


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


def gradAscent(dataMatIn, labelMatIn):
    dataMatrix = mat(dataMatIn)
    labelMat = mat(labelMatIn).transpose()
    n, m = shape(dataMatrix)
    alpha = 0.001
    weights = ones((m, 1))
    for i in range(500):
        h = sigmoid(dataMatrix * weights)
        """这里相减不能反过来, 这里表示的意思是真实类别与预测类别的差值, 如果反过来要利用梯度下降法"""
        error = (labelMat - h)
        """这里为什么是这样计算, 推导过程在下面"""
        weights = weights + alpha * dataMatrix.transpose() * error
    return weights

再新建一个test.py:

import logRegres

dataMat, labelMat = logRegres.loadDateSet()

print(logRegres.gradAscent(dataMat, labelMat))
"""
答案如下:
[[ 4.12414349]
 [ 0.48007329]
 [-0.6168482 ]]
"""

我们来看一下为什么在刚才的程序中:

h = sigmoid(dataMatrix * weights)
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose() * error

在前面的推断中,得知要计算概率的最大值可以通过梯度上升法求解,实际上我们利用概率论的极大似然估计来确定 θ 向量。来自总体简单样本 X 的简单样本X1,X2,...,Xn的联合密度 L(θ,x1,x2,...,xn) (下面简写成 L(θ) )称为 θ 的似然函数,定义如下:

L(θ,x1,x2,...,xn)=i=1nP(Xi=xi)
由于 θ 未知,所以事件 X1=x1,...,Xn=xn 的概率并不知道,但这一事件在一次试验中恰恰发生了,因此有理由把使得这一事件发生的概率最大的那个 θ 指作为 θ 的估计值,这就是极大似然估计的基本思想,于是
L(θ,x1,x2,...,xn)=i=1nP(Xi=xi)=i=1n(11+ez)yi(111+ez)1yi
=i=1n(hθ(x))yi(1hθ(x))1yi
对数似然函数为(这里的 xi,yi 代表的是第i组输入向量和其标签):
l(θ)=i=1n(yilog(hθ(xi))+(1yi)log(1hθ(xi)))
由于 log(x) 关于 x 是单调递增的,因此l(θ) L(θ) 有相同的极值点。总体的损失函数(const function)表示为:
J(θ)=1m(l(θ))
要求 l(θ) 最大,那么就是 J(θ) 最小,而按损失函数的定义,其值越小也就说明其预测值与真实值越接近,也就是差别越小。求损失函数的最小值可以利用梯度下降法求:
θi=θiαθiJ(θ)(j=1,2,3,...,n)

这里写图片描述

所以

θj=θjα1mi=1n(hθ(xi)yi)xj=θj+α1mi=1n(yihθ(xi))xij
由于 α 本身是一个常数,所以我们去掉常数 1m 这就是书本中梯度上升法:
weights = weights + alpha * dataMatrix.transpose() * error

既然知道了原理,我们将所有的散点都画出来,并根据计算的权重值画出直线(这里是直线,其它维度可能无法想象-_-!),logRegres.py加入:

def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat, labelMat = loadDateSet()
    dataArr = array(dataMat)
    n = shape(dataArr)[0]
    xcord1 = []
    ycord1 = []
    xcord0 = []
    ycord0 = []
    for i in range(n):
        if int(labelMat[i]) == 1:
            xcord1.append(dataArr[i, 1])
            ycord1.append(dataArr[i, 2])
        else:
            xcord0.append(dataArr[i, 1])
            ycord0.append(dataArr[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
    ax.scatter(xcord0, ycord0, s=30, c='green')
    x = arange(-3.0, 3.0, 0.1)
    """
    这里我们取w0x0+w1x1+w2x2 = 0
    也就是weight[0] + weight[1]x + weight[2]y = 0
    因为我们在sigmoid函数分类的时候输入的是以z=0的位置分类的, 此时p(z) = 0.5
    """
    y = (-weights[0] - weights[1]*x)/weights[2]
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()

test.py加入:

"""矩阵通过getA()这个方法可以将自身返回成一个n维数组对象"""
logRegres.plotBestFit(weights.getA())

得到结果如下图:

这里写图片描述

效果不错,在我们初学者看来,嘻嘻!但是,这里我们每次计算的时候都要相乘大约300次,因此,我们要继续改进算法。

训练算法:随机梯度上升
梯度上升算法每次都要遍历整个数据集,这对于少量数据还是可以接受的, 但是如果对于大数据如千万上亿级别的,那么时间复杂度就太高了。一种改进的算法就是每次使用数据集中一个样本点来更新回归系数,该方法称为随机梯度上升,随机梯度上升可以在新样本到来之前进行增量式更新,因此也被称为一个在线学习算法。伪代码如下:

首先初始化所有回归系数为1
对数据集中的每个样本点:
    计算样本的梯度
    使用alpha*gradient更新回归系数
返回回归系数
def stocGradAscent0(dataMat, labelMat):
    n, m = shape(dataMat)
    alpha = 0.01
    weights = ones(m)
    print(weights)
    for i in range(n):
        h = sigmoid(sum(dataMat[i]*weights))
        error = labelMat[i] - h
        weights = weights + alpha * error * dataMat[i]
    return weights

结果如下:

这里写图片描述

上图的分类效果很不理想,也难怪,我们没有进行迭代,只是把所有数据带进去求了一遍回归系数。我们看一下它3个weights值的变化,在logRegres.py加入以下代码:

"""这个函数与stocGradAscent0一样, 只不过增加了一个保存历史weights点的功能, 为后面画图用"""
def stocGradAscent0ToGetDynamicWeights(dataMat, labelMat):
    n, m = shape(dataMat)
    alpha = 0.01
    weights = ones(m)
    weightsDynamic = []
    for j in range(200):
        for i in range(n):
            h = sigmoid(sum(dataMat[i] * weights))
            error = labelMat[i] - h
            weights = weights + alpha * error * dataMat[i]
            weightsDynamic.append(weights)
    return weightsDynamic

"""画图"""
def plotWeights(weightsDynamic):
    import matplotlib.pyplot as plt
    n = len(weightsDynamic)
    ycord0 = []
    ycord1 = []
    ycord2 = []
    for i in range(n):
        ycord0.append(weightsDynamic[i, 0])
        ycord1.append(weightsDynamic[i, 1])
        ycord2.append(weightsDynamic[i, 2])
    fig = plt.figure()
    ax0 = fig.add_subplot(311)
    ax1 = fig.add_subplot(312)
    ax2 = fig.add_subplot(313)
    x = arange(0, n, 1)
    ax0.plot(x, ycord0)
    ax1.plot(x, ycord1)
    ax2.plot(x, ycord2)
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()

test.py中调用:

weightsDynamic = logRegres.stocGradAscent0ToGetDynamicWeights(array(dataMat), labelMat)
logRegres.plotWeights(array(weightsDynamic))

这里写图片描述

上图是设置迭代200次之后得到的图,跟书本上的图结果不一样,虽然课本上的图经过50次迭代看起来确实很稳定,但这跟我们一开始得到的3个系数[ 4.12414349][ 0.48007329][-0.6168482 ]好像有点偏差,而这里得到的图像更符合实际情况。一开始三个值都是剧烈变化的,所以一开始是没有正常分类的,到后期,每个值都逐步趋于稳定,随之而来的,其分类正确率就逐渐的上升。

我们可以一开始提升一下其收敛速度,让后期的收敛速度减小来加快我们稳定系数的速度,随着迭代次数的上升收敛速度较小,随着每次迭代更新的数据的数量增加来降低收敛速度,在logRegres.py加入以下代码:

def stocGradAscent1(dataMat, labelMat, numIter=150):
    n, m = shape(dataMat)
    weights = ones(m)
    for i in range(numIter):
        dataIndex = range(n)
        for j in range(n):
            alpha = 4 / (1.0 + i + j) + 0.01
            numIndex = int(random.uniform(0, len(dataIndex)))
            h = sigmoid(sum(dataMat[numIndex] * weights))
            error = labelMat[numIndex] - h
            weights = weights + alpha * error * dataMat[numIndex]
    return weights

在test.py中调试:

weights= logRegres.stocGradAscent1(array(dataMat), labelMat)
logRegres.plotBestFit(weights)

这里写图片描述

这是迭代150次后得到的效果,可以接受,我们再看看其系数的变化情况,在logRegres.py加入以下代码:

def stocGradAscent1ToGetDynamicWeights(dataMat, labelMat, numIter=150):
    n, m = shape(dataMat)
    weights = ones(m)
    weightsDynamic = []
    for i in range(numIter):
        dataIndex = range(n)
        for j in range(n):
            alpha = 4 / (1.0 + i + j) + 0.01
            numIndex = int(random.uniform(0, len(dataIndex)))
            if i == 0 and j ==0:
                print(numIndex)
            h = sigmoid(sum(dataMat[numIndex] * weights))
            error = labelMat[numIndex] - h
            weights = weights + alpha * error * dataMat[numIndex]
            weightsDynamic.append(weights)
    return  weightsDynamic

test.py中调试:

weightsDynamic = logRegres.stocGradAscent1ToGetDynamicWeights(array(dataMat), labelMat)
logRegres.plotWeights(array(weightsDynamic))

这里写图片描述

可以发现,其收敛的非常快,虽然X1还是有波动,可能是因为迭代次数的关系导致 α 改变还是挺大的。

现在,我们根据随机梯度上升得到了比梯度上升复杂度更小的方法来解决这类问题,那下面就根据课本的示例:从疝气病症状预测病马的死亡率。我们获得的数据有些不是相关特征的描述,去掉这些无关项之后,这里有21个特征来描述疝气病,有的关系挺大有的不太大,我们要根据这21个特征确定每个特征的系数,得到的分类有“仍存活”、“已经死亡”、“已经安乐死”,为了方便计算,把“已经死亡”、“已经安乐死”合并成为“未能存活”这个标签。我们可以直接利用本书中的数据,也可以从最新的数据中获取,笔者两种都试过了,现在以最新的数据为例,在获取样例数据(点击此处)中可以得到相应的未处理的数据,数据中有很多缺失项大约30%,如何处理的?对于要进行训练的数据,如果数据缺失,我们只需要把该项数据值置为0即可,置为0的话说明这个样例数据的这一项对当前该特征的系数不会产生影响,这样做是合理的。对于要测试的数据,假设该数据的最后分类标签缺失的话,我们就要把这条数据抛弃不做测试,因为我们无法就是要根据程序预测它的结果,而不是人为的给它一个主观的结果然后再输入到程序去预测,这没有意义。所以总结起来就是无论是训练还是测试的数据,除标签外,数据缺失的置为0,分类标签缺失的某条数据需要抛弃。

我们在logRegres.py中加入以下代码处理数据:

"""
比如我们将horseColicTrainingOriginal.txt的数据处理后放到horseColicTraining.txt中
我这里是去掉了第3列和24列之后的数据,第24列是分类标签
"""
def getDataFromFile(filename):
    fr = open(filename)
    tempName = str(filename).split('Original')
    writeFileName = tempName[0] + "1.txt"
    output = ""
    for Line in fr.readlines():
        line = Line.strip().split(' ')
        if line[23] == '?':
            continue
        for i in range(23):
            if i != 2:
                if line[i] == '?':
                    output += "0\t"
                else:
                    output += line[i] + "\t"
        """“已经死亡”、“已经安乐死”合并成为“未能存活”"""
        if (line[23] == '1'):
            output += '1'
        else:
            output += '0'
        output += '\n'
    fw = open(writeFileName, 'w')
    fw.write(output)

test.py中处理:

"""存放在horseColicTraining1.txt"""
logRegres.getDataFromFile('horseColicTrainingOriginal.txt')
"""存放在horseColicTest1.txt"""
logRegres.getDataFromFile('horseColicTestOriginal.txt')

要处理得到的数据,logRegres.py中加入:

def classifyVector(inX, weights):
    if sigmoid(sum(inX*weights)) > 0.5:
        return 1.0
    else:
        return 0.0


def calicTest():
    frTrain = open('horseColicTraining1.txt');
    frText = open('horseColicTest1.txt');
    trainingMat = []
    trainingLabel = []
    for line in frTrain.readlines():
        data = line.strip().split('\t')
        nextData = []
        for i in range(22):
            nextData.append(float(data[i]))
        trainingMat.append(nextData)
        trainingLabel.append(float(data[22]))
    weights = stocGradAscent1(array(trainingMat), trainingLabel, 100)
    errorNum = 0.0
    num = 0.0
    for line in frText.readlines():
        num += 1.0
        data = line.strip().split('\t')
        testData = []
        for i in range(22):
            testData.append(float(data[i]))
        testLabel = data[22]
        """使用sigmiod函数分类的时候可能由于数字过小出现溢出警告, 别人的解法是使用bigfloat或忽略警告"""
        if int(classifyVector(array(testData), weights)) != int(testLabel):
            errorNum += 1.0
    errorRate = float(errorNum)/num
    print("The error rate of this classify is ", errorRate)
    return errorRate


def multiTest():
    errorRate = 0.0
    for i in range(10):
        errorRate += calicTest()
    print("after 10 iterators the average error rate is: %f" % (errorRate/float(10)))

"""

调试test.py:

logRegres.multiTest()
"""
答案如下:数据会有变动
The error rate of this classify is  0.29411764705882354
The error rate of this classify is  0.2647058823529412
The error rate of this classify is  0.2647058823529412
The error rate of this classify is  0.29411764705882354
The error rate of this classify is  0.3382352941176471
The error rate of this classify is  0.20588235294117646
The error rate of this classify is  0.35294117647058826
The error rate of this classify is  0.25
The error rate of this classify is  0.3382352941176471
The error rate of this classify is  0.29411764705882354
after 10 iterators the average error rate is: 0.289706  
"""

附上完整程序logRegres.py:

from numpy import *

def loadDateSet():
    dataMat = []
    labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split('\t')
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        labelMat.append(float(lineArr[2]))
    return dataMat, labelMat


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


def gradAscent(dataMatIn, labelMatIn):
    dataMatrix = mat(dataMatIn)
    labelMat = mat(labelMatIn).transpose()
    n, m = shape(dataMatrix)
    alpha = 0.001
    weights = ones((m, 1))
    for i in range(500):
        h = sigmoid(dataMatrix * weights)
        """这里相减不能反过来, 这里表示的意思是真实类别与预测类别的差值, 如果反过来要利用梯度下降法"""
        error = (labelMat - h)
        """这里为什么是这样计算, 推导过程在下面"""
        weights = weights + alpha * dataMatrix.transpose() * error
    return weights


def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat, labelMat = loadDateSet()
    dataArr = array(dataMat)
    n = shape(dataArr)[0]
    xcord1 = []
    ycord1 = []
    xcord0 = []
    ycord0 = []
    for i in range(n):
        if int(labelMat[i]) == 1:
            xcord1.append(dataArr[i, 1])
            ycord1.append(dataArr[i, 2])
        else:
            xcord0.append(dataArr[i, 1])
            ycord0.append(dataArr[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
    ax.scatter(xcord0, ycord0, s=30, c='green')
    x = arange(-3.0, 3.0, 0.1)
    """
    这里我们取w0x0+w1x1+w2x2 = 0
    也就是weight[0] + weight[1]x + weight[2]y = 0
    因为我们在sigmoid函数分类的时候输入的是以z=0的位置分类的, 此时p(z) = 0.5
    """
    y = (-weights[0] - weights[1]*x)/weights[2]
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()


def stocGradAscent0(dataMat, labelMat):
    n, m = shape(dataMat)
    alpha = 0.01
    weights = ones(m)
    for i in range(n):
        h = sigmoid(sum(dataMat[i] * weights))
        error = labelMat[i] - h
        weights = weights + alpha * error * dataMat[i]
    return weights

"""这个函数与stocGradAscent0一样, 只不过增加了一个保存历史weights点的功能, 为后面画图用"""
def stocGradAscent0ToGetDynamicWeights(dataMat, labelMat):
    n, m = shape(dataMat)
    alpha = 0.01
    weights = ones(m)
    weightsDynamic = []
    for j in range(10):
        for i in range(n):
            h = sigmoid(sum(dataMat[i] * weights))
            error = labelMat[i] - h
            weights = weights + alpha * error * dataMat[i]
            weightsDynamic.append(weights)
    return weightsDynamic

"""画图"""
def plotWeights(weightsDynamic):
    import matplotlib.pyplot as plt
    n = len(weightsDynamic)
    ycord0 = []
    ycord1 = []
    ycord2 = []
    for i in range(n):
        ycord0.append(weightsDynamic[i, 0])
        ycord1.append(weightsDynamic[i, 1])
        ycord2.append(weightsDynamic[i, 2])
    fig = plt.figure()
    ax0 = fig.add_subplot(311)
    ax1 = fig.add_subplot(312)
    ax2 = fig.add_subplot(313)
    x = arange(0, n, 1)
    ax0.plot(x, ycord0)
    ax1.plot(x, ycord1)
    ax2.plot(x, ycord2)
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()


def stocGradAscent1(dataMat, labelMat, numIter=150):
    n, m = shape(dataMat)
    weights = ones(m)
    for i in range(numIter):
        dataIndex = range(n)
        for j in range(n):
            alpha = 4 / (1.0 + i + j) + 0.01
            numIndex = int(random.uniform(0, len(dataIndex)))
            h = sigmoid(sum(dataMat[numIndex] * weights))
            error = labelMat[numIndex] - h
            weights = weights + alpha * error * dataMat[numIndex]
    return weights


def stocGradAscent1ToGetDynamicWeights(dataMat, labelMat, numIter=150):
    n, m = shape(dataMat)
    weights = ones(m)
    weightsDynamic = []
    for i in range(numIter):
        dataIndex = range(n)
        for j in range(n):
            alpha = 4 / (1.0 + i + j) + 0.01
            numIndex = int(random.uniform(0, len(dataIndex)))
            if i == 0 and j ==0:
                print(numIndex)
            h = sigmoid(sum(dataMat[numIndex] * weights))
            error = labelMat[numIndex] - h
            weights = weights + alpha * error * dataMat[numIndex]
            weightsDynamic.append(weights)
    return  weightsDynamic


def classifyVector(inX, weights):
    if sigmoid(sum(inX*weights)) > 0.5:
        return 1.0
    else:
        return 0.0

# def calicTest():
#     frTrain = open('horseColicTraining.txt');
#     frText = open('horseColicTest.txt');
#     trainingMat = []
#     trainingLabel = []
#     for line in frTrain.readlines():
#         data = line.strip().split('\t')
#         nextData = []
#         for i in range(21):
#             nextData.append(float(data[i]))
#         trainingMat.append(nextData)
#         trainingLabel.append(float(data[21]))
#     weights = stocGradAscent1(array(trainingMat), trainingLabel, 50)
#     errorNum = 0.0
#     num = 0.0
#     for line in frText.readlines():
#         num += 1.0
#         data = line.strip().split('\t')
#         testData = []
#         for i in range(21):
#             testData.append(float(data[i]))
#         testLabel = data[21]
#         """使用sigmiod函数分类的时候可能由于数字过小出现溢出警告, 别人的解法是使用bigfloat或忽略警告"""
#         if int(classifyVector(array(testData), weights)) != int(testLabel):
#             errorNum += 1.0
#     errorRate = float(errorNum)/num
#     print("The error rate of this classify is ", errorRate)
#     return errorRate


def calicTest():
    frTrain = open('horseColicTraining1.txt');
    frText = open('horseColicTest1.txt');
    trainingMat = []
    trainingLabel = []
    for line in frTrain.readlines():
        data = line.strip().split('\t')
        nextData = []
        for i in range(22):
            nextData.append(float(data[i]))
        trainingMat.append(nextData)
        trainingLabel.append(float(data[22]))
    weights = stocGradAscent1(array(trainingMat), trainingLabel, 100)
    errorNum = 0.0
    num = 0.0
    for line in frText.readlines():
        num += 1.0
        data = line.strip().split('\t')
        testData = []
        for i in range(22):
            testData.append(float(data[i]))
        testLabel = data[22]
        """使用sigmiod函数分类的时候可能由于数字过小出现溢出警告, 别人的解法是使用bigfloat或忽略警告"""
        if int(classifyVector(array(testData), weights)) != int(testLabel):
            errorNum += 1.0
    errorRate = float(errorNum)/num
    print("The error rate of this classify is ", errorRate)
    return errorRate


def multiTest():
    errorRate = 0.0
    for i in range(10):
        errorRate += calicTest()
    print("after 10 iterators the average error rate is: %f" % (errorRate/float(10)))

"""
比如我们将horseColicTrainingOriginal.txt的数据处理后放到horseColicTraining.txt中
我这里是去掉了第3列和24列之后的数据,第24列是分类标签
"""
def getDataFromFile(filename):
    fr = open(filename)
    tempName = str(filename).split('Original')
    writeFileName = tempName[0] + "1.txt"
    output = ""
    for Line in fr.readlines():
        line = Line.strip().split(' ')
        if line[23] == '?':
            continue
        for i in range(23):
            if i != 2:
                if line[i] == '?':
                    output += "0\t"
                else:
                    output += line[i] + "\t"
        """“已经死亡”、“已经安乐死”合并成为“未能存活”"""
        if (line[23] == '1'):
            output += '1'
        else:
            output += '0'
        output += '\n'
    fw = open(writeFileName, 'w')
    fw.write(output)

test.py:

import logRegres
from numpy import *

dataMat, labelMat = logRegres.loadDateSet()

# weights, weightsDynamic = logRegres.gradAscent(dataMat, labelMat)
# print(weights)
# """
# 答案如下:
# [[ 4.12414349]
#  [ 0.48007329]
#  [-0.6168482 ]]
# """
#
# """矩阵通过getA()这个方法可以将自身返回成一个n维数组对象"""
# logRegres.plotBestFit(weights.getA())

# weights = logRegres.stocGradAscent0(array(dataMat), labelMat)
# logRegres.plotBestFit(weights)
# weightsDynamic = logRegres.stocGradAscent0ToGetDynamicWeights(array(dataMat), labelMat)
# logRegres.plotWeights(array(weightsDynamic))

# weights= logRegres.stocGradAscent1(array(dataMat), labelMat)
# logRegres.plotBestFit(weights)
# weightsDynamic = logRegres.stocGradAscent1ToGetDynamicWeights(array(dataMat), labelMat)
# logRegres.plotWeights(array(weightsDynamic))

# logRegres.multiTest()

# """存放在horseColicTraining1.txt"""
# logRegres.getDataFromFile('horseColicTrainingOriginal.txt')
# """存放在horseColicTest1.txt"""
# logRegres.getDataFromFile('horseColicTestOriginal.txt')

logRegres.multiTest()
"""
答案如下:
The error rate of this classify is  0.29411764705882354
The error rate of this classify is  0.2647058823529412
The error rate of this classify is  0.2647058823529412
The error rate of this classify is  0.29411764705882354
The error rate of this classify is  0.3382352941176471
The error rate of this classify is  0.20588235294117646
The error rate of this classify is  0.35294117647058826
The error rate of this classify is  0.25
The error rate of this classify is  0.3382352941176471
The error rate of this classify is  0.29411764705882354
after 10 iterators the average error rate is: 0.289706  
"""
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值