从全概率公式与贝叶斯公式原理讨论,引出贝叶斯估计理论及其具体应用

1. 随机事件及其运算

0x1:随机试验

在自然界和人类活动中,发生的现象多种多言,有确定性现象(例如偶数能够被2整除),也有不确定的随机现象(例如新生婴儿是男孩还是女孩)。概率论便是一门研究随机现象的统计规律性的数学学科。

随机现象在一次试验中呈现不确定的结果,而在大量重复试验中结果将呈现某种规律性,例如相对比较稳定的全国性别比例,这种规律性称为统计规律性

为了研究随机现象的统计规律性,就要对客观事物进行观察,观察的过程叫随机试验

随机试验有以下三个特点:

  • 在相同的条件下试验可以重复进行
  • 每次试验的结果不只一种,但是试验之前必须明确试验的所有可能结果
  • 每次试验将会出现什么样的结果是事先无法预知的

0x2:样本空间

随机试验的一切可能结果组成的集合称为样本空间,记为,其中w表示试验的每一个可能的结果,又称为样本点。即样本空间为全体样本点的集合。

0x3:随机事件

当我们通过随机试验来研究随机现象时,每一次试验都只能出现中的某一个结果w,各个可能结果w是否在一次试验中出现是随机的。

在随机试验中,常常会关心其中某一些结果是否出现,例如抛一枚色子的结果是否是奇数。这些在一次试验中可能出现,也可能不出现的一类结果称为随机事件

笔者认为,在小数据下,随机事件是一类呈现出无规律结果的事件,但是在大数据下,随机事件往往会呈现出明显的统计规律,这也是大数据时代人工智能发展迅猛的原因之一。

0x4:随机事件的集合性质

1. 集合论视角下的随机事件

随机事件是一个抽象概念,通过引入集合论的理论框架,使得我们可以通过集合的方式来考量随机事件间的关系以及对随机事件进行运算。

例如抛掷一枚均匀的色子,关心掷出的点数是否是偶数,定义,很显然,它是全体样本空间的一个子集。

所以,从集合的角度来看,样本空间的部分样本点组成的集合称为随机事件

2. 用集合论的方式来度量随机事件之间的关系 

由于随机事件是一个集合,因此,事件之间的关系与事件之间的运算应该按照集合论中集合之间的关系与集合之间的运算来规定。
给定一个随机试验,Ω是它的样本空间,事件A,B,C与Ai(i = 1 ,2 , ... )都是Ω的子集。则随机事件间的关系有以下几种:

1)包含

如果,那么,称事件B包含事件A。它的含义是:事件A发生必定导致事件B发生。

例如,事件A表示“灯泡寿命不超过200h”,事件B表示“灯泡寿命不超过 300h ”。于是

2)相等

如果,即A = B,那么称事件A与事件B相等。 

3)互斥

如果A与B没有相同的样本点,则称事件A与事件B互补相容,或称为互斥。

3. 随机事件之间的运算

1)随机事件的并运算

事件A ∪ B = {ω:ω ∈ A 或 ω ∈ B},称为事件A与事件B的和事件(或并事件),它的含义是:当且仅当事件A与事件B中至少有1个发生时,事件A ∪ B发生。

2)随机事件的交运算

事件A ∩ B = {ω:ω ∈ A 且 ω ∈ B},称为事件A与事件B的积事件(或交事件),它的含义是:当且仅当事件A与事件B同时发生时,事件A ∩ B发生,积事件也可以记作AB。

3)随机事件的差运算

事件称为事件A与事件B的差事件,它的含义是 : 当且仅当事件A发生且事件B不发生时,事件A - B发生。

4)随机事件的逆运算

事件Ω-A称为事件A的对立事件(或逆事件,或余事件),记作,它的含义是:当且仅当事件A不发生时,事件发生。于是

由于A也是的对立事件,因此称事件A与互逆(或互余)。

4. 随机事件之间的运算定律

1)交 换 律

A ∪ B = B ∪ A ,A ∩ B = B ∩ A

2)结 合 律

A ∪ (B ∪ C ) = (A ∪ B ) ∪ C ,
A ∩ (B ∩ C ) = (A ∩ B ) ∩ C ;

3)分 配 律

A ∪ (B ∩ C ) = (A ∪ B ) ∩ (A ∪ C ),

A ∩ (B ∪ C ) = (A ∩ B ) ∪ (A ∩ C );

4)对偶律

Relevant Link:

《概率论与数理统计》同济大学数学系 第一章 - 第一节

 

2. 概率的定义及其性质 

0x1:频数和频率的定义

概率是从频率学派发展而来的,我们这里先定义频数和频率的概念。

在n次试验中如果事件A出现了na次,则称na为事件A的频数,称比值 na / n 为这n次试验中事件A出现的频率。

0x2:概率的统计定义 - 大数定律

随着试验次数n的增大,频率值逐步”稳定“到一个实数,这个实数称为事件A发生的概率。

仔细看这个定义可以发现,概率的统计定义并不是一个精确的数学定义,而更倾向于一个实验归纳总结定理(Induction)。这里存在两个问题:

  • n需要多大?
  • 怎么定义稳定?

实际上,就像量子力学中的测不准原理一样,概率论并不是一门研究确定性的学科。在小数据下,随机事件呈现的是随机不确定的结果,但是在大数据下,随机事件整体上处于一个特定统计规律的概率场中。关于大数定律的相关讨论,读者朋友可以参阅另一篇文章

0x2:概率的公理化定义 - 柯尔莫哥洛夫定律

1933年,柯尔莫哥洛夫(苏联)首次提出了概率的公理化定理。

设任一随机试验E,Ω为相应的样本空间,若对任意事件A,有唯一实数P(A)与之对应,且满足下面条件,则数P(A)称为事件A的概率:

  • 非负性:对于任意事件A,总有
  • 规范性
  • 可列可加性:若A1,A2,....,An为两两互不相容的事件,则有,即

Relevant Link:

《概率论与数理统计》同济大学数学系 第一章 - 第二节

 

3. 等可能模型

在概率论发展的历史上,最先研究的,也最常见的的一类随机现象是等可能随机事件,在这类随机事件中,样本空间中的每个基本事件发生的可能性都相等,这样的数学模型我们称之为等可能摡型。

等可能摡型又可以主要分为两个主要方面:

  • 古典概型:样本空间只包含有限个不同的可能结果(即样本点) ,例如抛掷一枚均匀的硬币。
  • 几何概型:样本空间是某个区域,可能是一维区间、二维区间、三维区间。

0x1:古典摡型

一般地,称具有下列2个特征的随机试验的数学模型为古典概型:

  • 试验的样本空间Ω是个离散有限集,不妨记作Ω = {ω1,...,ωn}
  • 每个基本事件发生的可能性相等,即

在古典概型中,如果事件A中包含 na 个样本点,则事件A的概率为

用这种方法确定的概率被称为古典概率。

值得特别注意的是,这里的 na 指的是样本点个数,样本点是概率论中的概念,不能直接等价于频率中的频数。我们通过一批随机试验得到了事件A的统计频数,只有当随机试验的次数n很大时,大数定律才能起作用,这时候随机试验A的采样频数才能近似等于随机事件A的样本数(概率同分布假设),也即我们才能用随机试验的统计结果近似作为概率统计的结果。

0x2:几何概型

几何摡型是古典摡型的推广,保留每个样本点发生的等可能性,但去掉了Ω中包含离散有限个样本点的限制,即允许试验可能的结果有连续无穷个。

一般地,几何概型的基本思路如下:

  • 随机试验的样本空间Ω是某个区域(可以是一维的、也可以是二维、三维的)
  • 每个样本点等可能地出现

在几何概型中,我们规定事件A的概率为:

其中,在一维情形下表示长度,在二维情形下表示面积,在三维情形下表示体积。

求几何概型的关键在于用图形正确地描述样本空间Ω和所求事件A,然后计算出相关图形的度量。

Relevant Link:

《概率论与数理统计》同济大学数学系 第一章 - 第三节

  

4. 条件概率与事件的相互独立性

前三章我们讨论了概率性的基本概念,随机事件,概率定义基本定义等内容,这章开始我们来讨论概率论中一个非常重要的理论,条件概率以及事件的相互独立性。

可以这么说,正是因为这两个理论的发展,才有了后来的贝叶斯理论以及贝叶斯估计方法,以及再后来的朴素贝叶斯方法,甚至马尔科夫假设的发展也和它们有关系。

0x1:条件概率

在大千世界中,事物是互相联系、互相影响的,这对随机事件也不例外。在同一试验中,一个事件发生与否对其他事件发生的可能性的大小究竟是如何影响的?这便是条件概率理论要阐述和定义的内容。

笔者认为,条件概率是整个概率论体系基础中的基础,所有的随机事件间关系均可在条件概率的理论体系下解释,包括独立同分布事件,本质上也是条件概率的一个特例,即零依赖条件。

1. 条件概率基本定义

设E是随机试验,Ω是样本空间,A,B是随机试验E上的两个随机事件且P(B)>0,称

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

可以验证,条件概率也满足概率的公理化定义的三条基本性质:

  • 非负性公理:对于任意一个事件A,P(A | B) ≥ 0
  • 规范性公理:P (Ω | B) = 1
  • 可列可加性公理:当可列无限个事件A1,A2,... 两两互不相容时,则有

2. 条件概率的延伸定理

如果对条件概率定义式两端同乘P(A),可得如下定理:

概率的乘法公式:

设A,B为随机试验E上两个事件,且P(A)<0,则有

0x2:事件的相互独立性

在一个随机试验中,A,B是两个事件。如果它们之间是否发生是相互不影响的,这表现为 P(B | A) = P (B) 或 P(A | B) = P(A) 成立。

由条件概率延伸定理可得,这时,P(AB) = P(A)P(B)。

这说明不管事件A发生还是不发生,都对事件B的发生的概率没有影响。我们可以说事件A和事件B没有”关系“,或者称事件A与事件B相互独立。

1. 事件相互独立性的定义

设A,B为试验E的两个事件,如果满足等式,则称事件A,B相互独立,简称A,B独立。

同时,若事件A与事件B相互独立,则下列4个命题是等价的:

  • 事件 A 与 B 相互独立 ;
  • 事件 A 与 相互独立 ;
  • 事件 与 B 相互独立; 
  • 事件相互独立;

2. 三个事件下事件独立性的定义 - 三元及多元关系

我们将相互独立性推广到三个事件的情况,三个事件以上和三个本质上是相同的。

1)两两相互独立性质

设A,B,C是试验E的三个事件,如果满足等式:

  • P (A B) = P (A)P (B)
  • P (B C) = P (B)P (C)
  • P (C A) = P (C)P (A) 

则称事件A,B,C两两相互独立。

2)相互独立

设A,B,C是试验E的三个事件,如果满足等式:

  • P (A B) = P (A)P (B)
  • P (B C) = P (B)P (C)
  • P (C A) = P (C)P (A) 
  • P (A B C) = P (A)P (B)P (C) 

则称事件A,B,C相互独立。

可以看到,在三元关系中,相互独立定义的要求比两两相互独立更加严格,满足两两相互独立的事件集合,未必一定就满足相互独立的定义。

3. 事件独立性的一个例子

举一个例子说明两两互相独立和相互独立的区别。

把一枚硬币相互独立的投掷2次,事件 Ai 表示”投掷第 i 次时出现正面“,i=1,2。事件 A3 表示”正、反面各出现一次“,所以有:

P(A1) = P(A2) = P(A3) = 1/2,P(A1 A2) = P(A1 A3) = P(A2 A3) = 1/4,所以 A1,A2,A3两两互相独立。

但是P(A1 A2 A3) = 0,所以 A1,A2,A3 不相互独立。

Relevant Link:

《概率论与数理统计》同济大学数学系 第一章 - 第四节

 

5. 全概率公式与贝叶斯公式

0x1:关于贝叶斯公式的一些历史

贝叶斯公式是概率论中最重要的知识点之一,该公式的意义在于开创了统计学的一个学派 - 贝叶斯学派,它和经典统计学派并列为现代统计学的两大分支。

贝叶斯公式是由英国学者贝叶斯(Thomas Bayes,1701-1761)为了解决二项分布的概率估计问题所提出的一种”逆概率“思想发展而来的。

”求概率这个问题的逆概率“和”求某问题的概率“是两个互为相反的过程:

  • ”求某问题的概率“:已知事件的概率为p,可计算某种结果出现的概率问题,即原因推结果;
  • ”求概率这个问题的逆概率“:给定了观察结果,则可对概率p作出试验后的推断,即结果推原因;

贝叶斯的思想,以后后续学者对其思想的发展和理论的应用,最终发展成了贝叶斯统计理论,从而开辟了统计学发展中的一个新领域,对统计决策函数、统计推断、统计的估算等作出了巨大贡献。

贝叶斯学派与经典统计学派的差别在于是否使用先验信息,先验信息是指人们对一个事物的历史认知或主观判断。我们知道,任何事物都是发展变化的,都会通过样本数据信息不断挖掘和发现新变化。经典统计学只使用样本数据信息,而贝叶斯分析则是把先验信息与样本数据结合起来进行推断。 

0x2:全概率公式与贝叶斯公式定义

全概率公式是概率论中一个非常重要的公式,通常我们会遇到一些较为复杂的随机事件的概率计算问题,这时,如果将它分解成一些较为容易计算的情况分别进行考虑,可以化繁为简。

1. 完备事件组

设E是随机试验,Ω是相应的样本空间,A1,A2,....,An为Ω的一个事件组,若满足条件:

  • A1,...,An 两两互不相容 
  • A1 ∪...∪ An = Ω

则称事件组A1,A2,....,An为样本空间Ω的一个完备事件组,完备事件组完成了对样本空间的一个分割。

2. 全概率公式

设A1,A2,....,An为样本空间Ω的一个完备事件组,且P(Ai) > 0(i=1,2,....,n),B为任一事件,则:

下面给出证明上述公式的一个几何表示:

由于,且是两两互不相容的事件(即B与A1,A2,....,An中的任1个事件有且只有1个事件同时发生),因此

笔者认为,全概率公式可以这么理解:全概率公式表达了一个思想,导致某个结果B的原因A可以分解为若干子情况,所有子情况累加起来共同导致了结果B,这是从原因推结果的概率计算问题

3. 贝叶斯公式

设A1,A2,....,An为样本空间Ω的一个完备事件组,且P(Ai) > 0(i=1,2,....,n),B为任一事件,当P(B) > 0时,有:

,i = 1,2,...,n

上面公式看着复杂,其实并不复杂,我们将其和全概率公式进行对比。会发现以下几点:

  • 贝叶斯公式的分子和全概率公式的分解子项是相同的
  • 贝叶斯公式的分母等于全概率公式的累加和

笔者认为,贝叶斯公式可以这么理解:贝叶斯公式表达了一个思想,根据某个出现的结果B可以反推所有可能导致该结果的子原因Ai,而具体根据结果B逆推出每个子原因的条件概率比重,则取决于这个子原因和结果B的联合概率 ,这是从结果推原因的逆概率计算问题

4. 同一个硬币的正反两面 - 贝叶斯和全概率公式

从数学公式上来讲,贝叶斯公式是全概率公式的逆运算,全概率公式和贝叶斯公式实际上代表了同一个事物的正反两面,有因就有果,有果就有因。

从映射的角度来看,贝叶斯和全概率公式可以理解为一个将”原因“映射为”结果“的映射函数,也可以反过来解,将”结果“映射为”原因“。

同时,这个因果的互相推导关系(映射)又不是固定不变的,它是随着随机试验的不断重复,不断调整”原因-结果的映射比重“,这个所谓的比重就是先验概率,通过调整先验概率,因果之间的映射关系也随之改变,当达到大数统计的时候,这个映射关系会收敛到一个均值区间附近。

接下来最重要也最美妙的几个问题来了,那这个收敛均值区间和我们先验是什么关系呢?我们处于大数据的数据驱动时代,是应该相信数据还是相信先验经验呢?笔者这里就自己在日常中的一些工作实践和思考给出我的一些观点:

  • 收敛区间和我们的先验并没有明确的关系,它们代表了对事物的不同认知视角。
  • 是该相信先验还是相信数据,这个问题贝叶斯学派已经给出了明确的回答,即”综合起来综合判断呀!不偏执一端,而是让先天先验和后天数据共同决定结果“。笔者这里给出另一个视角的回答,具体偏重哪一端,取决于你的数据体量,数据体量越多,越可以依赖数据驱动,相反,如果数据体量越小,先验的比重就要适当提高。
  • 当数据量较小时,采样数据对真值概率分布的代表性相对较差,这时候应该加大先验概率的比重,避免估计出现偏差;当数据量较大时(海量大数据),这时候采样数据近似(甚至无限逼近)真值概率分布,这时候可以采取最大熵原理(均等先验分布)来设置先验,通过数据驱动的方式来进行概率估计。

0x3:先验概率对贝叶斯后验估计结果的影响

这个小节,我们用一个例子来讨论下,先验概率对最终贝叶斯后验估计结果的影响,先验使得我们不单只看单次试验的结果,而同时还要结合对应事件是否发生的先验概率。

以医院检查某种疾病为例,某种疾病在所有人群中的感染率是0.1%(即在历史经验中这种病是一个非常罕见的病),医院现有的技术对于该疾病检测准确率为 99%(已知患病情况下, 99% 的可能性可以检查出阳性(患病);已知不患病下 99% 的可能性检查为阴性(正常)) 

设随机事件A为是否患病,随机事件B为是否被检测为阳性,则有:

  • [公式],被检测者患病的概率
  • [公式],被检测未者患病的概率
  • [公式],已知患病的情况下检测为阳性的概率,即确诊
  • [公式],已知未患病的情况下检测为阳性的概率,即误诊

通过贝叶斯公式,我们可得”某个人被医院检测为阳性,同时又实际又真的患病(即真阳性)“的条件概率:

同理可得假阳性的条件概率为0.91。

可以看到,即使被医院检测为阳性,实际患病的概率其实还不到10%,有很大可能是假阳性,需要确诊最终的结果,往往需要复检来确定是否真的患病。

让我们再来计算初检和复检结果都为阳性时(2次随机试验),患病的可能性。

假设两次检查的准确率相同,都是99%,这里令 B 为第一次检测结果为阳性,C 为第二次检测结果为阳性,A 为被检测者患病,则有:

  • [公式],被检测者患病的概率
  • [公式],被检测者未患病的概率
  • [公式],已知患病情况下连续两次检测结果为阳性的概率,即两次都确诊
  • [公式],已知未患病情况下连续两次检测结果为阳性的概率,即两次都误诊

计算”两次医院检测都是真阳性的概率“贝叶斯公式有:

可见复检结果大大提高了检测的可信度,可见复检的意义在于大幅减少假阳性的可能(0.91 -> 0.1),从而大大提高阳性检测的准确性。

这也一定程度上印证了上个小节的一个观点,当数据量足够大的时候,先验的作用会逐渐减弱,数据驱动的作用会占上峰,但是如果是小数据,先验对最终结果的影响就比较明显了。

生活中,如果体检中遇到了某种罕见病,不要慌张,赶紧再重新体检一次。

0x4:多次重复试验对贝叶斯统计推断结果的影响的例子

在这个小节中,笔者希望通过一个具体的案例,向读者朋友展示贝叶斯统计推断的两个核心特点,即:

  • 合理利用先验信息(take advance of prior knowledge)
  • 通过不断试验,不断动态更新先验,也即数据驱动的先验获得(data driven prior knowledge)

1. 题目说明

一袋中共装有10个球,分贝为红球和白球,但是每种颜色的球有几个不是很明确,如果按照完备事件组的定义,总有有11种可能(这是一个古典摡型),但是为了简化讨论,我们假设完备集由下列三种可能组成:

  • A1:6个红球,4个白球
  • A2:7个红球,3个白球
  • A3:5个红球,5个白球

在没有任何前置知识的情况下,我们先设定一个先验,开始认为这三种可能的概率分别为:

  • P(A1) = 1/6
  • P(A2) = 1/3
  • P(A3) = 1/2

试验的过程是每次从袋中有放回的拿一个球,接下来我们来简要阐述下贝叶斯统计的过程。

2. 第一轮贝叶斯估计

第一轮的试验结果是,我们取出的球是红色的。

我们设”任取出一个球是红色“这个随机事件为B。试验的先验信息,P(A1) = 1/6,P(A2) = 1/3,P(A3) = 1/2。

根据全概率公式有:

又根据贝叶斯公式得到各个先验的后验概率估计:

所以,经过一次样本抽取试验后(引入了条件信息),结合历史先验信息,我们得到了关于A1,A2,A3的后验概率。

2. 第二次,即之后的n次迭代试验

在贝叶斯估计理论体系中,先验来自于历史,即包括先天的认知,也包括通过经验总结得到的历史经验认知(康德的理性与经验主义)。我们在第一次试验中由于没有任何历史试验经验可总结,所以只能依据先天的认知假定了一个先验。但是经过了一次历史试验后,我们已经有了一个后验概率估计,这时,我们就可以将这个后验概率估计用作下一次试验的先验估计,即:

  • P(A1) = 6/35
  • P(A2) = 2/5
  • P(A3) = 3/7

可以看到,相比于第一次的试验,A1和A2的先验都有微弱的提高,而A3的先验则微弱下降了。这是因为第一次的实验结果更倾向于强化A1和A2的发生可能,而弱化A3的发生可能。

可以想象,随着不断地试验,贝叶斯估计对事物的认识会不断加深和调整,对错误的先验会修正,对正确的先验会强化,最后收敛到真实附近。

Relevant Link:

《概率论与数理统计》同济大学数学系 第一章 - 第五节
https://zhuanlan.zhihu.com/p/22467549 

 

6. 朴素贝叶斯法原理

在完成了对条件概率概率、全概率公式、贝叶斯公式的讨论之后,我们接下来继续讨论一个基于理论的具体应用,本质上说,朴素贝叶斯法和贝叶斯理论之间的关系就相当于树枝和树根的关系,朴素贝叶斯法的理论依据来自于贝叶斯理论。

0x1:从贝叶斯最优分类器说起,贝叶斯最优分类器存在哪些问题

一言以蔽之,贝叶斯最优分类器是一种基于贝叶斯理论(全概率公式和贝叶斯公式)的生成式模型

在贝叶斯最优分类理论中,对于给定的特征向量,我们的目的是预测样本的标签

贝叶斯最优分类器的函数形式是:

接下来问题来了,根据全概率公式的分解,为了描述概率函数,我们需要个参数,这意味着,我们所需的样本数量随特征个数呈现指数型增长(事件分解的越细,所需估计的参数数量就越多),很显然,这直接导致了维度爆炸问题。

0x2:独立同分布假设下的贝叶斯最优分类器

独立同分布假设,是学者们提出的为了解决贝叶斯最优分类器运算量过大的一种方法。

我们知道,在PAC可学习理论中,通过限制假设类可以缓解欠拟合问题,同时减小逼近误差,虽然可能会引入估计误差增大的问题。

在朴素贝叶斯方法中,我们增加的一个假设是:对于给定的标签(目标值),各特征之间是彼此独立的。

有了这个假设,就可以由如下全概率公式:

也就是说,对于朴素贝叶斯生成式推测来说,需要估计的参数个数只有 2d+1 个。这个独立假设显著减少了需要学习的参数数量。

注意,这里用的是”假设“这个词,也就是说这个假设并不一定是合理的(例如一段文本中不同单词之间是存在语法依赖关系的),只是我们为了简化运算而添加上的一个约束条件。

独立同分布假设其实也并不是什么新的概念,文章前面提到的事件之间两两相互独立于事件之间互相独立的概念,就是这里所谓的独立同分布假设。

综上,朴素贝叶斯(naive Bayes)法是基于贝叶斯定理与特征条件独立假设的分类方法

0x3:朴素贝叶斯法算法流程

1. 模型训练 - 基于全概率公式计算(X,Y)的联合概率分布

设输入空间为 n 维向量的集合,输出空间为类标记集合 Y = {C1,C2,...,Ck},输入特征向量,输出类标记是X和Y的联合概率分布,训练数据集独立同分布产生。

朴素贝叶斯法的训练目标是,通过数据集学习联合概率分布

但遗憾的是,联合概率不能直接产生(事实上它是未知的),我们可以通过全概率公式计算得到联合概率。

先验概率分布

条件概率分布

先验概率和条件概率累乘得到联合概率。

2. 模型预测 - 预测贝叶斯后验估计概率值最大对应的类(label)

朴素贝叶斯预测的目的是”由果推因“,即根据n维输入向量x,反推所有可能的目标类概率值,并从中选择概率值最大的类作为最终预测值。

目标类概率值的计算公式如下:

朴素贝叶斯从所有目标类中选出后验概率最大的那一个类作为预测结果,最大后验概率估计的公式如下:

注意!上式中分母对所有分类Ck都是相同的,因此实际计算中,分母可约掉,最终最大后验概率估计公式如下:

0x4:朴素贝叶斯估计合理性背后的数学原理 

朴素贝叶斯法预测时将实例分到后验概率最大的类中,这等价于期望风险最小化。

假设选择0-1损失函数作为损失的评估函数:

这时,期望风险是:。该式中期望是对联合分布P(X,Y)取得,而联合概率分布我们是未知的,因此取等价的后验概率条件期望:

为了使期望风险最小化,只需对X = x逐个极小化,由此得到

等式推导的最后一步就是最后后验概率的意思,由此,根据期望风险最小化准则就推导出了等价的后验概率最大化准则:,这就是朴素贝叶斯法所采用的数学原理

Relevant Link:

https://www.google.com.hk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwj8m-mjmrvVAhUBzIMKHWiqCIoQFgglMAA&url=https%3a%2f%2fzh%2ewikipedia%2eorg%2fzh-cn%2f%25E6%259C%25B4%25E7%25B4%25A0%25E8%25B4%259D%25E5%258F%25B6%25E6%2596%25AF%25E5%2588%2586%25E7%25B1%25BB%25E5%2599%25A8&usg=AFQjCNGICcTloX_Ty9_xQ06UnWbSWHkcWw

0x5:朴素贝叶斯估计的一个例子 

我们先计算先验概率:P(Y = 1) = 9 / 15;P(Y = -1) = 6 / 15

然后计算输入变量各个特征的条件概率:

= 2 / 9; = 3 / 9; = 4 / 9

= 1 / 9; = 4 / 9; = 4 / 9

= 3 / 6; = 2 / 6; = 1 / 6

= 3 / 6; = 2 / 6; = 1 / 6

根据最大后验概率公式,对于给定的,计算其最大后验概率:

= 9 / 15 * 3 / 9 * 1 / 9 = 1 / 45

= 6 / 15 * 2 / 6 * 3 / 6 = 1 / 15

朴素贝叶斯法取后验概率最大的对应的类,所以 y = -1

0x6:平滑化的朴素贝叶斯估计

这个小节我们来讨论一种朴素贝叶斯估计的变种,平滑化的朴素贝叶斯估计。

1. 传统的朴素贝叶斯估计可能遇到的问题

原始的朴素贝叶斯估计是一种单纯从训练样本推导概率分布的算法,但是在实际工程实践中,可能遇到一个问题:在根据全概率公式计算分子中的条件概率时,可能因为数据分布不均匀导致结果出现零值等极端情况

为什么会有这个问题呢?我们前面不是说先验分布是根据人的先天经验来设定的吗?这里怎么又说不准确不均匀呢?

实际上,在工程项目中,除了一些特定场景,大部分时候我们不可能直接人工指定一个先验分布,而是需要根据训练样本集来得到先验分布以及先验条件概率的。

为了说明这个问题,我们再来回顾一下朴素贝叶斯估计的公式:

公式中的分子是一个累乘式,试想如果有一个条件概率P(Xi | Yck) = 0,那整个分子的累乘结果就会等于0,分子为零,直接导致最终的贝叶斯后验概率估计也为零。

那接下来问题来了,这个等于意味着什么?合理吗?笔者的观点是,在海量均匀大数据下,可能合理,但是如果数据量不够或者分布不够均匀,这不合理,相当于即可老鼠屎坏了一锅汤,个别条件概率的0值,导致了整体的概率空洞,这显然是不合理的。

例如在文本分类任务中,我们会对文本进行ngram分词并得到一个词表。之后在面对具体输入文本的时候,会逐一统计词表中的词在输入文本中的出现频率,那这个时候,就很容易出现某些特征在样本中出现次数为0的情况,这样就会导致这些词的条件概率为0,解决的方法也是进行平滑化,关于ngram平滑这个问题的讨论,笔者在另一篇文章里有所涉及。

2. 通过加入拉普拉斯平滑因子,强行改变先验分布

解决传统贝叶斯估计遇到0概率空洞问题的方法之一是加入平滑化因子,修改后的先验条件概率公式:

,式中λ>=0,等价于在随机变量各个取值的频数上赋予一个正数λ。

  • 当λ=0时公式退化到传统朴素贝叶斯估计
  • 通常取λ=1,这时被称为拉普拉斯平滑(Laplace smoothing)
  • 也可以取其他λ值,获得不同的效果

上面的公式,如果我们对其进行对数化后可以看到,公式可分为两部分。

  • 第一项是标准的对数似然函数
  • 第二项是先验分布的对数

这表明对参数的估计不再仅仅考虑样本的统计结果,还要考虑进先验分布,它如同一个惩罚项。也可以理解为通过平滑化因子,强行改变了通过统计方法得到的先验分布。

笔者这里多说一句,从原理上说,如果在具体应用中,算法开发者自己非常了解业务,例如笔者自己对安全攻防业务相对比较了解,是可以直接通过专家经验的方式,指定一个先验分布的,这么做的效果,有时候要比平滑化要好,缺点也很明显,比较费力,且对不同数据的适应性会下降。

Relevant Link: 

http://blog.csdn.net/juanjuan1314/article/details/78189527?locationNum=4&fps=1
http://www.cnblogs.com/liliu/archive/2010/11/24/1886110.html

 

7. 朴素贝叶斯法的具体应用 - Spam fileter(垃圾分类demo)

0x1: 分类原理

我们知道,我们如果假设用于预测的所有词(例如15个词)互相之间都是有相关依存关系的,则朴素贝叶斯法的公式如下

但是了简便实现,我们可以假设所有词之间是互相独立的,则计算过程会大大简化

下面我们简述原理与预测过程

1. 计算所有词的 P(wordN | S)、以及 P(wordN | H) 

1. 输入所有邮件,然后得到邮件中每个单词出现在垃圾邮件中的次数(条件概率 P(wordN | S) ),出现在正常邮件中的次数( P(wordN | H) )
2. 设置默认概率,即如果在预测时遇到训练语料库中未见过的词,则赋值默认概率例如: 3.7e-4
3. 先验概率,设置Spam为0.2,Ham为0.8,即根据经验,100封邮件里有20封是垃圾邮件

有了这些参数,模型就训练出来了。朴素贝叶斯分类器的训练就是在计算条件概率

2. 预测新邮件,获取所有关键字

然后输入一封待处理邮件,找到里面所有出现的关键词

3. 计算独立联合条件概率

求出,A为一封邮件是垃圾邮件的事件,T为关键词出现在一封邮件中的事件。

是多个关键词。A和T是关联的事件。每个关键词根据朴素贝叶斯的假设,是相互独立的。

这些关键词同时出现的情况下A是垃圾邮件的概率。

代表了从待预测email中切出的词,A代表Spam或者Ham,上面公式要分别计算A = S和A = H时的独立联合条件概率。

这个计算在工程上也十分简单,就是把每个词在语料库中出现的次数比例,累乘起来。分母可忽略不用计算,因为不影响分子的大小对比。

0x2: 利用朴素贝叶斯进行垃圾邮件分类 - 以单个词为依据

我们用一个例子来说明朴素贝叶斯是怎么应用在垃圾邮件分类中的

贝叶斯过滤器是一种统计学过滤器,建立在已有的统计结果之上。所以,我们必须预先提供两组已经识别好的邮件,一组是正常邮件(ham),另一组是垃圾邮件(spam)
我们用这两组邮件,对过滤器进行"训练"。这两组邮件的规模越大,训练效果就越好。这里我们假设正常邮件和垃圾邮件各4000封

1. 训练

"训练"过程很简单。首先,解析所有邮件,提取每一个词(word)。然后,计算每个词语在正常邮件和垃圾邮件中的出现频率。比如,我们假定"sex"这个词,在4000封垃圾邮件中,有200封包含这个词,那么它的spam出现频率就是5%;而在4000封正常邮件中,只有2封包含这个词,那么ham出现频率就是0.05%。(如果某个词只出现在垃圾邮件中,就假定它在正常邮件的出现频率是1%,反之亦然。这样做是为了避免概率为0。随着邮件数量的增加,计算结果会自动调整。)
有了这个初步的统计结果,过滤器就可以投入使用了

2. 概率计算

现在,我们收到了一封新邮件。在未经统计分析之前,我们假定它是垃圾邮件的概率为50%。(有研究表明,用户收到的电子邮件中,80%是垃圾邮件。但是,这里仍然假定垃圾邮件的"先验概率"为50%。)
我们用S表示垃圾邮件(spam),H表示正常邮件(healthy)。因此,P(S)和P(H)的先验概率,都是50%

然后,对这封邮件进行解析,发现其中包含了sex这个词,请问这封邮件属于垃圾邮件的概率有多高?
我们用W表示"sex"这个词,那么问题就变成了如何计算P(S|W)的值,即在某个词语(W)已经存在的条件下,垃圾邮件(S)的概率有多大。
根据条件概率公式,马上可以写出

公式中,P(W|S)和P(W|H)的含义是,这个词语在垃圾邮件和正常邮件中,分别出现的概率。这两个值可以从历史资料库中得到,对sex这个词来说,上文假定它们分别等于5%和0.05%。另外,P(S)和P(H)的值,前面说过都等于50%。所以,马上可以计算P(S|W)的值:

因此,这封新邮件是垃圾邮件的概率等于99%。这说明,sex这个词的推断能力很强,将50%的"先验概率"一下子提高到了99%的"后验概率"

0x3: 利用朴素贝叶斯进行垃圾邮件分类 - 以多个词为依据

在上面的例子中,基于一个词就推断一个email是否是垃圾邮件未免太过武断,在实际使用中很容易出现误报。因为在一封邮件里往往会包含很多词,为了能降低误报。更实际的做法是选出这封信中P(S|W)最高的15个词(对推断共享最高的15个词),计算它们的联合条件概率。如果有的词是第一次出现则初始化为0.4,因为垃圾邮件使用的往往是固定的语句,如果出现了训练库中从未出现的词,则有很大概率是正常的词

而所谓联合概率,就是指在多个事件发生的情况下,另一个事件发生概率有多大。比如,已知W1和W2是两个不同的词语,它们都出现在某封电子邮件之中,那么这封邮件是垃圾邮件的概率,就是联合概率。

在已知W1和W2的情况下,无非就是两种结果:垃圾邮件(事件E1)或正常邮件(事件E2)

其中,W1、W2和垃圾邮件的概率分别如下:

如果假定所有事件都是独立事件(这是一个强假设,可能会导致预测的准确性下降),那么就可以计算P(E1)和P(E2):

由于在W1和W2已经发生的情况下,垃圾邮件的概率等于下面的式子:

将上式带入即

将先验概率P(S)等于0.5代入,得到

将P(S|W1)记为P1,P(S|W2)记为P2,公式就变成

这就是联合概率的计算公式,将情况从二词扩展到15词,最终公式为

0x4: 代码示例

# -*- coding: utf-8 -*-

# for tokenize
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import wordpunct_tokenize

# for reading all the files
from os import listdir
from os.path import isfile, join

# add path to NLTK file
nltk.data.path = ['nltk_data']
# load stopwords
stopwords = set(stopwords.words('english'))

# path for all the training data sets
# 用于训练模型的语料集
spam_path = 'data/spam/'
easy_ham_path = 'data/easy_ham/'

# change it to the type of mails you want to classify
# path to the hard ham mails
# 用于预测检验效果4个语料库
spam2_path = 'data/spam_2/'
easy_ham2_path = 'data/easy_ham_2/'
hard_ham2_path = 'data/hard_ham_2/'
hard_ham_path = 'data/hard_ham/'

# 分别测试模型在4种不同类型的数据集中的分类效果
test_paths = [spam2_path, easy_ham2_path, hard_ham_path, hard_ham2_path]



def get_words(message):
    """
    Extracts all the words from the given mail and returns it as a set.
    """

    # thanks http://slendermeans.org/ml4h-ch3.html

    # remove '=' symbols before tokenizing, since these
    # sometimes occur within words to indicate, e.g., line-wrapping
    # also remove newlines
    all_words = set(wordpunct_tokenize(message.replace('=\\n', '').lower()))

    # remove the stopwords
    msg_words = [word for word in all_words if word not in stopwords and len(word) > 2]

    return msg_words


def get_mail_from_file(file_name):
    """
    Returns the entire mail as a string from the given file.
    """

    message = ''

    with open(file_name, 'r') as mail_file:

        for line in mail_file:
            # the contents of the actual mail start after the first newline
            # so find it, and then extract the words
            if line == '\n':
                # make a string out of the remaining lines
                for line in mail_file:
                    message += line

    return message


def make_training_set(path):
    """
    Returns a dictionary of <term>: <occurrence> of all
    the terms in files contained in the directory specified by path.
    path is mainly directories to the training data for spam and ham folders.
    occurrence is the percentage of documents that have the 'term' in it.
    frequency is the total number of times the 'term' appears across all the
    documents in the path
    """

    # initializations
    training_set = {}

    mails_in_dir = [mail_file for mail_file in listdir(path) if isfile(join(path, mail_file))]

    # count of cmds in the directory
    cmds_count = 0
    # total number of files in the directory
    total_file_count = len(mails_in_dir)

    for mail_name in mails_in_dir:

        if mail_name == 'cmds':
            cmds_count += 1
            continue

        # get the message in the mail
        message = get_mail_from_file(path + mail_name)

        # we have the message now
        # get the words in the message
        terms = get_words(message)

        # what we're doing is tabulating the number of files
        # that have the word in them
        # add these entries to the training set
        for term in terms:
            if term in training_set:
                training_set[term] = training_set[term] + 1
            else:
                training_set[term] = 1

    # reducing the count of cmds files from file count
    total_file_count -= cmds_count
    # calculating the occurrence for each term
    for term in training_set.keys():
        training_set[term] = float(training_set[term]) / total_file_count

    return training_set




# c is an experimentally obtained value
# 贝叶斯估计P(S) = P(H) = 0.5
# 当一个新词出现时,我们假定为3.7e-4
def classify(message, training_set, prior=0.5, c=3.7e-4):
    """
    Returns the probability that the given message is of the given type of
    the training set.
    """
    # 获取word token list
    msg_terms = get_words(message)

    msg_probability = 1

    for term in msg_terms:
        if term in training_set:
            msg_probability *= training_set[term]
        else:
            msg_probability *= c

    return msg_probability * prior


spam_training_set, ham_training_set = {}, {}
def trainingProess():
    global spam_training_set, ham_training_set
    print 'Loading training sets...',
    spam_training_set = make_training_set(spam_path)
    ham_training_set = make_training_set(easy_ham_path)
    print 'done.'



def testProcess():
    global spam_training_set, ham_training_set
    SPAM = 'spam'
    HAM = 'ham'
    for mail_path in test_paths:
        mails_in_dir = [mail_file for mail_file in listdir(mail_path) if isfile(join(mail_path, mail_file))]

        results = {}
        results[SPAM] = 0
        results[HAM] = 0

        print 'Running classifier on files in', mail_path[5:-1], '...'

        for mail_name in mails_in_dir:
            if mail_name == 'cmds':
                continue
            # 获取email的全文
            mail_msg = get_mail_from_file(mail_path + mail_name)

            # 0.2 and 0.8 because the ratio of samples for spam and ham were the same
            # 贝叶斯估计P(S) = 0.2;P(H) = 0.8
            # 当一个新词出现时,我们假定为3.7e-4
            spam_probability = classify(mail_msg, spam_training_set, 0.2)
            ham_probability = classify(mail_msg, ham_training_set, 0.8)
            # 计算得到独立联合条件概率:
            # P(T1|S) * P(T2|S) * ... * P(Tn|S)
            # P(T1|H) * P(T2|H) * ... * P(Tn|H)

            # 根据贝叶斯估计概率分别对S和H类的概率预测结果,判定属于垃圾邮件还是正常邮件
            if spam_probability > ham_probability:
                results[SPAM] += 1
            else:
                results[HAM] += 1

            total_files = results[SPAM] + results[HAM]
            spam_fraction = float(results[SPAM]) / total_files
            ham_fraction = 1 - spam_fraction

        print 'Fraction of spam messages =', spam_fraction
        print 'Fraction of ham messages =', ham_fraction
        print ''


if __name__ == '__main__':
    # training process
    # 训练模型,得到训练集中每个词的条件概率
    trainingProess()

    # test process
    # 测试模型
    testProcess()

    # 接收手工输入,并基于当前模型判定是否是恶意邮件
    mail_msg = raw_input('Enter the message to be classified:')
    print ''

    ## 0.2 and 0.8 because the ratio of samples for spam and ham were the 0.2-0.8
    spam_probability = classify(mail_msg, spam_training_set, 0.2)
    ham_probability = classify(mail_msg, ham_training_set, 0.8)
    if spam_probability > ham_probability:
        print 'Your mail has been classified as SPAM.'
    else:
        print 'Your mail has been classified as HAM.'
    print ''

Relevant Link:

http://www.ganecheng.tech/blog/53219332.html
https://en.wikipedia.org/wiki/Naive_Bayes_spam_filtering
https://github.com/aashishsatya/Bayesian-Spam-Filter/blob/master/ClassifierDemo.py
http://www.ganecheng.tech/blog/53219332.html
https://github.com/dwhitena/bayes-spam-filter
http://www2.aueb.gr/users/ion/data/enron-spam/
http://www.ruanyifeng.com/blog/2011/08/bayesian_inference_part_two.html
http://www.voidcn.com/blog/win_in_action/article/p-5800906.html

 

posted @ 2017-08-04 09:50  郑瀚Andrew  阅读(4218)  评论(0编辑  收藏  举报