[白话解析] 深入浅出朴素贝叶斯模型原理及应用

[白话解析] 深入浅出朴素贝叶斯模型原理及应用

0x00 摘要

朴素贝叶斯模型是机器学习中经常提到的概念。但是相信很多朋友都是知其然而不知其所以然。本文将尽量使用易懂的方式介绍朴素贝叶斯模型原理,并且通过具体应用场景和源码来帮助大家深入理解这个概念。

0x01 IT相关概念

1. 分类问题

  • 已知m个样本 (x1,y1), ...... (xm,ym),x是特征变量,y是对应的类别。要求得一个模型函数或者映射规则h,对于新的样本 xt,能够尽量准确的预测出 yt = h(xt)。
  • 我们也可以从概率的角度来考虑一下上述问题。假设y有m个类别,即 y1,......yn ∈ {C1,......Cm},对于样本 xt,如果能计算出每个类别的条件概率 P(C1|xt),......P(Cm|xt),那么可以认为概率最大的那个类别就是 xt 所属的类别。

h叫做分类器。分类算法的任务就是构造分类器h

  • 分类器一个直观理解就是在通过计算出的后验概率得到每个类别的概率,并输出最高类别的概率为分类结果。
  • 分类算法的内容是要求给定特征,让我们得出类别,这也是所有分类问题的关键。每一个不同的分类算法,对应着不同的核心思想。

2. 朴素贝叶斯

朴素贝叶斯(Naive Bayes)算法理论基础是基于贝叶斯定理和条件独立性假设的一种分类方法。朴素的意思是假设各个特征之间相互条件独立的。

贝叶斯分类器的基本方法:在统计资料的基础上,依据找到的一些特征属性,来计算各个类别的概率,找到概率最大的类,从而实现分类。即贝叶斯分类器通过预测一个对象属于某个类别的概率,再预测其类别。

  • 找到一个已知分类的待分类项集合,这个集合叫做训练样本集。
  • 统计得到在各类别下各个特征属性的条件概率估计。
  • 找出最大概率的那个类。

3. 公式解说

3.1 贝叶斯定理

前文呼延灼的方法是:
求解问题(A): 呼延灼想知道自己是否是公明哥哥的心腹,用A来代表"你是大哥的心腹"。
已知结果(B): 大哥对你下拜。记作事件B。
推理结果 P(A|B): 想通过大哥对你下拜这个事件,来判断大哥视你为心腹的概率。

于是有:

P(A|B) = P(B|A)P(A)/P(B)
P(A|B) 也就是在B事件"大哥下拜"发生之后,对A事件"大哥视你为心腹"概率的重新评估。

其实上述公式也隐含着:通过贝叶斯公式能够把人分成两类:大哥的心腹 / 普通下属

3.2 用类别的思路重新解读

所以贝叶斯公式可以用类别的思路重新解读。

我们把 B 理解成“具有某特征”,把A理解成“类别标签”。在最简单的二分类问题(是与否判定)下,我们将A 理解成“属于某类”的标签。

P(类别|特征)=P(特征|类别)P(类别)/P(特征)
  • P(A)是先验概率,表示每种类别分布的概率;
  • P(B|A)是条件概率,表示在某种类别前提下,某事发生的概率;该条件概率可通过统计而得出,这里需要引入极大似然估计概念。
  • P(A|B)是后验概率,表示某事发生了,并且它属于某一类别的概率,有了这个后验概率,便可对样本进行分类。后验概率越大,说明某事物属于这个类别的可能性越大,便越有理由把它归到这个类别下。

3.3 扩展到多个条件(特征)

之前只假设A只有B一个条件, 但在实际应用中,很少有一件事只受一个特征影响的情况,往往影响一件事的因素有多个。假设,影响 B 的因素有 n 个,分别是 b1,b2,…,bn。

则 P(A|B) 可以写为:

P(A|b1,b2,...,bn) = P(A) P(b1,b2,...,bn|A) / P(b1,b2,...,bn)

因为假设从 b1 到 bn 这些特征之间,在概率分布上是条件独立的,也就是说每个特征 bi与其他特征都不相关。所以可以做如下转换

P(b1,b2,...,bn|A) = P(b1|A)P(b2|A)...P(bn|A)

这个转换其实就是 独立变量的联合分布 = 各变量先验分布的乘积。只不过这里是条件概率,但是因为变换前后都有同样的条件 A,从样本空间 A 的角度看,其实就是联合分布转换成先验分布的乘积。

所以贝叶斯定理可以做如下推导

P(A|b1,b2,...,bn) = P(A) [P(b1|A)P(b2|A)...P(bn|A)] / P(b1,b2,...,bn)

0x02 呼延灼如何应用朴素贝叶斯模型来分类:

话说在前文[白话解析] 深入浅出贝叶斯定理中,呼延灼通过贝叶斯定理,推出了自己不是公明哥哥心腹的结论。虽然有些气闷,但是也好奇于贝叶斯定理的威力,于是他就决定用朴素贝叶斯模型对马军头领和步军头领进行分类。

1. 极简版朴素贝叶斯分类模型

目前有一个极简版朴素贝叶斯分类模型,能区分出两个类(A1, A2),用来分类的特征也有两个(B1, B2)。
所以公式为:

P(A|B1,B2) = P(A) [P(B1|A)P(B2|A)] / P(B1,B2)

这个就是分类器:

P(A|B1,B2) = P(A) [P(B1|A)P(B2|A)] / P(B1,B2) = P(A) [P(B1|A)P(B2|A)] / [P(B1) P(B2)]

b1,b2表示特征变量,Ai表示分类,p(Ai|b1,b2)表示在特征为b1,b2的情况下分入类别Ai的概率

再重温下朴素贝叶斯分类器,通过预测一个对象属于某个类别的概率,再预测其类别。

  • 找到一个已知分类的待分类项集合,这个集合叫做训练样本集。
  • 统计得到在各类别下各个特征属性的条件概率估计。
  • 找出最大概率的那个类。

2. 已知条件

样本是10位马军头领, 10位步兵头领,现在设定如下:

已知有两个分类:
A1=马军头领
A2=步军头领

两个用来分类的特征:
F1=纹身
F2=闹事

特征可以如下取值:
f11 = 有纹身
f12 = 无纹身
f21 = 爱闹事
f22 = 不爱闹事

有了分类器模型和预制条件,下面就看如何推导出分类器模型参数了。

3. 训练过程和数据

以下是根据已知数据统计得来。就是由实际数值训练出来的 分类器参数

假定 马军头领中,2位有纹身,1位爱闹事,步兵头领中,7位有纹身,6位爱闹事。所以得到统计数据如下:

P(有纹身) = P(f11) = (7+2)/20 = 9/20 = 0.45
P(无纹身) = P(f12) = 11/20 = 0.55
P(爱闹事) = P(f21) = 7/20 = 0.35
P(不爱闹事) = P(f22) = 13/20 = 0.65

P(F1=f11|A=A1) = P(有纹身|马军头领) = 2/20 = 0.1
P(F1=f12|A=A1) = P(无纹身|马军头领) = 8/20 = 0.4
P(F1=f11|A=A2) = P(有纹身|步兵头领) = 7/20 = 0.35
P(F1=f12|A=A2) = P(无纹身|步兵头领) = 3/20 = 0.15
P(F2=f21|A=A1) = P(爱闹事|马军头领) = 1/20 = 0.05
P(F2=f22|A=A1) = P(不爱闹事|马军头领) = 9/20 = 0.45
P(F2=f21|A=A2) = P(爱闹事|步兵头领) = 6/20 = 0.3
P(F2=f22|A=A2) = P(不爱闹事|步兵头领) = 4/20 = 0.2

这样就训练(统计)出来了一个分类器模型的参数

可以结合之前的分类器

P(A|F1,F2) = P(A) [P(F1|A)P(F2|A)] / P(F1,F2) = P(A) [P(F1|A)P(F2|A)] / [P(F1) P(F2)]

来对 "待分类数据" 做处理了。

4. 如何分类

如果有某位头领 x:不纹身,不闹事。进行针对两个分类(马军头领,步兵头领)进行两次运算,得出两个数值。

(不纹身,不闹事)是马军头领的可能性

P(马军头领|不纹身,不闹事) = P(马军头领)  [P(无纹身|马军头领) P(不闹事|马军头领) ] / [P(无纹身)P(不闹事)]

P(A=A1|x) = p(A=A1) P(F1=f12|A=A1)p(F2=f22|A=A1) / [P(f12)P(f22)] = 0.5 * 0.4 * 0.45 / [0.55 * 0.65] = 0.18 / [0.55 * 0.65] = 0.25

(不纹身,不闹事)是步兵头领的可能性

P(步兵头领|不纹身,不闹事) = P(步兵头领)  [P(无纹身|步兵头领) P(不闹事|步兵头领) ] / [P(无纹身)P(不闹事)]

P(A=A2|x) = p(A=A2) P(F1=f12|A=A2)p(F2=f22|A=A2) / [P(f12)P(f22)] = 0.5 * 0.15 * 0.2 / [0.55 * 0.65] = 0.03 / [0.55 * 0.65] = 0.04

所以x是马军的可能性更大。

贝叶斯定理最大的好处是可以用已知的频率去计算未知的概率,我们 简单地将频率当成了概率

0X03 参考snowNLP的源码

我们可以通过snowNLP的源码来对朴素贝叶斯模型再进一步理解。

在bayes对象中,有两个属性d和total,d是一个数据字典,total存储所有分类的总词数,经过train方法训练数据集后,d中存储的是每个分类标签的数据key为分类标签,value是一个AddOneProb对象。

这里的代码就是简单地将频率当成了概率。训练就是统计各个分类标签(key)所对应的个数。

1. 源码

#训练数据集
def train(self, data):
    #遍历数据集,data 中既包含正样本,也包含负样本
    for d in data: # data中是list
        # d[0]:分词的结果,list
        # d[1]:标签-->分类类别,正/负样本的标记
        c = d[1]
        #判断数据字典中是否有当前的标签
        if c not in self.d:
            #如果没有该标签,加入标签,值是一个AddOneProb对象
            self.d[c] = AddOneProb()  # 类的初始化
        #d[0]是评论的分词list,遍历分词list
        for word in d[0]:
            #调用AddOneProb中的add方法,添加单词
            self.d[c].add(word, 1)
    #计算总词数,是正类和负类之和
    self.total = sum(map(lambda x: self.d[x].getsum(), self.d.keys())) # # 取得所有的d中的sum之和

class AddOneProb(BaseProb):
def __init__(self):
    self.d = {}
    self.total = 0.0
    self.none = 1

#添加单词
def add(self, key, value):
    #更新该类别下的单词总数
    self.total += value
    #如果单词未出现过,需新建key
    if not self.exists(key):
        #将单词加入对应标签的数据字典中,value设为1
        self.d[key] = 1
        #更新总词数
        self.total += 1
    #如果单词出现过,对该单词的value值加1
    self.d[key] += value

具体分类则是计算各个分类标签的概率

#贝叶斯分类
def classify(self, x):
    tmp = {}
    #遍历每个分类标签
    for k in self.d: # 正类和负类
        #获取每个分类标签下的总词数和所有标签总词数,求对数差相当于log(某标签下的总词数/所有标签总词数)
        tmp[k] = log(self.d[k].getsum()) - log(self.total) # 正类/负类的和的log函数-所有之和的log函数
        for word in x:
            #获取每个单词出现的频率,log[(某标签下的总词数/所有标签总词数)*单词出现频率]
            tmp[k] += log(self.d[k].freq(word))
    #计算概率
    ret, prob = 0, 0
    for k in self.d:
        now = 0
        try:
            for otherk in self.d:
                now += exp(tmp[otherk]-tmp[k])
            now = 1/now
        except OverflowError:
            now = 0
        if now > prob:
            ret, prob = k, now
    return (ret, prob)

2. 源码推导公式

对于有两个类别c1,c1的分类问题来说,其特征为w1,?,wn,特征之间是相互独立的,属于类别c1的贝叶斯模型的基本过程为:

P(c1∣w1,?,wn)=P(w1,?,wn∣c1)?P(c1) / P(w1,?,wn)

如果做句子分类,可以认为是出现了w1, w2, ..., wn这些词之后,该句子被归纳到c1类的概率。

其中:

P(w1,?,wn)=P(w1,?,wn∣c1)?P(c1) + P(w1,?,wn∣c2)?P(c2)

预测的过程使用到了上述的公式,即:
\[
P(c1∣w1,?,wn)=\frac{P(w1,?,wn∣c1)?P(c1)}{P(w1,?,wn∣c1)?P(c1)+P(w1,?,wn∣c2)?P(c2)}
\]
对上述的公式简化:
\[
P(c1∣w1,?,wn)=\frac{P(w1,?,wn∣c1)?P(c1)}{P(w1,?,wn∣c1)?P(c1)+P(w1,?,wn∣c2)?P(c2)}
\]

\[
=\frac{1}{1+\frac{P(w1,?,wn∣c2)?P(c2)}{P(w1,?,wn∣c1)?P(c1)}}
\]

\[
=\frac{1}{1+exp[log(\frac{P(w1,?,wn∣c2)?P(c2)}{P(w1,?,wn∣c1)?P(c1)})]}
\]

\[
=\frac{1}{1+exp[log(P(w1,?,wn∣c2)?P(c2))?log(P(w1,?,wn∣c1)?P(c1))]}
\]

其中,分母中的1可以改写为:
\[
1=exp[log(P(w1,?,wn∣c1)?P(c1))?log(P(w1,?,wn∣c1)?P(c1))]
\]

3. 结合公式再详解代码

根据上面的公式,针对c1, c2,我们需要

a. 先求

\[
P(w1,?,wn∣c1)?P(c1)
\]

b. 再求

\[
P(c1)
\]

结合代码

p(Ck) = k这类词出现的概率 = self.d[k].getsum() / self.total
p(w1|Ck) = w1这个词在Ck类出现的概率 = self.d[k].freq(word)
k = 1,2

c. 再计算

\[
log(P(w1,?,wn∣c1)?P(c1))
\]

这个公式就是
\[
log(P(w1|c1)...p(wn∣c1)?P(c1))
\]
这个公式的结果就是:
\[
log(sum_{p(w1|C1)...p(wn|C1)}) + log(P(c1))
\]
最后展开:
\[
log(sum_{p(w1|C1)...p(wn|C1)}) + log(self.d[1].getsum()) - log(self.total))
\]
这个就是下面的 tmp[k]。其中,第一个for循环中的tmp[k]对应了公式中的log(P(ck)),第二个for循环中的tmp[k]对应了公式中的log(P(w1,?,wn∣ck)?P(ck))。两个for循环的结果就是最终的tmp[k]。

def classify(self, x):
    tmp = {}
    for k in self.d: # 正类和负类
        tmp[k] = log(self.d[k].getsum()) - log(self.total) # 正类/负类的和的log函数-所有之和的log函数
        for word in x:
            tmp[k] += log(self.d[k].freq(word)) # 词频,不存在就为0
    ret, prob = 0, 0
    for k in self.d:
        now = 0
        try:
            for otherk in self.d:
                now += exp(tmp[otherk]-tmp[k]) # for循环中有一个结果是0, exp(0)就是1.就是上面分母中的1
            now = 1/now
        except OverflowError:
            now = 0
        if now > prob:
            ret, prob = k, now
    return (ret, prob)

0x04 参考

朴素贝叶斯分类模型(一)

朴素贝叶斯分类——大道至简

带你搞懂朴素贝叶斯分类算法

snownlp情感分析源码解析

朴素贝叶斯详解及中文舆情分析

[数据挖掘]朴素贝叶斯分类

NLP系列(2)_用朴素贝叶斯进行文本分类(上)

情感分析——深入snownlp原理和实践

原文地址:https://www.cnblogs.com/rossiXYZ/p/12148809.html

时间: 2024-10-14 00:49:49

[白话解析] 深入浅出朴素贝叶斯模型原理及应用的相关文章

实现 | 朴素贝叶斯模型算法研究与实例分析

实现 | 朴素贝叶斯模型算法研究与实例分析(白宁超2018年9月4日09:03:21) 导读:朴素贝叶斯模型是机器学习常用的模型算法之一,其在文本分类方面简单易行,且取得不错的分类效果.所以很受欢迎,对于朴素贝叶斯的学习,本文首先介绍理论知识即朴素贝叶斯相关概念和公式推导,为了加深理解,采用一个维基百科上面性别分类例子进行形式化描述.然后通过编程实现朴素贝叶斯分类算法,并在屏蔽社区言论.垃圾邮件.个人广告中获取区域倾向等几个方面进行应用,包括创建数据集.数据预处理.词集模型和词袋模型.朴素贝叶斯

我理解的朴素贝叶斯模型

我理解的朴素贝叶斯模型 我想说:"任何事件都是条件概率."为什么呢?因为我认为,任何事件的发生都不是完全偶然的,它都会以其他事件的发生为基础.换句话说,条件概率就是在其他事件发生的基础上,某事件发生的概率. 条件概率是朴素贝叶斯模型的基础. 假设,你的xx公司正在面临着用户流失的压力.虽然,你能计算用户整体流失的概率(流失用户数/用户总数).但这个数字并没有多大意义,因为资源是有限的,利用这个数字你只能撒胡椒面似的把钱撒在所有用户上,显然不经济.你非常想根据用户的某种行为,精确地估计一

我理解的朴素贝叶斯模型【转】

转自:http://www.cnblogs.com/nxld/p/6607943.html 我想说:"任何事件都是条件概率."为什么呢?因为我认为,任何事件的发生都不是完全偶然的,它都会以其他事件的发生为基础.换句话说,条件概率就是在其他事件发生的基础上,某事件发生的概率. 条件概率是朴素贝叶斯模型的基础. 假设,你的xx公司正在面临着用户流失的压力.虽然,你能计算用户整体流失的概率(流失用户数/用户总数).但这个数字并没有多大意义,因为资源是有限的,利用这个数字你只能撒胡椒面似的把钱

PGM:贝叶斯网表示之朴素贝叶斯模型naive Bayes

http://blog.csdn.net/pipisorry/article/details/52469064 独立性质的利用 条件参数化和条件独立性假设被结合在一起,目的是对高维概率分布产生非常紧凑的表示. 随机变量的独立性 [PGM:概率论基础知识:独立性性质的利用] 条件参数化方法 Note: P(I), P(S | i0), P(S | i1)都是二项式分布,都只需要一个参数. 皮皮blog 朴素贝叶斯模型naive Bayes 朴素贝叶斯模型的学生示例 {这个示例很好的阐述了什么是朴素

机器学习基础——让你一文学会朴素贝叶斯模型

今天这篇文章和大家聊聊朴素贝叶斯模型,这是机器学习领域非常经典的模型之一,而且非常简单,适合初学者入门. 朴素贝叶斯模型,顾名思义和贝叶斯定理肯定高度相关.之前我们在三扇门游戏的文章当中介绍过贝叶斯定理,我们先来简单回顾一下贝叶斯公式: \[P(A|B)=\frac{P(A)P(B|A)}{P(B)}\] 我们把\(P(A)\)和\(P(B)\)当做先验概率,那么贝叶斯公式就是通过先验和条件概率推算后验概率的公式.也就是寻果溯因,我们根据已经发生的事件去探究导致事件发生的原因.而朴素贝叶斯模型正

机器学习基础——带你实战朴素贝叶斯模型文本分类

本文始发于个人公众号:TechFlow 上一篇文章当中我们介绍了朴素贝叶斯模型的基本原理. 朴素贝叶斯的核心本质是假设样本当中的变量服从某个分布,从而利用条件概率计算出样本属于某个类别的概率.一般来说一个样本往往会含有许多特征,这些特征之间很有可能是有相关性的.为了简化模型,朴素贝叶斯模型假设这些变量是独立的.这样我们就可以很简单地计算出样本的概率. 想要回顾其中细节的同学,可以点击链接回到之前的文章: 机器学习基础--让你一文学会朴素贝叶斯模型 在我们学习算法的过程中,如果只看模型的原理以及理

机器学习Matlab打击垃圾邮件的分类————朴素贝叶斯模型

该系列来自于我<人工智能>课程回顾总结,以及实验的一部分进行了总结学习机 垃圾分类是有监督的学习分类最经典的案例,本文首先回顾了概率论的基本知识.则以及朴素贝叶斯模型的思想.最后给出了垃圾邮件分类在Matlab中用朴素贝叶斯模型的实现 1.概率 1.1 条件概率 定义:事件B发生的情况下,事件A发生的概率记作条件概率P(A|B) P(A|B)=P(A∧B)P(B) 条件概率也叫后验概率.无条件概率也叫先验概率(在没有不论什么其他信息存在的情况下关于命题的信度) 能够得到乘法规则: P(A∧B)

机器学习Matlab实战之垃圾邮件分类————朴素贝叶斯模型

本系列来自于我<人工智能>课程复习总结以及机器学习部分的实验总结 垃圾邮件分类是监督学习分类中一个最经典的案例,本文先复习了基础的概率论知识.贝叶斯法则以及朴素贝叶斯模型的思想,最后给出了垃圾邮件分类在Matlab中用朴素贝叶斯模型的实现 1.概率 1.1 条件概率 定义:事件B发生的情况下,事件A发生的概率记作条件概率P(A|B) P(A|B)=P(A∧B)P(B) 条件概率也叫后验概率,无条件概率也叫先验概率(在没有任何其它信息存在的情况下关于命题的信度) 可以得到乘法规则: P(A∧B)

sklearn中的朴素贝叶斯模型及其应用

1.使用朴素贝叶斯模型对iris数据集进行花分类 尝试使用3种不同类型的朴素贝叶斯: 高斯分布型 多项式型 伯努利型 from sklearn.datasets import load_iris iris=load_iris() from sklearn.naive_bayes import GaussianNB gnb=GaussianNB() #模型 pred=gnb.fit(iris.data,iris.target) #训练 y_pred=pred.predict(iris.data)