Logistic模型原理详解以及Python项目实现(2)

简介: Logistic模型原理详解以及Python项目实现(2)
import matplotlib.pyplot as plt
from numpy import *
def loadData():
    dataMat=[]
    labelMat=[]
    fr = open('sample1.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
        labelMat.append(int(lineArr[2]))
    # print(dataMat)
    # print(labelMat)
    return dataMat, labelMat
def plotDot():
    dataMat,labelMat=loadData()
    dataArr = array(dataMat)
    n = shape(dataArr)[0]
    x0=[]
    x1=[]
    y0=[]
    y1=[]
    for i in range(n):
        if labelMat[i]==1:
            x1.append(dataMat[i][1])
            y1.append(dataMat[i][2])
        else:
            x0.append(dataMat[i][1])
            y0.append(dataMat[i][2])
    print(x0)
    print(x1)
    fig = plt.figure()
    ax = fig.add_subplot(111)#分割为1行1列第1块
    ax.scatter(x0, y0, s=30, c='red', marker='s')
    ax.scatter(x1, y1, s=30, c='green')
    plt.show()
plotDot()


数据集中一共有100个点,每个点包含两个数值型特征:X1和X2。因此可以将数据在一个二维平面上展示出来。我们可以将第一列数据(X1)看作x轴上的值,第二列数据(X2)看作y轴上的值。而最后一列数据即为分类标签。根据标签的不同,对这些点进行分类。

梯度上升法的伪代码:

每个回归系数初始化为1
重复R次:
    计算整个数据集的梯度
    使用alpha * gradient更新回归系数的向量
返回回归系数


代码实现:


from numpy import *
#预处理数据
def loadDataSet():
    #创建两个列表
    dataMat=[];labelMat=[]
    #打开文本数据集
    fr=open('sample1.txt')
    #遍历文本的每一行
    for line in fr.readlines():
        #对当前行去除首尾空格,并按空格进行分离
        lineArr=line.strip().split()
        #将每一行的两个特征x1,x2,加上x0=1,组成列表并添加到数据集列表中
        dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
        #将当前行标签添加到标签列表
        labelMat.append(int(lineArr[2]))
    #返回数据列表,标签列表
    return dataMat,labelMat
#定义sigmoid函数
def sigmoid(inx):
    return 1.0/(1+exp(-inx))
#梯度上升法更新最优拟合参数
#@dataMatIn:数据集
#@classLabels:数据标签
def gradAscent(dataMatIn,classLabels):
    #将数据集列表转为Numpy矩阵
    dataMatrix=mat(dataMatIn)
    #将数据集标签列表转为Numpy矩阵,并转置
    labelMat=mat(classLabels).transpose()
    #获取数据集矩阵的行数和列数
    m,n=shape(dataMatrix)
    #学习步长
    alpha=0.001
    #最大迭代次数
    maxCycles=500
    #初始化权值参数向量每个维度均为1.0
    weights=ones((n,1))
    print(weights)
    #循环迭代次数
    for k in range(maxCycles):
        #求当前的sigmoid函数预测概率
        h=sigmoid(dataMatrix*weights)
        #***********************************************
        #此处计算真实类别和预测类别的差值
        #对logistic回归函数的对数释然函数的参数项求偏导
        error=(labelMat-h)
        #更新权值参数
        weights=weights+alpha*dataMatrix.transpose()*error
        #***********************************************
    return weights
dataMat,labelMat=loadDataSet()
m=gradAscent(dataMat,labelMat)
print(m)

20201220235626754.png


我们知道对回归系数进行更新的公式为:gif.gif其中gif.gif是对参数w求偏导数。则我们可以通过求导验证logistic回归函数对参数w的梯度为(y_{i}-sigmoidgif.gifgif.gifgif.gif

20201221001206124.png

5.2、画出决策边界

def plotBestFit(wei):
    import matplotlib.pyplot as plt
    weights = wei.getA()
    dataMat, labelMat = loadDataSet()
    dataArr = array(dataMat)
    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)
    y = (-weights[0]- weights[1]*x)/weights[2]
    ax.plot(x, y)
    plt.xlabel('X1');
    plt.ylabel('X2');  
    plt.show()
plotBestFit(m)

2020122100272221.png


在拟合分类线中,我们设定sigmoid函数为0。0是两个分类的分解处,因此我们设定gif.gif0=w_{0}x_{0}+w_{1}x_{1}+w_{2}x_{2},然后根据函数制定x坐标表示为x1,y坐标表示为x2,画出分类线。尽管分类结果不错,但是这个方法却需要大量计算。


5.3、  随机梯度上升


梯度上升算法在每次更新回归系数时需要遍历整个数据集,该方法在处理100个左右的数据集时尚可,但如果有数十亿样本和成千上万的特征,那么该方法就很费劲了。所有我们思考了优化,一次仅用一个样本点来更新回归系数,该方法称为随机梯度上升法。对应的更新公式是:

gif.gif


由于可以在新的样本到来时对分类器进行增量式更新,因而随机梯度上升算法是一个在线学习算法。与之对应的是批处理算法。

随机梯度上升伪代码:

所有回归系数初始化为1
对数据集中每个样本
    计算该样本的梯度
    使用alpha*gradient更新回归系数值
返回回归系数值

代码:

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

20201222093944172.png

随机梯度上升法和批量梯度上升法是两个极端,一个采用所有数据来梯度上升,一个用一个样本来梯度上升。自然各自的优缺点都非常突出。对于训练速度来说,随机梯度上升法由于每次仅仅采用一个样本来迭代,训练速度很快,而批量梯度上升法在样本量很大的时候,训练速度不能让人满意。对于准确度来说,随机梯度上升法用于仅仅用一个样本决定梯度方向,导致解很有可能不是最优。对于收敛速度来说,由于随机梯度上升法一次迭代一个样本,导致迭代方向变化很大,不能很快的收敛到局部最优解。 但值得一提的是,随机梯度上升法在处理非凸函数优化的过程当中有非常好的表现,由于其上升方向具有一定随机性,因此能很好的绕开局部最优解,从而逼近全局最优解。


一个判断优化算法的可靠办法是看它是否收敛,也就是说参数是否达到了稳定值,是否还会变化。对此观察随机梯度上升算法的3个参数的变化:


20201222104556476.png


def stocGradAscent0(dataMatrix,classLabels):
    m,n=shape(dataMatrix)
    print(n)
    x1 = arange(0, 142)
    y1=[]
    y2=[]
    y3=[]
    alpha=0.01
    weights=ones(n)
    dataMatrix=array(dataMat)
    for i in range(142):
        h=sigmoid(sum([dataMatrix[i]*weights]))
        error = classLabels[i]-h
        weights=weights+alpha*error*dataMatrix[i]
        y1.append(weights[0])
        y2.append(weights[1])
        y3.append(weights[2])
    fig=plt.figure(figsize=(14,14),dpi=100)
    plt.subplot(3, 1, 1)
    plt.plot(x1,y1)
    plt.subplot(3, 1, 2)
    plt.plot(x1, y2)
    plt.subplot(3, 1, 3)
    plt.plot(x1, y3)
    # ax = fig.add_subplot(111)
    # bx = fig.add_subplot(211)
    # cx = fig.add_subplot(311)
    # ax.plot(x1, y1)
    # bx.plot(x1,y2)
    # cx.plot(x1,y3)
    plt.show()
    return weights


我们发现第三个参数仅仅在50次迭代就达到了稳定值,而其他两个则需要更多次迭代。产生这种现象的原因是存在一些不能正确分类的样本点(数据集并非线性可分),在每次迭代时会引发系数的剧烈变化。


5.4、优化随机梯度上升

我们对随机梯度上升算法做一些调整:

def stocGradAscent0(dataMatrix,classLabels,numIter=150):
    m,n=shape(dataMatrix)
    alpha=0.01
    weights=ones(n)
    dataMatrix=array(dataMat)
    for j in range(150):
        dataIndex = range(m)
        dataIndex=list(dataIndex)
        for i in range (m):
            #alpha每次迭代时调整
            alpha=4/(1.0+j+i)+0.1
            #随机选取更新
            randIndex=int(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

20201222110909952.png


该分割线达到了与gradAscent()差不多的效果,而且计算量明显少于批量梯度上升算法。


六、实战:从疝气病症预测病马的死亡率


我们将使用Logistic回归来预测患有疝气病的马存活问题。此数据集包含368个样本和28个特征。另外需要说明的是这些数据集是有部分缺失,我们需要先进行数据预处理再利用回归预测。

对于数据集中缺失数据我们可以采取以下办法进行处理:


  1. 使用可用特征的均值来填补缺失值;
  2. 使用特殊值来填补缺失值,比如-1;
  3. 忽略有缺失值的样本;
  4. 使用相似样本的均值添补缺失值;
  5. ‘使用另外的机器学习算法预测缺失值;(如KNN)


而对于该数据集我们选择用0代替缺失值,因为根据回归系数的更新公式:

gif.gif


当一数据集特征为0时,gif.gif将不作更新。

另外由于sigmoid(0)=0.5,它对结果的预测不具有任何倾向性,因此上述做法也不会对误差项造成任何影响。


现在我们根据上述所做的工作,现在只需要将特征向量乘以最优化系数得到的值全部相加,作为输入给sigmoid函数中。如果sigmoid值大于0.5则给定标签为1,否则为0。


def colicTest():
    frTrain = open('horseColicTraining.txt', encoding='utf8');
    frTest = open('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 = stocGradAscent0(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("该模型错误率为: %f" % errorRate)
    return errorRate

由于每次是随机取数,所以我们可将colicTest()迭代次数更多一些:


def multiTest():
    numTests = 10
    errorSum = 0.0
    for k in range(numTests):
        errorSum += colicTest()
    print("该模型迭代%d次平均错误率为: %f",numTests,(numTests, errorSum / float(numTests)))

运行输出:

20201223084013832.png

20201223084134903.png


可见错误率还是很低,因为数据存在30%的丢失。


总结


Logistic回归利用Sigmoid函数作为最佳拟合函数,利用最优化算法求出参数,再把数据集特征向量矩阵与对应训练好的参数相乘再相加,作为Sigmoid的输入从而得到预测。

目录
相关文章
|
12天前
|
机器学习/深度学习 数据采集 TensorFlow
使用Python实现智能食品加工优化的深度学习模型
使用Python实现智能食品加工优化的深度学习模型
110 59
|
7天前
|
机器学习/深度学习 数据采集 TensorFlow
使用Python实现智能食品市场预测的深度学习模型
使用Python实现智能食品市场预测的深度学习模型
45 5
|
9天前
|
机器学习/深度学习 算法 数据可视化
使用Python实现深度学习模型:智能食品配送优化
使用Python实现深度学习模型:智能食品配送优化
26 2
|
8天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
28 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
8天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
45 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
10天前
|
机器学习/深度学习 数据采集 TensorFlow
使用Python实现智能食品储存管理的深度学习模型
使用Python实现智能食品储存管理的深度学习模型
33 2
|
12天前
|
机器学习/深度学习 算法 PyTorch
用Python实现简单机器学习模型:以鸢尾花数据集为例
用Python实现简单机器学习模型:以鸢尾花数据集为例
36 1
|
7天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。
|
7天前
|
机器学习/深度学习 数据挖掘 Python
Python编程入门——从零开始构建你的第一个程序
【10月更文挑战第39天】本文将带你走进Python的世界,通过简单易懂的语言和实际的代码示例,让你快速掌握Python的基础语法。无论你是编程新手还是想学习新语言的老手,这篇文章都能为你提供有价值的信息。我们将从变量、数据类型、控制结构等基本概念入手,逐步过渡到函数、模块等高级特性,最后通过一个综合示例来巩固所学知识。让我们一起开启Python编程之旅吧!
|
8天前
|
存储 Python
Python编程入门:打造你的第一个程序
【10月更文挑战第39天】在数字时代的浪潮中,掌握编程技能如同掌握了一门新时代的语言。本文将引导你步入Python编程的奇妙世界,从零基础出发,一步步构建你的第一个程序。我们将探索编程的基本概念,通过简单示例理解变量、数据类型和控制结构,最终实现一个简单的猜数字游戏。这不仅是一段代码的旅程,更是逻辑思维和问题解决能力的锻炼之旅。准备好了吗?让我们开始吧!
下一篇
无影云桌面