美文网首页
机器学习(三):贝叶斯分类器基本原理及代码实现

机器学习(三):贝叶斯分类器基本原理及代码实现

作者: 风之舟 | 来源:发表于2019-06-16 15:46 被阅读0次

    贝叶斯分类算法是统计学的一种分类方法,它是一类利用概率统计知识进行分类的算法。该算法的优点在于简单易懂、学习效率高、在某些领域的分类问题中能够与决策树、神经网络相媲美。接下来我们介绍一下这个算法:

    一、基础知识

    在我们讲贝叶斯分类器之前,我们先补充一下相关的数学知识:

    1、条件概率

    条件概率是指事件A在另一个事件B已经发生条件下发生的概率。条件概率表示为P(A/B),读作“在B条件下A的概率”。
    若只有两个事件A,B,那么:P(AB) = P(A\B)P(B) = P(B\A)P(A)
    即:p(A|B)=\frac{P(AB)}{P(B)}

    2、全概率公式

    表示若事件A1,A2,…,An构成一个完备事件组且都有正概率,则对任意一个事件B都有公式成立:
    P(B)=P(AB+\bar{A}B) =P(AB)+P(\bar{A}B)=P(A)P(B|A)+P(\bar{A})P(B|\bar{A})同时P(B)也可以表示为:
    P(B)=P(A_{1}B)+P(A_{2}B)+...+P(A_{n}B)
    =\sum P(A_{i}B)
    =\sum P(B|A_{i})*P(A_{i})

    3、贝叶斯公式

    由条件概率公式可以得到贝叶斯表达式
    p(A|B)=\frac{P(AB)}{P(B)}=\frac{P(B|A)*P(A)}{P(B)}

    将全概率公式代入到条件概率公式当中,对于事件A_{k}和事件B有:
    P(A_{k}|B)=\frac{P(B|A_{k})*P(A_{k})}{\sum P(B|A_{i})*P(A_{i})}
    a、P(A)是 A 的先验概率,之所以称为“先验”是因为它不考虑任何 B 方面的因素。

    b、P(A|B)是已知 B 发生后 A 的条件概率,也由于得自 B 的取值而被称作 A 的后验概率。

    c、P(B|A)是已知 A 发生后 B 的条件概率,也由于得自 A 的取值而被称作 B 的后验概率。

    d、P(B)是 B 的先验概率,也作标淮化常量(normalizing constant)。

    二、贝叶斯定理

    设X是类标号未知的数据样本。设H为某种假定,如,数据样本X属于某特定的类C。对于分类问题,我们希望确定P(H\X)-给定观测数据样本,假定H成立的概率。P(H\X)是后验概率,或条件X下,H的后验概率。例如,假定数据样本世界是由水果组成,用它们的颜色和形状描述,假定X表示红色和圆的,H表示假定X是苹果,则P(H\X)反映当我们看到X是红色并是圆时,我们对X是苹果的确信程度。P(H)是先验概率,或H的先验概率,对于我们的例子,它是任意给定的数据样本为苹果的概率,而不管数据样本看上去如何。后验概率P(H\X)比先验概率P(H)基于更多的信息(如,背景知识)。P(H)是独立于X的。
    类似的,P(X\H)是条件H下,X的后验概率。即,它是已知X是苹果,X是红色并且是圆的的概率。P(X)是X的先验概率。
    “如何计算这些概率?”,给定数据集,P(X)、P(H)、P(X|H)我们是可以求出来的,这时候贝叶斯就发挥了作用,它提供了一种由P(X)、P(H)、P(X|H)计算后验概率P(H|X)的方法:
    P(H|X)=\frac{P(X|H)(H)}{P(X)}

    三、朴素贝叶斯分类器的公式

    假设某个体有n项特征(Feature),分别为F1,F2,...,Fn。现在有m个类别(Category),分别为C1,C2,C3,...,Cm。贝叶斯分类器就是计算出概率最大的那个分类,也就是求下面这个算式的最大值:
    P(C|F_{1}F_{2}...F_{n}) = \frac{P(F_{1}F_{2}...F_{n}|C)P(C)}{P(F_{1}F_{2}...F_{n})}
    由于P(F1F2...Fn)对于所有的分类都是相同的,可以省略,问题就变成了求P(F_{1}F_{2}...F_{n}|C)P(C)
    的最大值。
    朴素贝叶斯分类器则是更进一步,假设所有特征都彼此独立,因此:
    P(F_{1}F_{2}...F_{n}|C)P(C) = P(F_{1}|C)P(F_{2}|C)...P(F_{n}|C)P(C)
    上式等号右边的每一项,都可以从统计资料中得到,由此就可以计算出每个类别对应的概率,从而找出最大概率的那个类。虽然"所有特征彼此独立"这个假设,在现实中不太可能成立,但是它可以大大简化计算。

    四、拉普拉斯平滑(Laplace smoothing)

    也就是参数为1时的贝叶斯估计,当某个分量在总样本某个分类中(观察样本库/训练集)从没出现过,会导致整个实例的计算结果为0。为了解决这个问题,使用拉普拉斯平滑进行处理。它的思想非常简单,就是对先验概率的分子(划分的计数)加1,分母加上类别数;对条件概率分子加1,分母加上对应特征的可能取值数量。这样在解决零概率问题的同时,也保证了概率和依然为1.

    这里举个例子,假设在文本分类中,有3个类,C1,C2,C3,在指定的训练样本中,某个词语F1,在各个类中观测计数分别为0,990,10,则概率为P(F1|C1)=0,P(F1|C2)=0.99,P(F1|C3)=0.01,对这三个量使用拉普拉斯平滑的计算方法如下:1/1003=0.001,991/1003=0.988,11/1003=0.011

    五、朴素贝叶斯定理的应用

    贝叶斯算法在文本领域有重要的应用:
    文本挖掘典型场景
    1、网页自动分类
    2、垃圾邮件判断
    3、评论自动分析
    4、通过用户访问内容判别用户喜好
    这里我们进行两个实例的讲解:

    • 文本分类
      数据集我们使用sklearn自带的新闻数据集20news-bydate_py3.pkz,将它划分训练集与测试集进行预测
    #导包
    from sklearn.datasets import fetch_20newsgroups
    from sklearn.model_selection import train_test_split
    from sklearn.feature_extraction.text import TfidfVectorizer
    from sklearn.naive_bayes import MultinomialNB
    from sklearn.metrics.classification import classification_report
    

    1、获取数据集

    def naivebayes():
        """
        朴素贝叶斯进行分本分类
        :return:
        """
        #获取数据集
        news = fetch_20newsgroups(subset='all')
        print(news)
    if __name__ == "__main__":
        naivebayes()
    

    结果我就不展示了,有兴趣的同学加载一下看看。
    2、进行数据集的分割和特征提取

    def naivebayes():
        """
        朴素贝叶斯进行分本分类
        :return:
        """
        #获取数据集
        news = fetch_20newsgroups(subset='all')
        print(news)
        #对数据集进行分割
        x_train,x_test,y_train,y_test = train_test_split(news.data,news.target,test_size=0.25)
        #进行特征抽取
        tf = TfidfVectorizer()
        x_train = tf.fit_transform(x_train)
        print(tf.get_feature_names())#输出特征名
        x_test = tf.transform(x_test)
    if __name__ == "__main__":
        naivebayes()
    

    3、进行贝叶斯算法预测并输出准确率、精确率和召回率

    def naivebayes():
        """
        朴素贝叶斯进行分本分类
        :return:
        """
        #获取数据集
        news = fetch_20newsgroups(subset='all')
        print(news)
        #对数据集进行分割
        x_train,x_test,y_train,y_test = train_test_split(news.data,news.target,test_size=0.25)
        #进行特征抽取
        tf = TfidfVectorizer()
        x_train = tf.fit_transform(x_train)
        print(tf.get_feature_names())#输出特征名
        x_test = tf.transform(x_test)
        #进行贝叶斯算法预测
        mlt = MultinomialNB(alpha=1.0)
        print(x_train.toarray())
    
        mlt.fit(x_train,y_train)
        y_predict = mlt.predict(x_test)
        print("预测的文章类型为:",y_predict)
    
        #得出准确率
        print("准确率为:",mlt.score(x_test,y_test))
    
        #得出精确率召回率
        print("每个类别的精确率和召回率:",classification_report(y_test,y_predict,target_names=news.target_names))#target_names表示每个类别的名称(比如文章分科技、娱乐等)
    
        return None
    
    
    if __name__ == "__main__":
        naivebayes()
    
    • 贝叶斯拼写检查器
    #正则匹配、字典
    import re,collections
    #把语料中的单词全部抽取出来,转成小写,并且去除单词中间的特殊符号
    def words(text):#正则匹配
        return re.findall('[a-z]+',text.lower())#大写变小写
    #如果遇到一个新词,拼写完全正确,但是语料库中没有包含这个词,那么这个词也永远不会出现在训练集中
    #这时我们返回这个词的概率是0,但是这样不符合实际,因为概率为0就代表了这个事件绝对不会发生
    #而在我们的概率模型中,我们期望用一个很小的概率来代表这种情况,词频设为1
    def train(features):
        model=collections.defaultdict(lambda:1)#返回一个类似字典的对象
        for f in features:
            model[f]+=1#词频+1
        return model
    NWORDS=train(words(open('E:\\学习文件\\机器学习\\数据集\\贝叶斯算法\\test.txt').read()))#返回字典类型
    alphabet='abcdefghijklmnopqrstuvwxyz'
    #编辑距离:两个词之间的编辑距离定义为使用了几次插入(在词中插入一个单字母),删除(删除一个单字母)
    #交换(交换相邻两个字母),替换(一个字母换成另一个)的操作从一个词变成另外一个词
    #返回所有与单词w编辑距离为1的姐
    def edits(word):
        n=len(word)
        return set([word[0:i]+word[i+1:] for i in range(n)]+
                  [word[0:i]+word[i+1:]+word[i]+word[i+2:] for i in range(n-1)]+
                  [word[0:i]+c+word[i+1:] for i in range(n) for c in alphabet]+
                  [word[0:i]+c+word[i:] for i in range(n+1) for c in alphabet])
    #编辑距离为2的单词也会存在,但是单词数会非常多这里把编辑距离小于2的词中,只把那些正确的词作为候选词
    def edits2(word):
        return set(e2 for e1 in edits(word) for e2 in edits(e1))
    #正常来说把一个元音拼成另一个的概率要大于辅音(因为人常常把hello打成hallo这样)把单词的第一个字母拼错的概率会相对小,等等。
    #但是为了简单起见,选择了一个简单的方法:编辑距离为1的正确单词比编辑距离为2的优先级高,而编辑距离为0的正确单词优先级比编辑距离为1的高
    def known_edits(word):
        return set(e2 for e1 in edits(word) for e2 in edits(e1) if e2 in NWORDS)
    def known(words):
        return set(w for w in words if w in NWORDS)
    #如果known(set)非空,candidate就会选取这个集合,而不继续计算后面的
    def correct(word):
        candidates=known([word]) or known(edits(word)) or known_edits(word) or [word]
        return max(candidates,key=lambda w:NWORDS[w])
    correct('tha')
    
    实验结果

    代码相对来说比较简单,相关说明都已经在代码中注释了,大家可以看一下~

    六、算法总结

    1、优点

    • 朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率
    • 对缺失数据不太敏感,算法也比较简单,常用于文本分类
    • 分类准确度高,速度快

    2、缺点

    • 由于使用了样本属性独立性的假设,所以如果样本属性有关联时,其效果不好
      朴素贝叶斯定理就讲到这里,有兴趣的同学可以将上面的代码执行一下。

    相关文章

      网友评论

          本文标题:机器学习(三):贝叶斯分类器基本原理及代码实现

          本文链接:https://www.haomeiwen.com/subject/nsybfctx.html