zoukankan      html  css  js  c++  java
  • [机器学习]-朴素贝叶斯-最简单的入门实战例子

    简介

    如果你有一个很大的数据集,有很多的变量,而且已知这是一个分类问题,你想快速的得到你的分类结果,那朴素贝叶斯是一个不错的选择,他比一般的分类算法都要快,他的理论基础是概率中的贝叶斯定理。

    本文会介绍朴素贝叶斯的理论基础,以及一个基于python的实战例子,so,坐稳了,准备开车

    目录

      1.朴素贝叶斯是如何工作的?

       2.朴素贝叶斯的理论基础是什么?

       3.朴素贝叶斯的优缺点是什么?

       4.一个实战例子

       5.使用朴素贝叶斯模型的一些建议

    朴素贝叶斯是如何工作的?

    接下来用一个简单的例子介绍,下面的训练数据集反映了小学生出去玩(Play)和天气(Weather)之间的关系

    第一步:将数据集转换为频率表

    第二步:创建概率表,比如P(sunny) =0.36

        

    第三步:用朴素贝叶斯计算后验概率,后验概率大的为预测分类(关于先验概率,后验概率,看这篇文章

    问题:根据上面的数据集,如果天气是sunny就出去玩,这样说是否正确?

    可以根据第三步中讨论的后验概率来确定以上说法是否正确。

    P(Yes | Sunny) = P( Sunny | Yes) * P(Yes) / P (Sunny)    (什么?为什么这样计算,下面会介绍^_^)

    P (Sunny |Yes) = 3/9 = 0.33, P(Sunny) = 5/14 = 0.36, P( Yes)= 9/14 = 0.64

    最后: P (Yes | Sunny) = 0.33 * 0.64 / 0.36 = 0.60,因为0.6>0.5,所以以上说法正确

    朴素贝叶斯的理论基础是什么?

    先看看条件独立公式,如果X和Y相互独立,则有:

                  P(X,Y) = P(X)P(Y)

    接着看一下条件概率公式:

                  P(Y|X) = P(X,Y)/P(X)

    由上面两个公式可以推出贝叶斯公式:

                  P(Y|X) = P(X|Y)P(Y)/P(X)

    由上面的统计学知识回到我们的数据分析。

    假设某个体有n项特征(Feature),分别为F1、F2、…、Fn。现有m个类别(Category),分别为C1、C2、…、Cm。贝叶斯分类器就是计算出概率最大的那个分类,也就是求下面这个算式的最大值:

    P(C|F1F2...Fn) = P(F1F2...Fn|C)P(C) / P(F1F2...Fn)

    由于 P(F1F2…Fn) 对于所有的类别都是相同的,可以省略,问题就变成了求

    P(F1F2...Fn|C)P(C)

    的最大值。 
    朴素贝叶斯分类器则是更进一步,假设所有特征都彼此独立,因此

    P(F1F2...Fn|C)P(C) = P(F1|C)P(F2|C) ... P(Fn|C)P(C)

    上式等号右边的每一项,都可以从统计资料中得到,由此就可以计算出每个类别对应的概率,从而找出最大概率的那个类。 
    虽然”所有特征彼此独立”这个假设,在现实中不太可能成立,但是它可以大大简化计算,而且有研究表明对分类结果的准确性影响不大。

    朴素贝叶斯的优缺点是什么?

    优点:

    • 简单、运算量小、在拥有大量分类的数据集上仍然表现很好
    • 当数据的各个属性互相独立的假设成立,朴素贝叶斯比逻辑回归等模型表现更好,并且朴素贝叶斯需要更少的训练数据
    • 与数值变量相比,朴素贝叶斯在非数值变量的训练集上表现更好,因为对于数值型变量,一般假设数据符合正太分布(这个假设是一个很强的假设,大多数数据集并不相符)

    缺点:

    • 如果一个变量的某个值在测试集中有,在训练集中没有,计算结果将是0概率,无法做出分类,为了解决这个问题,需要引入平滑处理,比较简单的是拉普拉斯平滑
    • 朴素贝叶斯假定每个变量之间是相互独立的,但是现实中的数据往往都具有一定的相关性,很少有完全独立的

    一个实战例子

    该例子主要是为了识别某个文本是否具有侮辱性

    import numpy as np
    
    def getDataSet():
        """
        加载训练数据, postingList是所有的训练集, 每一个列表代表一条言论, 一共有8条言论 classVec代表每一条言论的类别,
         0是正常, 1是有侮辱性 返回 言论和类别
        :return:
        """
        postingList=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                     ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                     ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                     ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                     ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                     ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
        labels = [0,1,0,1,0,1]
        return postingList,labels
    
    def createVocabList(dataSet):
        """
        创建词汇表, 就是把这个文档中所有的单词不重复的放在一个列表里面
        :param dataSet:
        :return:
        """
        vocabSet = set([])
        for data in dataSet:
            vocabSet = vocabSet | set(data)
        return list(vocabSet)
    
    def vectorize(vocabSet,dataSet):
        """
        制作词向量矩阵
        将每一个文档转换为词向量, 然后放入矩阵中
        :param vocabSet:
        :param dataSet:
        :return:
        """
        vocab = [0] * len(vocabSet)
        for data in dataSet:
            vocab[vocabSet.index(data)] = 1
        return vocab
    
    def trainN(X_train,y_train):
        """
        制作贝叶斯分类器
        :param X_train:
        :param y_train:
        :return:
        """
        num = len(X_train)   #有多少记录
        numvocab = len(X_train[0]) #词向量的大小
        p0Num = np.ones(numvocab) #统计非侮辱类的相关单词频数 加入了拉普拉斯平滑
        p1Num = np.ones(numvocab) #统计侮辱类的相关单词频数
        p0Sum = 2
        p1Sum = 2
        pA = sum(y_train) / num                   #先验概率
        for i in range(num):
            if y_train[i]==0:   #统计属于非侮辱类的条件概率所需的数据
                # p0Sum += sum(X_train[i])
                p0Sum += 1
                p0Num += X_train[i]
            else:               #统计属于侮辱类的条件概率所需的数据
                # p1Sum += sum(X_train[i])
                p1Sum += 1
                p1Num += X_train[i]
    
        # 为了防止下溢出,计算条件概率的对数
        p0 = np.log(p0Num / p0Sum)      #频数除以总数 得到概率
        p1 = np.log(p1Num / p1Sum)
        return p0,p1,pA
    
    
    def classify(testMat,p0,p1,pA):
        """
        进行分类
        :param testMat: 
        :param p0: 
        :param p1: 
        :param pA: 
        :return: 
        """
        p0Score = sum(testMat * p0) + np.log(pA)
        p1Score = sum(testMat * p1) + np.log(1-pA)
        if p0Score > p1Score:
            return 0
        else:
            return 1
    
    if __name__=='__main__':
        dataSet,label = getDataSet()
        vocabSet = createVocabList(dataSet)
        trainMat = []
        for elem in dataSet:
            trainMat.append(vectorize(vocabSet,elem))
        # print(trainMat)
        p0,p1,pA = trainN(trainMat,label)
        test1= ['love', 'my', 'dalmation']
        test2= ['stupid', 'garbage','love']
        test1_vocab = np.array(vectorize(vocabSet,test1))
        test2_vocab = np.array(vectorize(vocabSet,test2))
        result1 = classify(test1_vocab,p0,p1,pA)
        result2 = classify(test2_vocab,p0,p1,pA)
        if result1==1:
            print(test1,"属于:侮辱类")
        else:
            print(test1, "属于:非侮辱类")
        print("------------------------------------------")
        if result2==1:
            print(test2,"属于:侮辱类")
        else:
            print(test2, "属于:非侮辱类")

     结果:

    ['love', 'my', 'dalmation'] 属于:非侮辱类
    ------------------------------------------
    ['stupid', 'garbage', 'love'] 属于:侮辱类

    使用朴素贝叶斯模型的一些建议

    • 如果连续型变量不符合正态分布,需要使用一些方法转换为正太分布
    • 删除相关属性,如果相关属性多次参与计算概率,会导致该属性出现的概率变大
    • 如果测试数据出现某个变量值在训练集为0时,记得使用拉普拉斯平滑
  • 相关阅读:
    Faster R-CNN
    Ubuntu软件安装
    Ubuntu16.04 caffe安装记录
    Unity Editor 工具开发 (三)——数据存储工具 -1
    #Unity Editor 工具开发 (二)
    Unity Editor 工具开发 (一)
    c# 多线程入门记录
    Unity 获取按键
    常用排序算法
    My “Hello World” For Blog
  • 原文地址:https://www.cnblogs.com/gunduzi/p/10639020.html
Copyright © 2011-2022 走看看