【NLP】从贝叶斯谈到N-gram语言模型

前言

  本篇主要是从贝叶斯方法谈起,由于贝叶斯方法具有坚实的理论基础,同时也是研究自然语言处理的一个好的开始。而且很多高级自然语言处理模型也是由此演化而来,所以从贝叶斯方法谈起非常适合。再由朴素贝叶斯谈到语言模型,由此开始自然语言处理学习之路。

本篇案例实战可见:朴素贝叶斯——新闻、邮件分类以及语种检测,通过案例可以更好的理解理论

一、贝叶斯定理

  在谈贝叶斯方法之前,我们要先了解什么是概率、什么是条件概率、什么是联合概率,以及什么是贝叶斯定理。下面我们就分别介绍:

(1)概率:

  • 事件发生的可能性,比如抛一枚硬币,正面向上的可能性有50%,掷色子点数为6的可能性为1/6。我们用符号表示为 P ( A ) P(A) P(A)

(2)条件概率:

  • 满足某些条件下事件发生的可能性,比如求一个人在买了裤子的前提下再买衣服的概率,我们用符号表示为 P ( B ∣ A ) P(B|A) P(BA),即事件 A A A发生下 B B B发生的概率;

(3)联合概率:

  • 多个事件同时发生的可能性,比如抛硬币两次都朝上的概率 P ( A B ) = P ( A ) P ( B ) P(AB) = P(A)P(B) P(AB)=P(A)P(B),前提是事件是相互独立的互不影响,如果不独立则联合概率为 P ( A B ) = P ( A ) P ( B ∣ A ) P(AB) = P(A)P(B|A) P(AB)=P(A)P(BA)

P ( B ) = P ( B ∣ A ) P(B) = P(B|A) P(B)=P(BA)时表示事件 A , B A,B A,B相互独立的

(4)贝叶斯定理:

利用联合概率我们可以计算出条件概率,比如知道了 P ( A B ) P(AB) P(AB) P ( A ) P(A) P(A)我们想知道事件 A A A发生的前提下 B B B发生的概率则:
P ( B ∣ A ) = P ( A B ) P ( A ) P(B|A) = \frac{P(AB)}{P(A)} P(BA)=P(A)P(AB)
可如果我们想计算 P ( A ∣ B ) P(A|B) P(AB)的概率呢?

不巧的是 P ( A ∣ B ) P(A|B) P(AB)并不等于 P ( B ∣ A ) P(B|A) P(BA)

我们从联合概率知道概率乘积的顺序可以交换即 P ( A B ) = P ( B A ) P(AB) = P(BA) P(AB)=P(BA),然后将两个概率展开 P ( A ) P ( B ∣ A ) = P ( B ) P ( A ∣ B ) P(A)P(B|A) = P(B)P(A|B) P(A)P(BA)=P(B)P(AB),我们可以清楚的看到我们想要的 P ( A ∣ B ) P(A|B) P(AB)就在其中:

P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ) P(A|B) = \frac{P(B|A)P(A)}{ P(B)} P(AB)=P(B)P(BA)P(A)

这就是贝叶斯定理。

P ( A ) P(A) P(A)就是先验概率,我们在计算前假设的某个概率,比如抛硬币正面向上的概率为50%;

P ( B ∣ A P(B|A P(BA)就是后验概率,这是我们看到数据后计算得到的;

P ( A ∣ B ) P(A|B) P(AB)就是先验概率和后验概率计算得到的,称似然度

二、从机器学习角度来看

  在机器学习的视角下,我们把 X X X 理解成“具有某特征”,把 Y Y Y 理解成“类别标签”。在最简单的二分类问题(是与否判定)下,我们将 Y Y Y 理解成“属于某类”的标签。于是贝叶斯公式就变形成了下面的样子:

P ( “ 属 于 某 类 ” ∣ “ 具 有 某 特 征 ” ) = P ( “ 具 有 某 特 征 ” ∣ “ 属 于 某 类 ” ) P ( “ 属 于 某 类 ” ) P ( “ 具 有 某 特 征 ” ) P(“属于某类”|“具有某特征”) = \frac{P(“具有某特征”|“属于某类”)P(“属于某类”)}{P(“具有某特征”)} P()=P()P()P()

其中:

  • P ( “ 属 于 某 类 ” ∣ “ 具 有 某 特 征 ” ) P(“属于某类”|“具有某特征”) P() 表示在已知某样本“具有某特征”的条件下,该样本“属于某类”的概率。即 “后验概率”
  • P ( “ 具 有 某 特 征 ” ∣ “ 属 于 某 类 ” ) P(“具有某特征”|“属于某类”) P() 表示在已知某样本“属于某类”的条件下,该样本“具有某特征”的概率;
  • P ( “ 属 于 某 类 ” ) P(“属于某类”) P() 表示该样本“属于某类”的概率。即 “先验概率”
  • P ( “ 具 有 某 特 征 ” ) P(“具有某特征”) P() 表示在未知某样本“属于某类”的条件下,该样本“具有某特征”的概率。

  我们的任务就是要获得后验概率 P ( “ 属 于 某 类 ” ∣ “ 具 有 某 特 征 ” ) P(“属于某类”|“具有某特征”) P()。然而,在现实任务中我们通常难以直接获得后验概率,从这个角度来看,机器学习所要实现的就是基于有限的训练样本集尽可能准确的估计出后验概率 P ( “ 属 于 某 类 ” ∣ “ 具 有 某 特 征 ” ) P(“属于某类”|“具有某特征”) P(),一般来看,有两种策略:

  • (1)给定 “ 具 有 某 特 征 ” “具有某特征” ,可通过直接建模 P ( “ 属 于 某 类 ” ∣ “ 具 有 某 特 征 ” ) P(“属于某类”|“具有某特征”) P()来预测 “ 属 于 某 类 ” “属于某类” ,这样得到的是“判别式模型”;
  • (2)也可先对联合概率分布 P ( “ 具 有 某 特 征 ” , “ 属 于 某 类 ” ) P(“具有某特征”,“属于某类”) P()建模,然后再由此获得 P ( “ 属 于 某 类 ” ∣ “ 具 有 某 特 征 ” ) P(“属于某类”|“具有某特征”) P(),这样得到的是“生成式模型”。

  贝叶斯方法就是把计算 P ( “ 属 于 某 类 ” ∣ “ 具 有 某 特 征 ” ) P(“属于某类”|“具有某特征”) P() 转换成计算 P ( “ 具 有 某 特 征 ” ∣ “ 属 于 某 类 ” ) P(“具有某特征”|“属于某类”) P(),而后者获取方法就简单多了,我们只需要找到一些包含已知特征标签的样本,即可进行训练。而样本的类别标签都是明确的,所以贝叶斯方法在机器学习里属于有监督学习方法。

举例说明(垃圾邮件分类):

  假设我们现在要对邮件进行分类,识别垃圾邮件和普通邮件,如果我们选择使用朴素贝叶斯分类器,那目标就是判断 P ( “ 垃 圾 邮 件 ” ∣ “ 具 有 某 特 征 ” ) P(“垃圾邮件”|“具有某特征”) P() 是否大于0.5。现在假设我们有垃圾邮件和正常邮件各1万封作为训练集。需要判断以下这个邮件是否属于垃圾邮件:

“我司可办理正规发票(保真)17%增值税发票点数优惠!”

也就是判断概率 P ( “ 垃 圾 邮 件 ” ∣ “ 我 司 可 办 理 正 规 发 票 ( 保 真 ) 17 % 增 值 税 发 票 点 数 优 惠 ! ” ) P(“垃圾邮件”|“我司可办理正规发票(保真)17\%增值税发票点数优惠!”) P(17%)是否大于0.5。

我们要计算的便是:

P ( “ 垃 圾 邮 件 ” ∣ “ 我 司 可 办 理 正 规 发 票 ( 保 真 ) 17 % 增 值 税 发 票 点 数 优 惠 ! ” ) P(“垃圾邮件”|“我司可办理正规发票(保真)17\%增值税发票点数优惠!”) P(17%)
= 垃 圾 邮 件 中 出 现 这 句 话 的 次 数 垃 圾 邮 件 中 出 现 这 句 话 的 次 数 + 普 通 邮 件 中 出 现 这 句 话 的 次 数 = \frac{垃圾邮件中出现这句话的次数}{垃圾邮件中出现这句话的次数+普通邮件中出现这句话的次数} =+

我们发现,这个很简单,只要统计出垃圾邮件和普通邮件中含有这句话的邮件次数即可。

  但是往往想象很美好,现实却很残酷。由于我们中文的强大,要表达这句话的意思的句子有很多种,而且训练集又是有限的,所以要想覆盖所有句子可能性的训练集根本不存在。那么我们又应该如何处理这个问题呢?

句子是多样性的,但是表达这句话意思的词语就那么些。

  我们好像又看到了一丝曙光,汉语常用字2500个,常用词语也是有限的。根据经验两句相似的句子,并不要求每一个字、词语都一样。比如 “我司可办理正规发票,17%增值税发票点数优惠!”,这句话就比之前那句话少了“(保真)”这个词,但是意思基本一样。如果把这些情况也考虑进来,那样本数量就会增加,这就方便我们计算了。

  因此,我们可以不拿整个句子作为特征,而是拿句子里面的词语作为特征去考虑,比如**“正规发票”可以作为一个单独的词语,“增值税”** 也可以作为一个单独的词语等等。

  这便涉及到了,此链接中提到的分词,使用分词工具我们便可以把句子分解成一个个的词语:

句子 “我司可办理正规发票,17%增值税发票点数优惠!” 就可以变成(“我”,“司”,“可”,“办理”,“正规发票”,“保真”,“增值税”,“发票”,“点数”,“优惠”)。

这便是中文自然语言处理中的一个最重要的技术:分词。(关于分词可参见上面的链接)。

此时,对于句子分词后得到的词语,我们可以理解为一个向量:向量的每一个元素代表原来句子中的特定词语 ,这样我们就把之前的整个句子作为特征变成了更细粒度的特征,依据这些特征词我们之前的贝叶斯公式就变成了:

P ( “ 垃 圾 邮 件 ” ∣ ( . . . ) ) = P ( ( . . . ) ∣ “ 垃 圾 邮 件 ” ) P ( “ 垃 圾 邮 件 ” ) P ( ( . . . ) ) P\big(“垃圾邮件”|(...)\big)=\frac{P\big((...)|“垃圾邮件”\big)P(“垃圾邮件”)}{P\big((...)\big)} P((...))=P((...))P((...))P()

P ( “ 普 通 邮 件 ” ∣ ( . . . ) ) = P ( ( . . . ) ∣ “ 普 通 邮 件 ” ) P ( “ 普 通 邮 件 ” ) P ( ( . . . ) ) P\big(“普通邮件”|(...)\big)=\frac{P\big((...)|“普通邮件”\big)P(“普通邮件”)}{P\big((...)\big)} P((...))=P((...))P((...))P()

其中 ( . . . ) (...) (...)表示词向量 ( “ 我 ” , “ 司 ” , “ 可 ” , “ 办 理 ” , “ 正 规 发 票 ” , “ 保 真 ” , “ 增 值 税 ” , “ 发 票 ” , “ 点 数 ” , “ 优 惠 ” ) (“我”,“司”,“可”,“办理”,“正规发票”,“保真”,“增值税”,“发票”,“点数”,“优惠”) (,,,,,,,,,)

  然而,我们发现基于贝叶斯公式来估计后验概率 P ( “ 垃 圾 邮 件 ” ∣ ( . . . ) ) P\big(“垃圾邮件”|(...)\big) P((...)) 也不好求,因为条件概率 P ( ( . . . ) ∣ “ 垃 圾 邮 件 ” ) P\big((...)|“垃圾邮件”\big) P((...))是所有属性上的联合概率,难以从有限的训练数据集中直接估计而得。

条件独立假设:

为了避开这个障碍,我们便使用了一个很朴素的近似,也就是朴素贝叶斯分类器,采用了“属性条件独立假设”:

  对已知类别,假设所有属性相互独立,换言之,假设每个属性独立地对分类结果发生影响。

  基于属性条件独立性假设,可将上面的式子重写为:

P ( “ 垃 圾 邮 件 ” ∣ ( . . . ) ) = P ( ( . . . ) ∣ “ 垃 圾 邮 件 ” ) P ( “ 垃 圾 邮 件 ” ) P ( ( . . . ) ) P\big(“垃圾邮件”|(...)\big)=\frac{P\big((...)|“垃圾邮件”\big)P(“垃圾邮件”)}{P\big((...)\big)} P((...))=P((...))P((...))P()
= P ( “ 垃 圾 邮 件 ” ) P ( ( . . . ) ) ∏ i = 1 d P ( x i ∣ “ 垃 圾 邮 件 ” ) =\frac{P(“垃圾邮件”)}{P\big((...)\big)}\prod_{i=1}^dP\big(x_i|“垃圾邮件”\big) =P((...))P()i=1dP(xi)

其中, ( . . . ) (...) (...)表示此向量, x i x_i xi表示每个词语。

也就是:

P ( ( “ 我 ” , “ 司 ” , “ 可 ” , “ 办 理 ” , “ 正 规 发 票 ” , “ 保 真 ” , “ 增 值 税 ” , “ 发 票 ” , “ 点 数 ” , “ 优 惠 ” ) ∣ S ) = P ( " 我 " ∣ S ) × P ( “ 司 ” ∣ S ) × P ( “ 办 理 ” ∣ S ) × P ( “ 正 规 发 票 ” ∣ S ) × P ( “ 保 真 ” ∣ S ) × P ( “ 增 值 税 ” ∣ S ) × P ( “ 发 票 ” ∣ S ) × P ( “ 点 数 ” ∣ S ) × P ( “ 优 惠 ” ∣ S ) P\big((“我”,“司”,“可”,“办理”,“正规发票”,“保真”,“增值税”,“发票”,“点数”,“优惠”)|S\big)\\ =P("我"|S)\times P(“司”|S)\times P(“办理”|S)\times P(“正规发票”|S) \\ \times P(“保真”|S)\times P(“增值税”|S)\times P(“发票”|S)\times P(“点数”|S)\times P(“优惠”|S) P((,,,,,,,,,)S)=P(""S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)

普通邮件的条件独立假设的式子与上式类似。于是我们将条件独立假设代入上面两个相反事件的贝叶斯公式中:

P ( “ 垃 圾 邮 件 ” ∣ ( . . . ) ) = P ( “ 垃 圾 邮 件 ” ) P ( ( . . . ) ) ∏ i = 1 d P ( x i ∣ “ 垃 圾 邮 件 ” ) P\big(“垃圾邮件”|(...)\big)=\frac{P(“垃圾邮件”)}{P\big((...)\big)}\prod_{i=1}^dP\big(x_i|“垃圾邮件”\big) P((...))=P((...))P()i=1dP(xi)

P ( “ 普 通 邮 件 ” ∣ ( . . . ) ) = P ( “ 普 通 邮 件 ” ) P ( ( . . . ) ) ∏ i = 1 d P ( x i ∣ “ 普 通 邮 件 ” ) P\big(“普通邮件”|(...)\big)=\frac{P(“普通邮件”)}{P\big((...)\big)}\prod_{i=1}^dP\big(x_i|“普通邮件”\big) P((...))=P((...))P()i=1dP(xi)

由于两个式子分母都一样,所以我们只需要比较下面两个式子的大小即可:

C 1 = P ( “ 垃 圾 邮 件 ” ) ∏ i = 1 d P ( x i ∣ “ 垃 圾 邮 件 ” ) = P ( " 我 " ∣ S ) × P ( “ 司 ” ∣ S ) × P ( “ 办 理 ” ∣ S ) × P ( “ 正 规 发 票 ” ∣ S ) × P ( “ 保 真 ” ∣ S ) × P ( “ 增 值 税 ” ∣ S ) × P ( “ 发 票 ” ∣ S ) × P ( “ 点 数 ” ∣ S ) × P ( “ 优 惠 ” ∣ S ) P ( “ 垃 圾 邮 件 ” ) C_1=P(“垃圾邮件”)\prod_{i=1}^dP\big(x_i|“垃圾邮件”\big)\\= P("我"|S)\times P(“司”|S)\times P(“办理”|S)\times P(“正规发票”|S) \times P(“保真”|S)\\\times P(“增值税”|S)\times P(“发票”|S)\times P(“点数”|S)\times P(“优惠”|S)P(“垃圾邮件”) C1=P()i=1dP(xi)=P(""S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)P()

C 2 = P ( “ 普 通 邮 件 ” ) ∏ i = 1 d P ( x i ∣ “ 普 通 邮 件 ” ) = P ( " 我 " ∣ H ) × P ( “ 司 ” ∣ H ) × P ( “ 办 理 ” ∣ H ) × P ( “ 正 规 发 票 ” ∣ H ) × P ( “ 保 真 ” ∣ H ) × P ( “ 增 值 税 ” ∣ H ) × P ( “ 发 票 ” ∣ H ) × P ( “ 点 数 ” ∣ H ) × P ( “ 优 惠 ” ∣ H ) P ( “ 普 通 邮 件 ” ) C_2=P(“普通邮件”)\prod_{i=1}^dP\big(x_i|“普通邮件”\big)\\= P("我"|H)\times P(“司”|H)\times P(“办理”|H)\times P(“正规发票”|H) \times P(“保真”|H)\\\times P(“增值税”|H)\times P(“发票”|H)\times P(“点数”|H)\times P(“优惠”|H)P(“普通邮件”) C2=P()i=1dP(xi)=P(""H)×P(H)×P(H)×P(H)×P(H)×P(H)×P(H)×P(H)×P(H)P()

其中, S , H S,H S,H分别表示“垃圾邮件”、“普通邮件”

这时候我们发现,这个式子中的每一项都特别好求,只需要分别统计各类邮件中该关键词出现的概率就可以了。比如:
P ( “ 发 票 ” ∣ S ) = 垃 圾 邮 件 中 所 有 “ 发 票 ” 的 次 数 垃 圾 邮 件 中 所 有 词 语 的 次 数 P(“发票” | S) = \frac{垃圾邮件中所有“发票”的次数}{垃圾邮件中所有词语的次数} P(S)=

统计次数非常方便,而且样本如果足够大的话,根据大数定理,算出来的概率比较接近真实的。于是垃圾邮件分类的问题就可以解决了。

三、朴素贝叶斯(Naive Bayes,NB)

  上面我们提到了条件独立假设,加上条件独立假设的贝叶斯方法就是朴素贝叶斯方法,我们由下面式子:

P ( ( “ 我 ” , “ 司 ” , “ 可 ” , “ 办 理 ” , “ 正 规 发 票 ” , “ 保 真 ” , “ 增 值 税 ” , “ 发 票 ” , “ 点 数 ” , “ 优 惠 ” ) ∣ S ) = P ( " 我 " ∣ S ) × P ( “ 司 ” ∣ S ) × P ( “ 办 理 ” ∣ S ) × P ( “ 正 规 发 票 ” ∣ S ) × P ( “ 保 真 ” ∣ S ) × P ( “ 增 值 税 ” ∣ S ) × P ( “ 发 票 ” ∣ S ) × P ( “ 点 数 ” ∣ S ) × P ( “ 优 惠 ” ∣ S ) P\big((“我”,“司”,“可”,“办理”,“正规发票”,“保真”,“增值税”,“发票”,“点数”,“优惠”)|S\big)\\ =P("我"|S)\times P(“司”|S)\times P(“办理”|S)\times P(“正规发票”|S) \\ \times P(“保真”|S)\times P(“增值税”|S)\times P(“发票”|S)\times P(“点数”|S)\times P(“优惠”|S) P((,,,,,,,,,)S)=P(""S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)

  可以发现,由于乘法交换律,更换词语的顺序不影响最终的条件概率值,也就是说,朴素贝叶斯忽略了词语之间的顺序信息,例如:“我司可办理正规发票”与“正规发票可办理我司”就完全相同,这就相当于把分词后的所有词扔进一个口袋里随意搅合,朴素贝叶斯认为它们一样,这也就是“词袋模型”。

  虽然朴素贝叶斯忽略了词语的顺序,方法也很朴素,但是在垃圾邮件识别中的正确率却很高。因此,朴素贝叶斯方法看似不咋样,但实际上却简单、使用且强大。

朴素贝叶斯算法可归纳为如下:

输入:训练数据 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . ( x N , y N ) } T = \{(x_1,y_1),(x_2,y_2),...(x_N,y_N)\} T={(x1,y1),(x2,y2),...(xN,yN)},其中 x i = ( x i ( 1 ) , x i ( 2 ) , . . . , x i ( n ) ) T x_i = (x_i^{(1)},x_i^{(2)},...,x_i^{(n)})^T xi=(xi(1),xi(2),...,xi(n))T x i ( j ) x_i^{(j)} xi(j)是第 i i i个样本的第 j j j个特征, x i ( j ) ∈ { a j 1 , a j 2 , . . . , a j S j , } x_i^{(j)} \in \{a_{j1},a_{j2},...,a_{jS_j},\} xi(j){aj1,aj2,...,ajSj,} a j l a_{jl} ajl是第 j j j个特征可能取的第 l l l个值, j = 1 , 2 , . . . , n , l = 1 , 2 , . . . , S j , y i ∈ { c 1 , c 2 , . . . , c K } j = 1,2,...,n,l = 1,2,...,S_j,y_i \in \{c_1,c_2,...,c_K\} j=1,2,...,nl=1,2,...,Sjyi{c1,c2,...,cK};实例 x x x

输出:实例 x x x的分类;

(1)计算先验概率及条件概率的极大似然估计:
P ( Y = c k ) = ∑ i = 1 N I ( y i = c k ) N , k = 1 , 2 , . . . , K P(Y=c_k) =\frac{\sum_{i=1}^NI(y_i = c_k)}{N},k = 1,2,...,K P(Y=ck)=Ni=1NI(yi=ck)k=1,2,...,K
P ( X ( j ) = a j l ∣ Y = c k ) = ∑ i = 1 N I ( x i ( j ) = a j l , y i = c k ) ∑ i = 1 N I ( y i = c k ) P(X^{(j)} = a_{jl} | Y=c_k) = \frac{\sum_{i=1}^N I(x_i^{(j)}=a_{jl},y_i=c_k)}{\sum_{i=1}^NI(y_i = c_k)} P(X(j)=ajlY=ck)=i=1NI(yi=ck)i=1NI(xi(j)=ajl,yi=ck)
j = 1 , 2 , . . . , n ; l = 1 , 2 , . . . , S j ; k = 1 , 2 , . . . , K j = 1,2,...,n;l = 1,2,...,S_j;k = 1,2,...,K j=1,2,...,nl=1,2,...,Sjk=1,2,...,K
其中, I ( x i ( j ) = a j l , y i = c k ) I(x_i^{(j)}=a_{jl},y_i=c_k) I(xi(j)=ajl,yi=ck)为指示函数,表示标签为 c k c_k ck且特征值为 a j i a_{ji} aji的就计数;

I ( y i = c k ) I(y_i = c_k) I(yi=ck)表示标签为 c k c_k ck的样本个数。

(2)对于给定的实例 x = ( x ( 1 ) , x ( 2 ) , . . . , x ( n ) ) T x = (x^{(1)},x^{(2)},...,x^{(n)})^T x=(x(1),x(2),...,x(n))T,计算:
P ( Y = c k ) ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) , k = 1 , 2 , . . . , K P(Y=c_k) \prod_{j = 1} ^n P(X^{(j)} = x^{(j)} | Y=c_k),k = 1,2,...,K P(Y=ck)j=1nP(X(j)=x(j)Y=ck)k=1,2,...,K
(3)确定实例 x x x的类
y = a r g max ⁡ c k P ( Y = c k ) ∏ j = 1 n P ( X ( j ) = x ( j ) ∣ Y = c k ) y = arg \max_{c_k}P(Y = c_k)\prod_{j = 1} ^n P(X^{(j)} = x^{(j)} | Y=c_k) y=argckmaxP(Y=ck)j=1nP(X(j)=x(j)Y=ck)

D c D_c Dc表示训练数据集 D D D中第 c c c类样本组成的集合,若有充足的独立同分布样本,则可容易计算出类先验概率:
P ( c ) = ∣ D c ∣ D P(c) = \frac{|D_c|}{D} P(c)=DDc
对于离散属性而言,令 D c , x i D_{c,x_i} Dc,xi表示 D c D_c Dc中在第 i i i个属性上取值为 x i x_i xi的样本组成的集合,则条件概率 P ( x i ∣ c ) P(x_i | c) P(xic)可估计为:
P ( x i ∣ c ) = ∣ D c , x i ∣ ∣ D c ∣ P(x_i | c) = \frac{|D_{c,x_i}|}{|D_c|} P(xic)=DcDc,xi
对于连续属性而言可考虑概率密度函数,假定 p ( x i ∣ c ) ∽ N ( μ c , i , σ c , i 2 ) , p(x_i | c) \backsim \mathcal{N}(\mu_{c,i},\sigma^2_{c,i}), p(xic)N(μc,i,σc,i2)其中 μ c , i , σ c , i 2 \mu_{c,i},\sigma^2_{c,i} μc,iσc,i2分别是第 c c c类在第 i i i个属性上取值的均值和方差,则有:
P ( x i ∣ c ) = 1 2 π σ c , i e x p ( − ( x i − μ c , i ) 2 2 σ c , i 2 ) P(x_i | c) = \frac{1}{\sqrt{2 \pi}\sigma_{c,i}}exp \Big(-\frac{(x_i -\mu_{c,i} )^2}{2\sigma^2_{c,i}}\Big) P(xic)=2π σc,i1exp(2σc,i2(xiμc,i)2)

四、贝叶斯估计

  在上面的算法中,我们使用的是极大似然估计,但是可能回出现概率值为0的情况,这是会影响到后验概率的计算结果,是分类产生误差。

为了解决这一问题,下面我们介绍贝叶斯估计。

条件概率的贝叶斯估计为:
P λ ( X ( j ) = x ( j ) ∣ Y = c k ) = ∑ i = 1 N I ( x i ( j ) = a j l , y i = c k ) + λ ∑ i = 1 N I ( y i = c k ) + S j λ P_\lambda(X^{(j)} = x^{(j)} | Y=c_k) = \frac{\sum_{i=1}^N I(x_i^{(j)}=a_{jl},y_i=c_k) + \lambda}{\sum_{i=1}^NI(y_i = c_k) + S_j \lambda} Pλ(X(j)=x(j)Y=ck)=i=1NI(yi=ck)+Sjλi=1NI(xi(j)=ajl,yi=ck)+λ

式中 λ ⩾ 0 \lambda \geqslant 0 λ0,等价于在随机变量各个取值的频数上赋予一个正数 λ > 0 \lambda > 0 λ>0 S j S_j Sj表示第 j j j个属性可能的取值数;

λ = 0 \lambda = 0 λ=0时就是极大似然估计;
常取 λ = 1 \lambda = 1 λ=1时,称为拉普拉斯平滑;

显然,对任何 l = 1 , 2 , . . . , S j , k = 1 , 2 , . . . , K l = 1,2,...,S_j, k = 1,2,...,K l=1,2,...,Sjk=1,2,...,K,有:

P λ ( X ( j ) = a j l ∣ Y = c k ) > 0 ∑ l = 1 S j P λ ( X ( j ) = x ( j ) ∣ Y = c k ) = 1 P_\lambda(X^{(j)} = a_{jl} | Y=c_k) > 0 \\ \sum_{l=1}^{S_j}P_\lambda(X^{(j)} = x^{(j)} | Y=c_k) = 1 Pλ(X(j)=ajlY=ck)>0l=1SjPλ(X(j)=x(j)Y=ck)=1

同样,先验概率的贝叶斯估计为:
P λ ( Y = c k ) = ∑ i = 1 N I ( y i = c k ) + λ N + K λ P_\lambda(Y=c_k) =\frac{\sum_{i=1}^NI(y_i = c_k) + \lambda}{N + K \lambda} Pλ(Y=ck)=N+Kλi=1NI(yi=ck)+λ

其中, K K K表示训练集中可能的类别数。

实例计算:

有如下数据集(数据来源《机器学习》西瓜数据集3.0)

【NLP】从贝叶斯谈到N-gram语言模型_第1张图片

测试样本:

青绿    蜷缩    浊响    清晰    凹陷    硬滑    0.697    0.460    ?

(1)首先计算类先验概率和每个属性的条件概率:
P ( 好 瓜 ) = 8 17 ≈ 0.471 P ( 坏 瓜 ) = 9 17 ≈ 0.529 P(好瓜 ) = \frac{8}{17} \approx 0.471\\ P(坏瓜 ) = \frac{9}{17} \approx 0.529 P()=1780.471P()=1790.529

P 青 绿 ∣ 好 瓜 = P ( 色 泽 = 青 绿 ∣ 好 瓜 ) = 3 8 ≈ 0.375 P 青 绿 ∣ 坏 瓜 = P ( 色 泽 = 青 绿 ∣ 坏 瓜 ) = 3 9 ≈ 0.333 P 蜷 缩 ∣ 好 瓜 = P ( 根 蒂 = 蜷 缩 ∣ 好 瓜 ) = 5 8 = 0.625 P 蜷 缩 ∣ 坏 瓜 = P ( 根 蒂 = 蜷 缩 ∣ 坏 瓜 ) = 3 9 ≈ 0.333 P 浊 响 ∣ 好 瓜 = P ( 敲 声 = 浊 响 ∣ 好 瓜 ) = 6 8 = 0.750 P 浊 响 ∣ 坏 瓜 = P ( 敲 声 = 浊 响 ∣ 坏 瓜 ) = 4 9 ≈ 0.444 P 清 晰 ∣ 好 瓜 = P ( 纹 理 = 清 晰 ∣ 好 瓜 ) = 7 8 = 0.875 P 清 晰 ∣ 坏 瓜 = P ( 纹 理 = 清 晰 ∣ 坏 瓜 ) = 2 9 ≈ 0.222 P 凹 陷 ∣ 好 瓜 = P ( 脐 部 = 凹 陷 ∣ 好 瓜 ) = 5 8 = 0.625 P 凹 陷 ∣ 坏 瓜 = P ( 脐 部 = 凹 陷 ∣ 坏 瓜 ) = 2 9 ≈ 0.222 P 硬 滑 ∣ 好 瓜 = P ( 触 感 = 硬 滑 ∣ 好 瓜 ) = 6 8 = 0.750 P 硬 滑 ∣ 坏 瓜 = P ( 触 感 = 硬 滑 ∣ 坏 瓜 ) = 6 9 ≈ 0.667 P 密 度 : 0.697 ∣ 好 瓜 = P ( 密 度 = 0.697 ∣ 好 瓜 ) = 1 2 π ⋅ 0.129 e x p ( − ( 0.697 − 0.574 ) 2 2 ⋅ 0.12 9 2 ) ≈ 1.959 P_{青绿|好瓜} = P(色泽 = 青绿 | 好瓜) = \frac{3}{8}\approx 0.375 \\ P_{青绿|坏瓜} = P(色泽 = 青绿 | 坏瓜) = \frac{3}{9}\approx 0.333\\ P_{蜷缩|好瓜} = P(根蒂 = 蜷缩 | 好瓜) = \frac{5}{8} = 0.625\\ P_{蜷缩|坏瓜} = P(根蒂 = 蜷缩 | 坏瓜) = \frac{3}{9}\approx 0.333\\ P_{浊响|好瓜} = P(敲声 = 浊响 | 好瓜) = \frac{6}{8}= 0.750\\ P_{浊响|坏瓜} = P(敲声 = 浊响 | 坏瓜) = \frac{4}{9}\approx 0.444\\ P_{清晰|好瓜} = P(纹理 = 清晰 | 好瓜) = \frac{7}{8}= 0.875\\ P_{清晰|坏瓜} = P(纹理 = 清晰 | 坏瓜) = \frac{2}{9}\approx 0.222\\ P_{凹陷|好瓜} = P(脐部 = 凹陷 | 好瓜) = \frac{5}{8}= 0.625\\ P_{凹陷|坏瓜} = P(脐部 = 凹陷 | 坏瓜) = \frac{2}{9}\approx 0.222\\ P_{硬滑|好瓜} = P(触感 = 硬滑 | 好瓜) = \frac{6}{8}= 0.750\\ P_{硬滑|坏瓜} = P(触感 = 硬滑 | 坏瓜) = \frac{6}{9}\approx 0.667 \\ \\ P_{密度:0.697|好瓜} = P(密度=0.697 | 好瓜) = \frac{1}{\sqrt{2\pi} \cdot 0.129} exp(-\frac{(0.697 - 0.574)^2}{2 \cdot 0.129^2})\approx 1.959 P绿=P(=绿)=830.375P绿=P(=绿)=930.333P=P(=)=85=0.625P=P(=)=930.333P=P(=)=86=0.750P=P(=)=940.444P=P(=)=87=0.875P=P(=)=920.222P=P(=)=85=0.625P=P(=)=920.222P=P(=)=86=0.750P=P(=)=960.667P0.697=P(=0.697)=2π 0.1291exp(20.1292(0.6970.574)2)1.959
其中,0.574为好瓜的密度均值, 0.12 9 2 0.129^2 0.1292为方差
P 密 度 : 0.697 ∣ 坏 瓜 = P ( 密 度 = 0.697 ∣ 坏 瓜 ) = 1 2 π ⋅ 0.195 e x p ( − ( 0.697 − 0.496 ) 2 2 ⋅ 0.19 5 2 ) ≈ 1.203 P_{密度:0.697|坏瓜} = P(密度=0.697 | 坏瓜) = \frac{1}{\sqrt{2\pi} \cdot 0.195} exp(-\frac{(0.697 - 0.496)^2}{2 \cdot 0.195^2})\approx 1.203 P0.697=P(=0.697)=2π 0.1951exp(20.1952(0.6970.496)2)1.203
其中,0.496为坏瓜的密度均值, 0.19 5 2 0.195^2 0.1952为方差
P 含 糖 率 : 0.460 ∣ 好 瓜 = P ( 含 糖 率 = 0.460 ∣ 好 瓜 ) = 1 2 π ⋅ 0.101 e x p ( − ( 0.460 − 0.297 ) 2 2 ⋅ 0.10 1 2 ) ≈ 0.788 P_{含糖率:0.460|好瓜} = P(含糖率=0.460| 好瓜) = \frac{1}{\sqrt{2\pi} \cdot 0.101} exp(-\frac{(0.460 - 0.297)^2}{2 \cdot 0.101^2})\approx 0.788 P0.460=P(=0.460)=2π 0.1011exp(20.1012(0.4600.297)2)0.788
其中,0.297为好瓜的含糖率均值, 0.10 1 2 0.101^2 0.1012为方差
P 含 糖 率 : 0.460 ∣ 坏 瓜 = P ( 含 糖 率 = 0.460 ∣ 坏 瓜 ) = 1 2 π ⋅ 0.108 e x p ( − ( 0.460 − 0.154 ) 2 2 ⋅ 0.10 8 2 ) ≈ 0.066 P_{含糖率:0.460|坏瓜} = P(含糖率=0.460|坏瓜) =\frac{1}{\sqrt{2\pi} \cdot 0.108} exp(-\frac{(0.460 - 0.154)^2}{2 \cdot 0.108^2})\approx 0.066 P0.460=P(=0.460)=2π 0.1081exp(20.1082(0.4600.154)2)0.066
其中,0.154为坏瓜的含糖率均值, 0.10 8 2 0.108^2 0.1082为方差

(2)于是,有:
P ( 好 瓜 ) × P 青 绿 ∣ 好 瓜 × P 蜷 缩 ∣ 好 瓜 × P 浊 响 ∣ 好 瓜 × P 清 晰 ∣ 好 瓜 × P 凹 陷 ∣ 好 瓜 × P 硬 滑 ∣ 好 瓜 × P 密 度 : 0.697 ∣ 好 瓜 × P 含 糖 率 : 0.460 ∣ 好 瓜 ≈ 0.063 P(好瓜) \times P_{青绿|好瓜} \times P_{蜷缩|好瓜} \times P_{浊响|好瓜} \times P_{清晰|好瓜}\\ \times P_{凹陷|好瓜} \times P_{硬滑|好瓜} \times P_{密度:0.697|好瓜} \times P_{含糖率:0.460|好瓜} \approx 0.063 P()×P绿×P×P×P×P×P×P0.697×P0.4600.063

P ( 坏 瓜 ) × P 青 绿 ∣ 坏 瓜 × P 蜷 缩 ∣ 坏 瓜 × P 浊 响 ∣ 坏 瓜 × P 清 晰 ∣ 坏 瓜 × P 凹 陷 ∣ 坏 瓜 × P 硬 滑 ∣ 坏 瓜 × P 密 度 : 0.697 ∣ 坏 瓜 × P 含 糖 率 : 0.460 ∣ 坏 瓜 ≈ 6.80 × 1 0 − 5 P(坏瓜) \times P_{青绿|坏瓜} \times P_{蜷缩|坏瓜} \times P_{浊响|坏瓜} \times P_{清晰|坏瓜}\\ \times P_{凹陷|坏瓜} \times P_{硬滑|坏瓜} \times P_{密度:0.697|坏瓜} \times P_{含糖率:0.460|坏瓜} \approx 6.80 \times 10^{-5} P()×P绿×P×P×P×P×P×P0.697×P0.4606.80×105

(3)由于 0.063 > 6.80 × 1 0 − 5 0.063 > 6.80 \times 10^{-5} 0.063>6.80×105,因此,朴素贝叶斯分类器将测试样本分类为“好瓜”。

需要注意,若某个属性值在训练集中没有与某个类同时出现过,如:
P 清 脆 ∣ 好 瓜 = P ( 敲 声 = 清 脆 ∣ 好 瓜 ) = 0 8 = 0 P_{清脆|好瓜} = P(敲声 = 清脆 | 好瓜) = \frac{0}{8} = 0 P=P(=)=80=0
此时,连乘式计算出的概率值为0;
为了避免此问题,我们就可以使用贝叶斯估计。

四、实际项目中一些技巧

4.1 处理重复词语

  前面我们仅讨论了一句话分词后中没有重复的词语,那么要是一句话分词后有重复的词语该怎么处理呢?例如:

“代开发票。增值税发票,正规发票。” 分词后为向量: (“代开”,“发票”,“增值税”,“发票”,“正规”,“发票”)

一般有三种方式:

  • 多项式模型

如果我们考虑重复词语的情况,也就是说,重复的词语我们视为其出现多次,直接按条件独立假设的方式推导,则有:

P ( ( “ 代 开 ” , “ 发 票 ” , “ 增 值 税 ” , “ 发 票 ” , “ 正 规 ” , “ 发 票 ” ) ∣ S ) P\big((“代开”,“发票”,“增值税”,“发票”,“正规”,“发票”)|S\big) P((,,,,,)S)
= P ( “ 代 开 ” ∣ S ) × P ( “ 发 票 ” ∣ S ) × P ( “ 增 值 税 ” ∣ S ) × P ( “ 发 票 ” ∣ S ) × P ( “ 正 规 ” ∣ S ) × P ( “ 发 票 ” ∣ S ) =P(“代开”|S)\times P(“发票”|S)\times P(“增值税”|S)\times P(“发票”|S) \times P(“正规”|S)\times P(“发票”|S) =P(S)×P(S)×P(S)×P(S)×P(S)×P(S)
= P ( “ 代 开 ” ∣ S ) × P ( “ 发 票 ” ∣ S ) 3 × P ( “ 增 值 税 ” ∣ S ) × P ( “ 正 规 ” ∣ S ) × = P(“代开”|S)\times P(“发票”|S)^3\times P(“增值税”|S)\times P(“正规”|S)\times =P(S)×P(S)3×P(S)×P(S)×

在统计计算 P ( “ 发 票 ” ∣ S ) P(“发票”|S) P(S)时,每个被统计的垃圾邮件样本中重复的词语也统计多次。

P ( “ 发 票 ” ∣ S ) = 每 封 垃 圾 邮 件 中 出 现 “ 发 票 ” 的 次 数 的 总 和 每 封 垃 圾 邮 件 中 所 有 词 语 ( 计 算 重 复 的 词 语 ) 的 总 和 P(“发票”|S) = \frac{每封垃圾邮件中出现“发票”的次数的总和}{每封垃圾邮件中所有词语(计算重复的词语)的总和} P(S)=

你看这个多次出现的结果,出现在概率的指数/次方上,因此这样的模型叫作多项式模型。

  • 伯努利模型

另一种更加简化的方法是将重复的词语都视为其只出现1次:

P ( ( “ 代 开 ” , “ 发 票 ” , “ 增 值 税 ” , “ 发 票 ” , “ 正 规 ” , “ 发 票 ” ) ∣ S ) P((“代开”,“发票”,“增值税”,“发票”,“正规”,“发票”)|S) P((,,,,,)S)
= P ( “ 发 票 ” ∣ S ) P ( “ 代 开 ” ” ∣ S ) P ( “ 增 值 税 ” ∣ S ) P ( “ 正 规 ” ∣ S ) =P(“发票”|S)P(“代开””|S)P(“增值税”|S)P(“正规”|S) =P(S)P(S)P(S)P(S)
P ( “ 发 票 ” ∣ S ) = 出 现 “ 发 票 ” 的 垃 圾 邮 件 的 封 数 每 封 垃 圾 邮 件 中 所 有 词 语 ( 不 计 算 重 复 的 词 语 ) 的 总 和 P(“发票”|S) = \frac{出现“发票”的垃圾邮件的封数}{每封垃圾邮件中所有词语(不计算重复的词语)的总和} P(S)=

这样的模型叫作伯努利模型(又称为二项独立模型)。这种方式更加简化与方便。当然它丢失了词频的信息,因此效果可能会差一些。

  • 混合模型

第三种方式是在计算句子概率时,不考虑重复词语出现的次数,但是在统计计算词语的概率 P ( “ 词 语 ” ∣ S ) P(“词语”|S) P(S)时,却考虑重复词语的出现次数,这样的模型可以叫作混合模型。

我们通过下图展示三种模型的关系。

【NLP】从贝叶斯谈到N-gram语言模型_第2张图片

具体实践中采用那种模型,关键看具体的业务场景,一个简单经验是,对于垃圾邮件识别,混合模型更好些。

4.2 去除停用词与选择关键词

  我们继续观察(“我”,“司”,“可”,“办理”,“正规发票”,“保真”,“增值税”,“发票”,“点数”,“优惠”) 这句话。其实,像“我”、“可”之类词其实非常中性,无论其是否出现在垃圾邮件中都无法帮助判断的有用信息。所以可以直接不考虑这些典型的词。这些无助于我们分类的词语叫作“停用词”(Stop Words)。这样可以减少我们训练模型、判断分类的时间。 于是之前的句子就变成了(“司”,“办理”,“正规发票”,“保真”,“增值税”,“发票”,“点数”,“优惠”) 。

  我们进一步分析。以人类的经验,其实“正规发票”、“发票”这类的词如果出现的话,邮件作为垃圾邮件的概率非常大,可以作为我们区分垃圾邮件的“关键词”。而像“司”、“办理”、“优惠”这类的词则有点鸡肋,可能有助于分类,但又不那么强烈。如果想省事做个简单的分类器的话,则可以直接采用“关键词”进行统计与判断,剩下的词就可以先不管了。于是之前的垃圾邮件句子就变成了(“正规发票”,“发票”) 。这样就更加减少了我们训练模型、判断分类的时间,速度非常快。

“停用词”和“关键词”一般都可以提前靠人工经验指定。不同的“停用词”和“关键词”训练出来的分类器的效果也会有些差异。

4.3 取对数

我们提到用来识别垃圾邮件的方法是比较以下两个概率的大小(字母S表示“垃圾邮件”,字母H表示“普通邮件/正常邮件”):

C 1 = P ( “ 垃 圾 邮 件 ” ) ∏ i = 1 d P ( x i ∣ “ 垃 圾 邮 件 ” ) = P ( " 我 " ∣ S ) × P ( “ 司 ” ∣ S ) × P ( “ 办 理 ” ∣ S ) × P ( “ 正 规 发 票 ” ∣ S ) × P ( “ 保 真 ” ∣ S ) × P ( “ 增 值 税 ” ∣ S ) × P ( “ 发 票 ” ∣ S ) × P ( “ 点 数 ” ∣ S ) × P ( “ 优 惠 ” ∣ S ) P ( “ 垃 圾 邮 件 ” ) C_1=P(“垃圾邮件”)\prod_{i=1}^dP\big(x_i|“垃圾邮件”\big)\\= P("我"|S)\times P(“司”|S)\times P(“办理”|S)\times P(“正规发票”|S) \times P(“保真”|S)\\\times P(“增值税”|S)\times P(“发票”|S)\times P(“点数”|S)\times P(“优惠”|S)P(“垃圾邮件”) C1=P()i=1dP(xi)=P(""S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)P()

C 2 = P ( “ 普 通 邮 件 ” ) ∏ i = 1 d P ( x i ∣ “ 普 通 邮 件 ” ) = P ( " 我 " ∣ H ) × P ( “ 司 ” ∣ H ) × P ( “ 办 理 ” ∣ H ) × P ( “ 正 规 发 票 ” ∣ H ) × P ( “ 保 真 ” ∣ H ) × P ( “ 增 值 税 ” ∣ H ) × P ( “ 发 票 ” ∣ H ) × P ( “ 点 数 ” ∣ H ) × P ( “ 优 惠 ” ∣ H ) P ( “ 普 通 邮 件 ” ) C_2=P(“普通邮件”)\prod_{i=1}^dP\big(x_i|“普通邮件”\big)\\= P("我"|H)\times P(“司”|H)\times P(“办理”|H)\times P(“正规发票”|H) \times P(“保真”|H)\\\times P(“增值税”|H)\times P(“发票”|H)\times P(“点数”|H)\times P(“优惠”|H)P(“普通邮件”) C2=P()i=1dP(xi)=P(""H)×P(H)×P(H)×P(H)×P(H)×P(H)×P(H)×P(H)×P(H)P()

  但这里进行了很多乘法运算,计算的时间开销比较大。尤其是对于篇幅比较长的邮件,几万个数相乘起来还是非常花时间的。如果能把这些乘法变成加法则方便得多。刚好数学中的对数函数log就可以实现这样的功能。两边同时取对数(本文统一取底数为2),则上面的公式变为:

l o g C 1 = l o g P ( " 我 " ∣ S ) + l o g P ( “ 司 ” ∣ S ) + l o g P ( “ 办 理 ” ∣ S ) + l o g P ( “ 正 规 发 票 ” ∣ S ) logC_1= logP("我"|S)+log P(“司”|S)+log P(“办理”|S)+log P(“正规发票”|S) logC1=logP(""S)+logP(S)+logP(S)+logP(S)
+ l o g P ( “ 保 真 ” ∣ S ) + l o g P ( “ 增 值 税 ” ∣ S ) + l o g P ( “ 发 票 ” ∣ S ) +log P(“保真”|S)+logP(“增值税”|S)+log P(“发票”|S) +logP(S)+logP(S)+logP(S)
+ l o g P ( “ 点 数 ” ∣ S ) + l o g P ( “ 优 惠 ” ∣ S ) + l o g P ( “ 垃 圾 邮 件 ” ) +log P(“点数”|S)+log P(“优惠”|S)+ logP(“垃圾邮件”) +logP(S)+logP(S)+logP()
l o g C 2 = l o g P ( " 我 " ∣ H ) + l o g P ( “ 司 ” ∣ H ) + l o g P ( “ 办 理 ” ∣ H ) + l o g P ( “ 正 规 发 票 ” ∣ H ) logC_2= logP("我"|H)+log P(“司”|H)+log P(“办理”|H)+log P(“正规发票”|H) logC2=logP(""H)+logP(H)+logP(H)+logP(H)
+ l o g P ( “ 保 真 ” ∣ H ) + l o g P ( “ 增 值 税 ” ∣ H ) + l o g P ( “ 发 票 ” ∣ H ) +log P(“保真”|H)+logP(“增值税”|H)+log P(“发票”|H) +logP(H)+logP(H)+logP(H)
+ l o g P ( “ 点 数 ” ∣ H ) + l o g P ( “ 优 惠 ” ∣ H ) + l o g P ( “ 普 通 邮 件 ” ) +log P(“点数”|H)+log P(“优惠”|H)+ logP(“普通邮件”) +logP(H)+logP(H)+logP()

可是“做对数运算岂不会也很花时间?”的确如此,但是可以在训练阶段直接计算 l o g P logP logP ,然后把他们存在一张大的hash表里。在判断的时候直接提取hash表中已经计算好的对数概率,然后相加即可。这样使得判断所需要的计算时间被转移到了训练阶段,实时运行的时候速度就比之前快得多,这可不止几个数量级的提升。

4.3 转换为权重

  对于二分类,我们还可以继续提高判断的速度。既然要比较 l o g C 1 logC_1 logC1 l o g C 2 logC_2 logC2 的大小,那就可以直接将上下两式相减,并继续化简:

l o g C 1 C 2 = l o g P ( " 我 " ∣ S ) P ( " 我 " ∣ H ) + l o g P ( “ 司 ” ∣ S ) P ( “ 司 ” ∣ H ) + l o g P ( “ 办 理 ” ∣ S ) P ( “ 办 理 ” ∣ H ) + l o g P ( “ 正 规 发 票 ” ∣ S ) P ( “ 正 规 发 票 ” ∣ H ) log \frac{C_1}{C_2} = log\frac{P("我"|S)}{P("我"|H)} +log\frac{P(“司”|S)}{P(“司”|H)} +log\frac{P(“办理”|S)}{P(“办理”|H)}+log\frac{P(“正规发票”|S)}{P(“正规发票”|H)} logC2C1=logP(""H)P(""S)+logP(H)P(S)+logP(H)P(S)+logP(H)P(S)
+ l o g P ( “ 保 真 ” ∣ S ) P ( “ 保 真 ” ∣ H ) + l o g P ( “ 增 值 税 ” ∣ S ) P ( “ 增 值 税 ” ∣ H ) + l o g P ( “ 发 票 ” ∣ S ) P ( “ 发 票 ” ∣ H ) + l o g P ( “ 点 数 ” ∣ S ) P ( “ 点 数 ” ∣ H ) +log\frac{P(“保真”|S)}{P(“保真”|H)}+log\frac{P(“增值税”|S)}{P(“增值税”|H)}+log\frac{ P(“发票”|S)}{ P(“发票”|H)}+log\frac{P(“点数”|S)}{P(“点数”|H)} +logP(H)P(S)+logP(H)P(S)+logP(H)P(S)+logP(H)P(S)
+ l o g P ( “ 优 惠 ” ∣ S ) P ( “ 优 惠 ” ∣ H ) + l o g P ( “ 垃 圾 邮 件 ” ) P ( “ 普 通 邮 件 ” ) +log\frac{P(“优惠”|S)}{P(“优惠”|H)}+log\frac{P(“垃圾邮件”)}{P(“普通邮件”)} +logP(H)P(S)+logP()P()

如果 l o g C 1 C 2 log \frac{C_1}{C_2} logC2C1大于0则属于垃圾邮件,此外我们还可以把 l o g P ( “ 正 规 发 票 ” ∣ S ) P ( “ 正 规 发 票 ” ∣ H ) log\frac{P(“正规发票”|S)}{P(“正规发票”|H)} logP(H)P(S) 作为“正规发票”的权重,权重越大就越说明“正规发票”更可能是与“垃圾邮件”相关的特征。这样可以根据权重的大小来评估和筛选显著的特征,比如关键词。而这些权重值可以直接提前计算好而存在hash表中 。判断的时候直接将权重求和即可。

4.4 选取topk的关键词

  前文说过可以通过提前选取关键词来提高判断的速度。有一种方法可以省略提前选取关键词的步骤,就是直接选取一段文本中权重最高的K个词语,将其权重进行加和。

  通过权重hash表可知,如果是所有词语的权重,则权重有正有负。如果只选择权重最高的K个词语,则它们的权重基本都是正的。所以就不能像之前那样判断 l o g C 1 C 2 log \frac{C_1}{C_2} logC2C1 是否大于0来区分邮件了。而这需要依靠经验选定一个正数的阈值(门槛值) ,依据 l o g C 1 C 2 log \frac{C_1}{C_2} logC2C1与该门槛值的大小来识别垃圾邮件。

4.5 分割样本

选取topk个词语的方法对于篇幅变动不大的邮件样本比较有效。但是对篇幅过大或者过小的邮件则会有判断误差。

  比如这个垃圾邮件的例子:(“我”,“司”,“可”,“办理”,“正规发票”,“保真”,“增值税”,“发票”,“点数”,“优惠”)。分词出了10个词语,其中有“正规发票”、“发票”2个关键词。关键词的密度还是蛮大的,应该算是敏感邮件。但因为采用最高15个词语的权重求和,并且相应的阈值是基于15个词的情况有效,可能算出来的结果还小于之前的阈值,这就造成漏判了。

  类似的,如果一封税务主题的邮件有1000个词语,其中只有“正规发票”、“发票”、“避税方法”3个权重比较大的词语,它们只是在正文表述中顺带提到的内容。关键词的密度被较长的篇幅稀释了,应该算是正常邮件。但是却被阈值判断成敏感邮件,造成误判了。

  这两种情况都说明topk关键词的方法需要考虑篇幅的影响。这里有许多种处理方式,它们的基本思想都是选取词语的个数及对应的阈值要与篇幅的大小成正比,本文只介绍其中一种方方法:

  • 对于长篇幅邮件,按一定的大小,比如每500字,将其分割成小的文本段落,再对小文本段落采用topk关键词的方法。只要其中有一个小文本段落超过阈值就判断整封邮件是垃圾邮件。

  • 对于超短篇幅邮件,比如50字,可以按篇幅与标准比较篇幅的比例来选取topk,以确定应该匹配关键词语的个数。比如选取 50 500 × 15 ≈ 2 \frac{50}{500}×15≈2 50050×152 个词语进行匹配,相应的阈值可以是之前阈值的 2 15 \frac{2}{15} 152 。以此来判断则更合理。

4.6 位置权重

  到目前为止,我们对词语权重求和的过程都没有考虑邮件篇章结构的因素。比如“正规发票”如果出现在标题中应该比它出现在正文中对判断整个邮件的影响更大;而出现在段首句中又比其出现在段落正文中对判断整个邮件的影响更大。所以可以根据词语出现的位置,对其权重再乘以一个放大系数,以扩大其对整封邮件的影响,提高识别准确度。

比如一封邮件其标题是“正规发票”(假设标题的放大系数为2),段首句是“发票”,“点数”,“优惠”(假设段首的放大系数为1.5),剩下的句子是(“我”,“司”,“可”,“办理”,“保真”)。则计算 l o g C 1 C 2 log \frac{C_1}{C_2} logC2C1时的公式就可以调整为:

l o g C 1 C 2 = 2 × l o g P ( “ 正 规 发 票 ” ∣ S ) P ( “ 正 规 发 票 ” ∣ H ) + 1.5 × l o g P ( “ 发 票 ” ∣ S ) P ( “ 发 票 ” ∣ H ) + 1.5 × l o g P ( “ 点 数 ” ∣ S ) P ( “ 点 数 ” ∣ H ) log \frac{C_1}{C_2} =2\times log\frac{P(“正规发票”|S)}{P(“正规发票”|H)}+1.5 \times log\frac{ P(“发票”|S)}{ P(“发票”|H)}+1.5 \times log\frac{P(“点数”|S)}{P(“点数”|H)} logC2C1=2×logP(H)P(S)+1.5×logP(H)P(S)+1.5×logP(H)P(S)
+ 1.5 × l o g P ( “ 优 惠 ” ∣ S ) P ( “ 优 惠 ” ∣ H ) + l o g P ( " 我 " ∣ S ) P ( " 我 " ∣ H ) + l o g P ( “ 司 ” ∣ S ) P ( “ 司 ” ∣ H ) + l o g P ( “ 办 理 ” ∣ S ) P ( “ 办 理 ” ∣ H ) +1.5 \times log\frac{P(“优惠”|S)}{P(“优惠”|H)}+ log\frac{P("我"|S)}{P("我"|H)} +log\frac{P(“司”|S)}{P(“司”|H)} +log\frac{P(“办理”|S)}{P(“办理”|H)} +1.5×logP(H)P(S)+logP(""H)P(""S)+logP(H)P(S)+logP(H)P(S)
+ l o g P ( “ 保 真 ” ∣ S ) P ( “ 保 真 ” ∣ H ) + l o g P ( “ 增 值 税 ” ∣ S ) P ( “ 增 值 税 ” ∣ H ) + l o g P ( “ 垃 圾 邮 件 ” ) P ( “ 普 通 邮 件 ” ) +log\frac{P(“保真”|S)}{P(“保真”|H)}+log\frac{P(“增值税”|S)}{P(“增值税”|H)}+log\frac{P(“垃圾邮件”)}{P(“普通邮件”)} +logP(H)P(S)+logP(H)P(S)+logP()P()

五、N-gram 语言模型

  我们知道朴素贝叶斯的局限性来源于其条件独立假设,它将文本看成是词袋子模型,不考虑词语之间的顺序信息,就会把“武松打死了老虎”与“老虎打死了武松”认作是一个意思。那么有没有一种方法提高其对词语顺序的识别能力呢?有,就是这里要提到的N-gram语言模型。

前面我们根据条件独立假设得到:

P ( ( “ 我 ” , “ 司 ” , “ 可 ” , “ 办 理 ” , “ 正 规 发 票 ” , “ 保 真 ” , “ 增 值 税 ” , “ 发 票 ” , “ 点 数 ” , “ 优 惠 ” ) ∣ S ) = P ( " 我 " ∣ S ) × P ( “ 司 ” ∣ S ) × P ( “ 办 理 ” ∣ S ) × P ( “ 正 规 发 票 ” ∣ S ) × P ( “ 保 真 ” ∣ S ) × P ( “ 增 值 税 ” ∣ S ) × P ( “ 发 票 ” ∣ S ) × P ( “ 点 数 ” ∣ S ) × P ( “ 优 惠 ” ∣ S ) P\big((“我”,“司”,“可”,“办理”,“正规发票”,“保真”,“增值税”,“发票”,“点数”,“优惠”)|S\big)\\ =P("我"|S)\times P(“司”|S)\times P(“办理”|S)\times P(“正规发票”|S) \\ \times P(“保真”|S)\times P(“增值税”|S)\times P(“发票”|S)\times P(“点数”|S)\times P(“优惠”|S) P((,,,,,,,,,)S)=P(""S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)×P(S)

为了便于式子表达,这里用 x i x_i xi表示上式中每个词,如果我们去掉条件独立假设,就应该有如下式子:

P ( ( x 1 , x 2 , x 3 , x 4 , x 5 , x 6 , x 7 , x 8 , x 9 , x 10 ) ∣ S ) P((x_1,x_2,x_3,x_4,x_5,x_6,x_7,x_8,x_9,x_{10})|S) P((x1,x2,x3,x4,x5,x6,x7,x8,x9,x10)S)

= P ( x 1 ∣ S ) P ( x 2 ∣ x 1 , S ) P ( x 3 ∣ x 1 , x 2 , S ) P ( x 4 ∣ x 1 , x 2 , x 3 , S ) . . . P ( x 10 ∣ x 1 , . . . x 9 , S ) =P(x_1|S)P(x_2|x_1,S)P(x_3|x_1,x_2,S)P(x_4|x_1,x_2,x_3,S)...P(x_{10}|x_1,...x_9,S) =P(x1S)P(x2x1,S)P(x3x1,x2,S)P(x4x1,x2,x3,S)...P(x10x1,...x9,S)

满足联合概率链规则;上面的式子表示,每一个词都会受前面所有词语的影响,也即在前面词语的条件下的概率。

联合概率链规则我们便可以得到我们想要的N-gram 语言模型。

  上面的联合概率链规则公式考虑到词和词之间的依赖关系,但是比较复杂(每个词都与其前面的所有词有关),在实际生活中几乎没办法使用,于是我们就想了很多办法去近似这个公式,比如我们要讲到的语言模型n-gram就是它的一个简化。

  如果我们只考虑一个词语对上一个词语的依赖关系,公式就简化了如下形式,我们把它叫做二元语法(bigram,2-gram):

P ( ( x 1 , x 2 , x 3 , x 4 , x 5 , x 6 , x 7 , x 8 , x 9 , x 10 ) ∣ S ) P((x_1,x_2,x_3,x_4,x_5,x_6,x_7,x_8,x_9,x_{10})|S) P((x1,x2,x3,x4,x5,x6,x7,x8,x9,x10)S)

= P ( x 1 ∣ S ) P ( x 2 ∣ x 1 , S ) P ( x 3 ∣ x 2 , S ) P ( x 4 ∣ x 3 , S ) . . . P ( x 10 ∣ x 9 , S ) =P(x_1|S)P(x_2|x_1,S)P(x_3|x_2,S)P(x_4|x_3,S)...P(x_{10}|x_9,S) =P(x1S)P(x2x1,S)P(x3x2,S)P(x4x3,S)...P(x10x9,S)

如果把依赖词长度再拉长一点,考虑一个词对前两个词的依赖关系,就叫做三元语法(trigram,3-gram),公式如下:

P ( ( x 1 , x 2 , x 3 , x 4 , x 5 , x 6 , x 7 , x 8 , x 9 , x 10 ) ∣ S ) P((x_1,x_2,x_3,x_4,x_5,x_6,x_7,x_8,x_9,x_{10})|S) P((x1,x2,x3,x4,x5,x6,x7,x8,x9,x10)S)

= P ( x 1 ∣ S ) P ( x 2 ∣ x 1 , S ) P ( x 3 ∣ x 1 , x 2 , S ) P ( x 4 ∣ x 2 , x 3 , S ) . . . P ( x 10 ∣ x 8 , x 9 , S ) =P(x_1|S)P(x_2|x_1,S)P(x_3|x_1,x_2,S)P(x_4|x_2,x_3,S)...P(x_{10}|x_8,x_9,S) =P(x1S)P(x2x1,S)P(x3x1,x2,S)P(x4x2,x3,S)...P(x10x8,x9,S)

依次类推,便可以得到N-gram 语言模型。

其实以上几个简化后的公式,就是著名的马尔科夫假设(Markov Assumption):下一个词的出现仅依赖于它前面的一个或几个词。这相对于联合概率链规则,其实是一个有点粗糙的简化,不过很好地体现了就近思路,离得较远和关系比较弱的词语就被简化和省略了。实际应用中,这些简化后的n-gram语法比独立性假设还是强很多的。

  那么我们如何确定这个依赖词的个数n呢?选择依赖词的个数"n"主要与计算条件概率有关。理论上,只要有足够大的语料,n越大越好,毕竟这样考虑的信息更多嘛。条件概率很好算,统计一下各个元组出现的次数就可以,比如:

P ( “ 优 惠 ” ∣ “ 发 票 ” , “ 点 数 ” ) = ( “ 发 票 ” , “ 点 数 ” , “ 优 惠 ” ) 出 现 的 次 数 ( “ 发 票 ” , “ 点 数 ” ) 出 现 的 次 数 P(“优惠”|“发票”,“点数”) = \frac{(“发票”,“点数”,“优惠”)出现的次数}{(“发票”,“点数”)出现的次数} P(,)=(,)(,,)

  但我们实际情况往往是训练语料很有限,很容易产生数据稀疏,不满足大数定律,算出来的概率失真。比如(“发票”,“点数”,“优惠”)在训练集中竟没有出现,就会导致零概率问题。

  另一方面,如果n很大,参数空间过大,也无法实用。假设词表的大小为 100000 ,那么n-gram模型的参数数量为 10000 0 n 100000^n 100000n 。这么多的参数,估计内存就不够放了。

那么,如何选择依赖词的个数n呢?从前人的经验来看:

  • 经验上,trigram用的最多。尽管如此,原则上,能用bigram解决,绝不使用trigram。n取≥4的情况较少。
  • 更大的n:对下一个词出现的约束信息更多,具有更大的辨别力;
  • 更小的n:在训练语料库中出现的次数更多,具有更可靠的统计信息,具有更高的可靠性、实用性。

六、N-gram实际应用举例

6.1 词性标注

  词性标注是一个典型的多分类问题。常见的词性包括名词、动词、形容词、副词等。而一个词可能属于多种词性。如“爱”,可能是动词,可能是形容词,也可能是名词。但是一般来说,“爱”作为动词还是比较常见的。所以统一给“爱”分配为动词准确率也还足够高。这种最简单粗暴的思想非常好实现,如果准确率要求不高则也比较常用。它只需要基于词性标注语料库做一个统计就够了,连贝叶斯方法、最大似然法都不要用。词性标注语料库一般是由专业人员搜集好了的。

需要比较以下各概率的大小,选择概率最大的词性即可:

P ( 词 性 i ∣ “ 爱 ” ) = “ 爱 ” 作 为 “ 词 性 i ” 的 次 数 “ 爱 ” 出 现 的 次 数 , i = 1 , 2 , 3 , . . . . P(词性_i|“爱”) = \frac{“爱”作为“词性_i”的次数}{“爱”出现的次数},i = 1, 2, 3,.... P(i)=ii=1,2,3,....

  但这种方法没有考虑上下文的信息。而一般来说,形容词后面接名词居多,而不接动词,副词后面才接动词,而不接名词。 考虑到词性会受前面一两个词的词性的影响,可以引入2-gram模型提升匹配的精确度。 我们匹配以下这句话(已被空格分好词)中“爱”的词性:

“闷骚的 李雷 很 爱 韩梅梅”

将公式进行以下改造,比较各概率的大小,选择概率最大的词性:

P ( 词 性 i ∣ “ 很 ” 的 词 性 ( 副 词 ) , “ 爱 " ) = 前 面 被 副 词 修 饰 的 “ 爱 ” 作 为 “ 词 性 i ” 的 次 数 前 面 被 副 词 修 饰 的 “ 爱 ” 出 现 的 次 数 , i = 1 , 2 , 3 , . . . P(词性i|“很”的词性(副词),“爱") = \frac{前面被副词修饰的“爱”作为“词性_i”的次数}{前面被副词修饰的“爱”出现的次数} , i =1 ,2,3,... P(i")=ii=1,2,3,...

计算这个概率需要对语料库进行统计。但前提是你得先判断好“很”的词性,因为采用2-gram模型,进而就需要提前判断“李雷”的词性,需要判断“闷骚的”词性。但是“闷骚的”作为第一个词语,已经找不比它更靠前的词语了。这时就可以考虑用之前最简单粗暴的方法判断“闷骚的”的词性,统一判断为形容词即可。

6.2 垃圾邮件识别

  用N-gram进行垃圾邮件识别,是朴素贝叶斯方法的进化版。下面我们用直观的例子探讨一下其在分类问题上是怎么发挥作用的。一个可行的思路如下:

  • 先对邮件文本进行断句,以句尾标点符号(“。” “!” “?”等)为分隔符将邮件内容拆分成不同的句子。
  • N-gram分类器判断每个句子是否为垃圾邮件中的敏感句子。
  • 当被判断为敏感句子的数量超过一定数量(比如3个)的时候,认为整个邮件就是垃圾邮件。

其中N-gram分类器是结合贝叶斯方法和语言模型的分类器。这里用 Y1,Y2 分别表示这垃圾邮件和正常邮件,用 X 表示被判断的邮件的句子。根据贝叶斯公式有:

P ( Y i ∣ X ) ∝ P ( X ∣ Y i ) P ( Y i ) , i = 1 , 2 P(Y_i|X)\propto P(X|Y_i)P(Y_i) ,i=1,2 P(YiX)P(XYi)P(Yi)i=1,2

比较i=1和2时两个概率值的大小即可得到 X 所属的分类。

对于句子(“我”,“司”,“可”,“办理”,“正规发票”,“保真”,“增值税”,“发票”,“点数”,“优惠”)用字母 X X X 代表,每一个词语用字母 x i x_i xi表示。 X X X 就可以写成一个 x i x_i xi组成的向量, x i x_i xi 就是这向量中某个维度的特征。对 P ( X ∣ Y i ) P(X|Y_i) P(XYi) 套用2-gram模型。 则上式化简为:

P ( Y i ∣ X ) ∝ P ( X ∣ Y i ) P ( Y i ) , i = 1 , 2 ∝ P ( x 1 ∣ Y i ) P ( x 2 ∣ x 1 , Y i ) P ( x 3 ∣ x 2 , Y i ) . . . P ( x 10 ∣ x 9 , Y i ) P ( Y i ) P(Y_i|X)\propto P(X|Y_i)P(Y_i) ,i=1,2 \propto P(x_1|Y_i)P(x_2|x_1,Y_i)P(x_3|x_2,Y_i)...P(x_{10}|x_9,Y_i)P(Y_i) P(YiX)P(XYi)P(Yi)i=1,2P(x1Yi)P(x2x1Yi)P(x3x2Yi)...P(x10x9Yi)P(Yi)
∝ P ( “ 我 ” ∣ Y i ) P ( “ 司 ” ∣ “ 我 ” , Y i ) P ( “ 可 ” ∣ “ 司 ” , Y i ) . . . P ( “ 优 惠 ” ∣ “ 点 数 ” , Y i ) P ( Y i ) \propto P(“我”|Y_i)P(“司”|“我”,Y_i)P(“可”|“司”,Y_i)...P(“优惠”|“点数”,Y_i)P(Y_i) P(Yi)P(Yi)P(Yi)...P(Yi)P(Yi)

公式中的条件概率也比较好求,举个例子:

P ( “ 优 惠 ” ∣ “ 点 数 ” , Y i ) = 在 类 别 Y i 中 , ( “ 点 数 ” , “ 优 惠 ” ) 出 现 的 次 数 在 类 别 Y i 中 , “ 点 数 ” 出 现 的 次 数 P(“优惠”|“点数”,Y_i)=\frac{在类别Y_i中,(“点数”,“优惠”)出现的次数}{在类别Y_i中,“点数”出现的次数} P(Yi)=YiYi()

剩下的就需要在语料库中间做一个的统计就是了。因为这种方法考虑到了词语前面的一个词语的信息,同时也考虑到了部分语序信息,因此区分效果会比单纯用朴素贝叶斯方法更好。

此外,N-gram模型还可以用于中文分词、机器翻译与语言识别等,感兴趣的可以进一步研究。

七、总结

  长篇大幅说了这么多,想必大家已经不知道看了些啥,我们再来总结下:

  • 首先,我们介绍了贝叶斯公式(贝叶斯定理),这是基础公式;
  • 其次,从机器学习分类问题的角度来看,我们知道在现实任务中我们通常难以直接获得后验概率,于是我们便将后验概率 P ( “ 属 于 某 类 ” ∣ “ 具 有 某 特 征 ” ) P(“属于某类”|“具有某特征”) P()通过贝叶斯公式转换为 P ( “ 具 有 某 特 征 ” ∣ “ 属 于 某 类 ” ) P(“具有某特征”|“属于某类”) P(),而后者获取方法就简单多了,我们只需要找到一些包含已知特征标签的样本,即可进行训练;
  • 后来,我们发现对于根据一个句子做分类比较麻烦,于是便用到了分词方法,由词语进行建模,并通过垃圾邮件做了例子说明;
  • 然而,我们发现基于贝叶斯公式来估计后验概率 P ( “ 垃 圾 邮 件 ” ∣ “ 具 有 某 特 征 ” ) P\big(“垃圾邮件”|“具有某特征”\big) P() 也不好求,因为条件概率 P ( “ 具 有 某 特 征 ” ∣ “ 垃 圾 邮 件 ” ) P\big(“具有某特征”|“垃圾邮件”\big) P()是所有属性上的联合概率,难以从有限的训练数据集中直接估计而得;于是并提出了条件独立假设,谈到了朴素贝叶斯方法,并成功解决了垃圾邮件分类问题;
  • 接着,我们提了一些实际工程中可能会用到的一些小技巧,平滑处理(贝叶斯估计)等,此部分不够完善,需要大量的实践,从实践中发现;
  • 最后,我们知道朴素贝叶斯方法没有考虑词与词之间的关系(顺序)问题,谈到了N-gram 语言模型,并提到了N-gram 语言模型在词性标注、垃圾邮件分类上的应用。

你可能感兴趣的:(NLP)