机器学习-----详解贝叶斯公式、朴素贝叶斯的来龙去脉(附上多方式代码实现)

贝叶斯公式:

          提到贝叶斯公式,首先需要从条件概率说起,因为他们都是基于条件概率发展而来的,既然条件概率那么重要,那么什么是条件概率呢?

           条件概率是概率论中的一个重要而时用的概念,生活中我们总是无意识的使用它们,即所考虑的事件A已发生的条件下事件B发生的概率,例如生活中,我们能根据今天的天气去预测明天的天气,其实隐含的条件就是在知道今天的天气情况下去预测明天的天气的概率,这就是条件概率了,下面举一个实际经典的掷硬币的例子:

           将一枚硬币投掷两次,观察其出现正反两面的情况,设事件A为“至少有一次为正面用“正”表示,事件B为“两次掷出同一面即(同正或者同反)”,现在来求已知事件A发生的条件下事件B发生的概率。

分析:     这里,样本空间为S = {正正,正反,反正,反反},A={正正,正反,反正},B={正正,反反},可知此属于古典概型问题。已知事件A已发生,有了这一信息,知道B中的{反反}不可能发生,即试验所有可能结果所组成的集合就是A,A中有三个元素,其中{正正}属于B,于是,在事件A发生的条件下B发生的概率(记为P(B/A))为:

                                                                           P(A/B) = \frac{1}{3}

           在这里我们看到,P(B)=\frac{2}{4} \neq P(B/A),这里很容易理解,因为在求P(B/A)时我们限制在事件A已经发生的条件下考虑事件B发生的概率的。

            另外,根据古典概型易知:

                                               P(A)=\frac{3}{4},,,, P(AB)=\frac{1}{4},,,,,P(B/A)=\frac{1}{3}=\frac{1/4}{3/4}

故有:

                                                                              P(B/A)=\frac{P(AB)}{P(A)}

这样就引出了条件概率的推导过程,下面给出严格的定义和使用条件:

                             定义: 设A,B是两个事件,且P(A)>0,称:

                                                                                   P(B/A)=\frac{P(AB)}{P(A)}

                                            为在事件A发生的条件下B发生的条件概率。

                需要满足概率的三个条件,不难证明,条件概率P(*/A)符合概率的三个条件,即:

                              1.非负性

                              2.规范性

                              3.可列可加性

证明省了,有兴趣的查阅概率论相关书籍。

至此我们知道了什么是条件概率,那么由条件概率又是如何推出贝叶斯公式的呢?下面继续推倒:

在推到贝叶斯公式之前呢,先给大家解释一下贝叶斯公式有什么用,贝叶斯的最牛叉的地方是他可以反求某些条件概率,例如银行希望能得到人群中哪一类人最有可能办理100万贷款业务,这样就可以针对这类人群投入广告,设计活动,例如人群我们占时分为老人、中年、青年、小孩(当然现实要考虑很多因素,如收入、可信度等),银行想知道哪一类人贷款百万的概率最大即P(百万贷款/哪类人),然而这个概率不好计算,因为条件是人,在此基础上去推测社会中的哪类人最有可能办理百万贷款,这个无法统计,因为条件太庞大了,条件是人啊,人那么多你怎么统计呢?但是银行就是想知道这个概率,怎么解决呢?这时候贝叶斯公式就很好的解决了,虽然统计哪类人办理贷款的概率很难,但是银行有大量办理百万贷款的数据啊,从中可以统计出办理百万贷款都是哪类人,注意,此时的条件是百万贷款,在此基础上就可以统计出P(哪类人/百万贷款)的概率,这个条件概率还是很容易算的,知道这个概率以后,就可以计算P(百万贷款/哪类人)了,怎么计算?这就是贝叶斯解决的问题了,我们接着往下看。

             我们已经知道了条件概率公式即:

                                                                                       P(B/A)=\frac{P(AB)}{P(A)}

               变一下形,把P(A)乘到左边即(记为①):

                                                                                    P(AB)=P(A)*P(B/A)                                                     ①

到这里我们需要想一想,存在P(B/A),是不是也会存在P(A/B)呢?答案是肯定的,贝叶斯公式就是根据这两个条件概率推到出来的,因此同理可得:

                                                                                    P(A/B)=\frac{P(AB)}{P(B)}

               同理也需要变形一下,此时把P(B)乘到左边即(记为②):

                                                                                     P(AB) = P(B)*P(A/B)                                                     ②

这时我们发现①式和②式的左边都是P(AB),因此两式相等,即:

                                                                                     P(A)*P(B/A) = P(B)*P(A/B)

此时可以得到:

                                                                                      P(A/B) =\frac{P(A)*P(B/A)}{P(B)}

这就是贝叶斯公式了,由此我们可以清楚的看到贝叶斯公式最牛叉的地方在于他把条件和目标可以通过一个等式联系起来,知道一个条件概率,另外一个就可以直接推出,再回到上面的银行例子,假如A代表百万贷款,B代表哪类人,那么P(A/B)就是银行想要的数据,即他想从人群中了解哪类人最有可能办理百万贷款,但是如果正面去计算显然很困难,通过上面的公式我们可以发现,只要知道,P(A),P(B),P(B/A)就可以间接的计算这个很求的条件概率了,那么这三个概率又代表什么呢?容易求吗?我们继续分析,P(A)代表在那么多的贷款项目中,办理百万贷款的概率,这个银行数据可以提供,P(B)代表,在某一类中都多少人办理这个贷款,P(B/A)就是在百万贷款的项目中哪一类人办理贷款的概率。这些银行贷款数据都可以给出,因此一个很难的问题就转换成很简单的概率计算问题,虽然公式很简单,但是所蕴含的信息是巨大的,大家多联系生活你会发现生活处处都有贝叶斯的身影。

         好了贝叶斯公式就到这里,下面我们看看如何把贝叶斯公式应用到机器学习的分类中,既然有贝叶斯公式了为何还要有朴素贝叶斯?他们有什么不同,又有什么联系呢?

 朴素贝叶斯

         朴素贝叶斯来源于分类,需要从分类角度解释他,然后再和贝叶斯公式比较:

先给出朴素贝叶斯分类器的算法实现步骤,然后给出示例,最后在总结什么是朴素贝叶斯分类,个人觉得这样理解朴素贝叶斯可能更容易,理解的更深刻。

该段内容来源韩家炜先生的书《数据挖掘:概念与技术》第351页:

       解释一下:训练元组可理解为训练的样本,A代表样本的特征,每个样本都有很多特征,C代表分类,上述给定是向量即表示有很多样本,每个样本有很多特征,分类的规则是计算每个样本属于某一分类的概率,然后把概率大的样本归为这一类的 ,简单来说就是在某一样本的前提下,判断他属于哪一类的概率的大小即P(C_{i}|A)>P(C_{j}|A),至于什么是先验概率什么是后验概率,大家可以这样理解:

        先验概率是在缺乏某个事实的情况下描述一个变量; 而后验概率是在考虑了一个事实之后的条件概率.  先验概率通常是经验  丰富的专家的纯主观的估计. 比如在法国大选中女候选罗雅尔的支持率 p,  在进行民意调查之前, 可以先验概率来表达这个    确定性.

       简单理解就是通过统计从数据统计出来的概率称为先验概率,通过在某一条件下得出的概率称为后验概率,其中条件概率就是后验概率,同理贝叶斯更是后验概率,本文所讲的后验概率默认指贝叶斯概率,先验概率指为了计算得出贝叶斯概率而需要的概率。

       我们继续解说,如果能计算出P(C_{i}|X)即每个样本的分为每一类的概率最大,一旦计算出这个概率,就可以分类了,这也是贝叶斯分类的最基本的准则,现在是如何求P(C_{i}|X),直接求很困难,这时候上面说的贝叶斯公式就有用武之地了,根据贝叶斯公式即:

                                                         P(C_{i}/X) =\frac{P(C_{i})*P(X/C_{i})}{P(X)}

        这时候问题就转为求P(C_{i})P(X/C_{i})P(X),,而这些概率根据样本数据可以求出来,但是有一个问题那就是就计算量太大了,大家能看出来计算量大在哪里吗?计算量大在求P(X/C_{i})得概率上,我们可以看出,他求的是在某一分类的下所有特征的概率,这牵扯到复杂的计算问题,至于哪里计算哪里复杂,有兴趣的同学可以查看相关书籍,如何解决这个计算量复杂问题呢?

         另外就是因为计算出后验概率的目的是为了比较,又因为在同一个样本空间中P(X)是不变的,所以同除P(X)和同时不除他比较结果是不影响的,因此为了降低计算量,只需求出P(C_{i})*P(X/C_{i}),找出其中的最大值即可,如果P(C_{i})也是等概率的,那么P(C_{i})也是不变的,因此只需求出P(X/C_{i})即可。

        继续看韩老师的书:

       解决的办法就是假设类条件独立,即假定样本数据的特征是独立的朴素假定或者说样本的各特征之间是没关联,没关系的,此时的P(X/C_{i})根据独立条件的性质可以拆开写了:

                                         P(X/C_{i}) = \prod_{k=1}^{n}p(x_{k}/c_{i})=p(x_{1}/c_{i})*p(x_{2}/c_{i})*p(x_{3}/c_{i})\cdot \cdot \cdot \cdot p(x_{n}/c_{i})

       假设条件独立后,计算复杂度降低了几个数量级,同时根据样本计算独立的概率还是很容易的,这也是朴素贝叶斯的由来,可以说贝叶斯和朴素贝叶斯的最大区别就在‘朴素’上即条件独立,引入朴素贝叶斯的目的是为了降低计算量

到这里基本上就解释了朴素贝叶斯的由来,但是还是不清晰,下面给出韩家炜书上的例子,带大家过一遍:

         上篇决策树的文章引入了一个例子,这个例子是关于银行贷款问题,也是韩家炜书上的例子,详细题目就不贴出来了,给出针对朴素贝叶斯的题目:

其中age、income、student、credit_rating为样本特征,分类为yes或者no,请细看题目,下面详细解说:

这个示例很清晰,如还有看不懂的建议去看韩家炜的书《数据挖掘:概念与技术》第三版 第229页,多看两遍就理解了。

到这里还有一个问题就是如果某个特征的概率为零,那么因为是连乘,所有容易结果为零,怎么解决该问题呢?

     有个很好的解决方法,假设样本数量很大,在初始化时,就让所有的特征加1,这样就避免了不存在特征的情况,在数据很大时,加1操作可以忽略不计,该方法称为拉普拉斯校准或者是拉普拉斯估计法,这个方法在机器学习实战这一节使用了,下面的程序会注明。

到此理论分析结束,下面给出机器学习实战的手写代码,关键代码均已注释完毕,后面再给出使用sklearn进行实践的源码:

代码是国庆之前写的,现在才写博客,,,国庆期间主要学习数据预处理实战了,好,本代码是邮件分类问题,参考 代码是机器学习实战的代码:

#!/usr/bin/env/python
# -*- coding: utf-8 -*-
# Author: 赵守风
# File name: bayes.py
# Time:2018/9/28
# Email:[email protected]
from numpy import *


# 准备数据阶段,本阶段主要是把文本数据转换成词条向量,该词条背景来源斑点犬爱好者留言板,这些留言文本被切分成
# 一系列的词条集合,标点已经去掉
def load_data_set():
    posting_list = [['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']]
    class_vec = [0, 1, 0, 1, 0, 1]    # 类别标签,1是辱骂性文字,0是正常言论,标签数据是人工标签,用于训练模型
    return posting_list, class_vec


# 创建一个包含在所有文档中出现不重复的词的列表,这个词汇表可以根据现实情况给出,可以人为选择设置,性质和特征类似
def create_vocablist(dataset):
    vocabset = set([])  # 创建一个空集
    for document in dataset:
        vocabset = vocabset | set(document)  # 创建两个集合的并集
    return list(vocabset)     # 返回列表型的词汇数据



# 本模型为词集模型,每个词只能出现一次,又称基于贝努利模型的,其缺点是无法挖掘一个词出现多次的情况,因此引入词袋模型
# 又称基于多项式模型的分类器
# 判断文档有没有单词和建立的单词向量相同,并划分,输入的是词汇列表和某一个文档,输出的是文档向量
# 文档向量的每一个元素分别为1或者0,表示词汇表中的单词是否在文档中出现
def set_of_words2vec(vocablist, inputset):
    return_vec = [0]*len(vocablist)  # 创建一个向量,这个向量和输入的词汇向量长度一致
    for word in inputset:  # 遍历输入文档所有单词,并与词汇标准的单词比对是否出现
        if word in vocablist:  # 查看文档向量的单词是否在建立的词汇向量里
            return_vec[vocablist.index(word)] = 1  # 如果在词汇向量里,则该位置为1,反之为0,注意即使重复出现
                                                   # 也是不停的赋值为1,无法解决文本一个词多次出现的情况
        else:
            print('the word: %s is not in my vocablist!' % word)
    return return_vec



# 朴素贝叶斯词袋模型又称基于多项式模型
# 判断文档有没有单词和建立的单词向量相同,并划分,输入的是词汇列表和某一个文档,输出的是文档向量
# 文档向量的每一个元素分别为1或者0,表示词汇表中的单词是否在文档中出现
def bag_of_words2vec(vocablist, inputset):
    return_vec = [0]*len(vocablist)  # 创建一个向量,这个向量和输入的词汇向量长度一致
    for word in inputset:  # 遍历输入文档所有单词,并与词汇标准的单词比对是否出现
        if word in vocablist:  # 查看文档向量的单词是否在建立的词汇向量里
            return_vec[vocablist.index(word)] += 1  # 如果在词汇向量里,则该位置为1,反之为0
    return return_vec


# 朴素贝叶斯分类器训练函数
def train_nb0(train_matrix, train_category):  # train_matrix为输入样本矩阵,train_category为分类标签数据
    num_train_docs = len(train_matrix)  # 获得训练样本(文档)的个数
    num_words = len(train_matrix[0])  # 获得矩阵中每个样本(文档)的维度,每个文档多少词
    p_abusive = sum(train_category) / float(num_train_docs)  # 计算辱骂性文档出现的概率
    p0_num = ones(num_words)  # 为了避免概率为零的错误。初始化每个单词出现一次,并且分母初始化为2
    p1_num = ones(num_words)
    p0_denom = 2.0
    p1_denom = 2.0
    for i in range(num_train_docs):
        if train_category[i] == 1:  # 侮辱性文档
             p1_num += train_matrix[i]  # 出现的侮辱性的单词对应累加
             p1_denom += sum(train_matrix[i])  # 出现侮辱性的词总数叠加
        else:                          # 不是侮辱性文档
            p0_num += train_matrix[i]  # 出现的侮辱性的单词对应相加
            p0_denom += sum(train_matrix[i])  # 出现侮辱性的词总数叠加

    # 使用对数的目的是为了避免概率连乘很小溢出
    p1_vect = log(p1_num / p1_denom)  # 侮辱性文档中出现侮辱性词汇的概率
    p0_vect = log(p0_num / p1_denom)  # 正常文档中出现侮辱性词汇的概率

    return p0_vect, p1_vect, p_abusive

# 朴素贝叶斯计算
def classifynb(vec2classify, p0_vec, p1_vec, pclass1):
    # 解释一下下面的代码,下面的代码求得是条件概率即:p(ci/w) = {p(w/ci)*p(ci)}/p(w),其中ci为类别,w为特征向量
    # 意思就是根据样本数据求出在某一类别的情况下,出现w特征的概率即p(w/ci),在乘上类别的概率p(ci),
    # 在除以特征的概率p(w) 就可以得到具有某些特征属于某一类别的概率p(ci/w)
    # 例如vec2classify为文本数据出现的特征词汇的向量为[1,0,0,1,0,0,0,0,1....], p1vec为前面计算出来的
    # 侮辱性文档中出现侮辱性词汇的概率即p(w/ci),如[0.0526 0.05263158 0.05263158 0.05263158 0.05263158 0.05263158...],
    # 现在vec2classify * p1_vec就是特征单词出现的概率,再求sum是因为前面计算p1_vec是log,相加就是相乘,最后在+log(pclass1)
    # 也是相乘,本来还需要同时除以p(w)的,但是因为所有的计算都除,而且只是比较大小,因此可以都不除这个分母
    p1 = sum(vec2classify * p1_vec) + log(pclass1)

    p0 = sum(vec2classify * p0_vec) + log(1 - pclass1)
    if p1 > p0:
        return 1
    else:
        return 0


# 测试朴素贝叶斯分类器
def testingnb():
    listoposts, listclasses = load_data_set()   # 加载样本和标签数据
    myvocablist = create_vocablist(listoposts)  # 创建特征词汇列表
    train_mat = []  # 创建文本空矩阵
    for postindoc in listoposts:  # 遍历文本的单词和特征词汇列表比对,出现词汇列表的词时为1反之为0
        train_mat.append(set_of_words2vec(myvocablist, postindoc))
    p0v, p1v, pab = train_nb0(array(train_mat), array(listclasses))  # 计算先验概率,即通过样本计算p(w/ci)和p(ci),也是训练权值
    testentry = ['love', 'my', 'dalmation']  # 测试数据
    thisdoc = array(set_of_words2vec(myvocablist, testentry))  # 测试样本数值化
    print(testentry, 'classifiled as;', classifynb(thisdoc, p0v, p1v, pab))  # 分类,并打印结果
    testentry = ['stupid', 'garbage']
    thisdoc = array(set_of_words2vec(myvocablist, testentry))
    print(testentry, 'classifiled as;', classifynb(thisdoc, p0v, p1v, pab))

下面给出调用上面的函数,进行邮件分类的试验,其中开始部分注释的内容 为测试某些python功能进行的试验:

#!/usr/bin/env/python
# -*- coding: utf-8 -*-
# Author: 赵守风
# File name: ex_bayes_email_filter.py
# Time:2018/9/29
# Email:[email protected]
import re
import bayes
import numpy as np

'''
# 准备数据:切分文本
mysent = 'This book is the best book on python or M.L. I have ever laid eyes upon.'
print(mysent.split())  # 切割字符串,但是把标点符号也切割进去了
# ['This', 'book', 'is', 'the', 'best', 'book', 'on', 'python', 'or', 'M.L.', 'I', 'have', 'ever',
#  'laid', 'eyes', 'upon.']
# reg_ex = re.compile('\\W*')
# 分隔符是  除单词、数字外的任意字符串,得到去除标点的切分字符串
list_of_tokens = re.split('\\W*', mysent)
print(list_of_tokens)
# ['This', 'book', 'is', 'the', 'best', 'book', 'on', 'python', 'or', 'M', 'L', 'I', 'have', 'ever',
# 'laid', 'eyes', 'upon', '']

# 删除空格
temp = [tok for tok in list_of_tokens if len(tok) > 0]
print(temp)
# ['This', 'book', 'is', 'the', 'best', 'book', 'on', 'python', 'or', 'M', 'L', 'I', 'have', 'ever',
# 'laid', 'eyes', 'upon']

# 转换大写字母为小写字母
temp1 = [tok.lower() for tok in list_of_tokens if len(tok) > 0]
print(temp1)
# ['this', 'book', 'is', 'the', 'best', 'book', 'on', 'python', 'or', 'm', 'l', 'i', 'have', 'ever',
#  'laid', 'eyes', 'upon']
emailtext = open('email/ham/6.txt').read()
list_of_email = re.split('\\W*', emailtext)
print(list_of_email)
'''


# 文本解析,把文本读入,并切分成单个字符串,把大写字母转换成小写字母,只保留数字和字母,同时剔除小于3的字符串
def textparse(bigstring):
    import re
    list_of_tokens = re.split(r'\W*', bigstring)
    return [tok.lower() for tok in list_of_tokens if len(tok) > 2]


# 垃圾邮件测试
def spamtest():
    doclist = []
    classlist = []
    fulltext = []
    for i in range(1, 26):
        wordlist = textparse(open('email/spam/%d.txt' % i).read())
        doclist.append(wordlist)
        fulltext.extend(wordlist)
        classlist.append(1)
        wordlist = textparse(open('email/ham/%d.txt' % i).read())
        # 运行时会出错,错误提示为UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 199:
        #  illegal multib,原因是在email/ham/%d.txt中的第23个文件出错,打开直接保存就好,不用修改任何内容
        doclist.append(wordlist)
        fulltext.extend(wordlist)
        classlist.append(0)

    vocablist = bayes.create_vocablist(doclist)
    trainingset = list(range(50))
    testset = []

    for i in range(10):
        randindex = int(np.random.uniform(0, len(trainingset)))
        testset.append(trainingset[randindex])
        del(trainingset[randindex])
        # 运行到这里会出错,这是因为Python3中range不在返回数值,修改办法为:
        # trainingset = range(50)改为trainingset = list(range(50))

    train_mat = []
    train_classes = []
    for docindex in trainingset:
        train_mat.append(bayes.set_of_words2vec(vocablist, doclist[docindex]))
        train_classes.append(classlist[docindex])

    p0v, p1v, pspam = bayes.train_nb0(np.array(train_mat), np.array(train_classes))
    errorcount = 0
    class_error = []
    for docindex in testset:
        word_vector = bayes.set_of_words2vec(vocablist, doclist[docindex])
        if bayes.classifynb(np.array(word_vector), p0v, p1v, pspam) != classlist[docindex]:
            errorcount += 1
            class_error.append(doclist[docindex])
    print('the error rate is : ', float(errorcount)/len(testset))
    print('错误分类的文本: ', class_error)

下面给出基于sklearn的实现:

      使用sklearn中的模型很简单,下面先介绍关于朴素贝叶斯的三个类型,同时介绍一下接口函数的用法:

注明:下面的理论讲解来源sklearn官网。

1.高斯朴素贝叶斯 

GaussianNB 实现了运用于分类的高斯朴素贝叶斯算法。特征的可能性(即概率)假设为高斯分布:

                                                           P(x_i \mid y) &= \frac{1}{\sqrt{2\pi\sigma^2_y}} \exp\left(-\frac{(x_i - \mu_y)^2}{2\sigma^2_y}\right)

参数 \sigma_y 和 \mu_y 使用最大似然法估计。

2.多项分布朴素贝叶斯

   MultinomialNB 实现了服从多项分布数据的朴素贝叶斯算法,也是用于文本分类(这个领域中数据往往以词向量表示,尽管在实践中 tf-idf 向量在预测时表现良好)的两大经典朴素贝叶斯算法之一。 分布参数由每类 y 的 \theta_y = (\theta_{y1},\ldots,\theta_{yn}) 向量决定, 式中 n 是特征的数量(对于文本分类,是词汇量的大小) \theta_{yi} 是样本中属于类 y 中特征 i 概率 P(x_i \mid y) 。

参数 \theta_y 使用平滑过的最大似然估计法来估计,即相对频率计数:

                                                                 \hat{\theta}_{yi} = \frac{ N_{yi} + \alpha}{N_y + \alpha n}

式中 N_{yi} = \sum_{x \in T} x_i 是 训练集 T 中 特征 i 在类 y 中出现的次数,

N_{y} = \sum_{i=1}^{|T|} N_{yi} 是类 y 中出现所有特征的计数总和。

先验平滑因子 \alpha \ge 0 应用于在学习样本中没有出现的特征,以防在将来的计算中出现0概率输出。 把 \alpha = 1 被称为拉普拉斯平滑(Lapalce smoothing),而 \alpha < 1 被称为利德斯通(Lidstone smoothing)。

3.伯努利朴素贝叶斯

   BernoulliNB 实现了用于多重伯努利分布数据的朴素贝叶斯训练和分类算法,即有多个特征,但每个特征 都假设是一个二元 (Bernoulli, boolean) 变量。 因此,这类算法要求样本以二元值特征向量表示;如果样本含有其他类型的数据, 一个 BernoulliNB 实例会将其二值化(取决于 binarize 参数)。

伯努利朴素贝叶斯的决策规则基于

                                              P(x_i \mid y) = P(i \mid y) x_i + (1 - P(i \mid y)) (1 - x_i)

与多项分布朴素贝叶斯的规则不同 伯努利朴素贝叶斯明确地惩罚类 y 中没有出现作为预测因子的特征 i ,而多项分布分布朴素贝叶斯只是简单地忽略没出现的特征。

       在文本分类的例子中,词频向量(word occurrence vectors)(而非词数向量(word count vectors))可能用于训练和用于这个分类器。 BernoulliNB 可能在一些数据集上可能表现得更好,特别是那些更短的文档。 如果时间允许,建议对两个模型都进行评估。

       各种各样的的朴素贝叶斯分类器的差异大部分来自于处理 P(x_i \mid y) 分布时的所做的假设不同,尽管其假设过于简单,在很多实际情况下,朴素贝叶斯工作得很好,特别是文档分类和垃圾邮件过滤。这些工作都要求 一个小的训练集来估计必需参数。相比于其他更复杂的方法,朴素贝叶斯学习器和分类器非常快。 分类条件分布的解耦意味着可以独立单独地把每个特征视为一维分布来估计。这样反过来有助于缓解维度灾难带来的问题。因此朴素贝叶斯分类器是一个很好用的分类器,但不是一个好的预测器。

代码给出:

from sklearn import datasets
from sklearn.naive_bayes import GaussianNB,MultinomialNB,BernoulliNB
import pandas as pd
import numpy as np

breast_cancer = datasets.load_breast_cancer() # 乳腺癌数据

# sklearn自带的数据已经帮我们分好了,自带了很多属性,可以直接调用,但是建议能找到一份原始数据,
# 自己进行处理,然后在调用模型,后面有机会我会这样多做几个几个项目

# 高斯朴素贝叶斯
gnb = GaussianNB()
y_pred = gnb.fit(breast_cancer.data, breast_cancer.target).predict(breast_cancer.data)
print("Number of mislabeled points out of a total %d points : %d" % (breast_cancer.data.shape[0],(breast_cancer.target != y_pred).sum()))
print('正确率为:%f ' %(1 - ((breast_cancer.target != y_pred).sum()/breast_cancer.data.shape[0])))

输出:
Number of mislabeled points out of a total 569 points : 33
正确率为:0.942004 



# 多项分布朴素贝叶斯
mnb = MultinomialNB()
y_pred = mnb.fit(breast_cancer.data, breast_cancer.target).predict(breast_cancer.data)
print("Number of mislabeled points out of a total %d points : %d" % (breast_cancer.data.shape[0],(breast_cancer.target != y_pred).sum()))
print('正确率为:%f ' %(1 - ((breast_cancer.target != y_pred).sum()/breast_cancer.data.shape[0])))


输出:
Number of mislabeled points out of a total 569 points : 59
正确率为:0.896309 


# 伯努利朴素贝叶斯
bnb = BernoulliNB()
y_pred = bnb.fit(breast_cancer.data, breast_cancer.target).predict(breast_cancer.data)
print("Number of mislabeled points out of a total %d points : %d" % (breast_cancer.data.shape[0],(breast_cancer.target != y_pred).sum()))
print('正确率为:%f ' %(1 - ((breast_cancer.target != y_pred).sum()/breast_cancer.data.shape[0])))

Number of mislabeled points out of a total 569 points : 212
正确率为:0.627417 

猜你喜欢

转载自blog.csdn.net/weixin_42398658/article/details/82967039