文章目录
实验背景
朴素贝叶斯算法是用于分类问题的一种算法,该算法属于生成式模型,与其他算法的判别式模型不同。比如一封电子邮件是不是垃圾邮件,判别式模型是判断这封邮件是某种类型的概率,生成式模型是某种类型生成这封邮件的概率。
判别式模型:
生成式模型:
以判断电子邮件是否垃圾为例,如果采用判别式模型来判断,那么对于这个二分类(是垃圾,不是垃圾)问题来说,如果是垃圾邮件的可能性只有10%,那么根据简单的非A即B,这个邮件大概率不是垃圾邮件。但是如果这封邮件是一种全新的垃圾邮件,我们之前没有见过,那么这个分类就是错误的。生成式模型则不同,一封全新的垃圾邮件,如果是垃圾邮件的概率为10%,不是垃圾邮件的概率只有5%,那么很显然,这封邮件就是垃圾邮件。
1.算法原理
1.1.贝叶斯公式
已知两个独立事件A和B,事件B发生的前提下,事件A发生的概率可以表示为P(A|B),即上图中橙色部分占红色部分的比例,即:
其中P(A)为先验概率,通过训练数据集得出,比如10封邮件,里面有3封垃圾邮件和7封正常邮件,那么假设A代表垃圾邮件,P(A)就为30%。P(A|B)为后验概率,也就给定一封邮件B,判断是否为垃圾邮件的概率。P(B)为这封邮件在所有邮件中出现的概率,这个概率与我们判断是否为垃圾邮件无关,我们可以不去考虑,即
那么核心问题转化为求P(B|A),即垃圾邮件产生邮件B的概率,很显然P(B|A)是个联合分布概率,邮件B里有很多个单词,这些单词共同决定B是否为一封垃圾邮件。
1.1.2.朴素贝叶斯
很显然,如果我们要找到单词之间的关联需要大量的数据支持,为了减少数据量,我们认为单词之间是没有联系的,每个单词单独分布,由这些单词概率之积来决定联合概率,这就是朴素贝叶斯算法。
扩展到其他分类问题上,意味着属性条件独立分布,即每个属性独立地对分类结果发生影响。
假设分类结果为c,x为实例,那么可以将贝叶斯公式表达为:
其中d为属性数目,xi为 x 在第i个属性上的取值
举个例子:
那么对于这么一个样例x
他是否能够Play Tennis呢
首先我们统计下每个属性出现的次数。然后将其转换为概率。
对于YES和NO的概率来说,因为分母都是P(X),所以我们只需比较分子的大小,也就是说
因为NO的概率 比YES的概率大,所以我们把这个样本x分类为NO
1.1.3.拉普拉斯修正
有细心的朋友会发现,对于outlook属性中,overcast只在yes的样本中出现过,那么一个新的带有overcast属性的样本x,因为p(Overcast|NO)=0的关系,分类为NO的概率一定为0,也就是说只要新的样本x带有overcast属性,那么就一定会被分类为YES。这就是过拟合现象,过度地适应训练数据,不符合现实应用。
因此,我们采取最简单的修正方法,也就是拉普拉斯提出的加1法,即每个类别的属性数量都加上1,总数再加上类别的数量。
2.代码解析
2.1.防溢出策略
对于计算机来说因为属性数量的增多,属性概率过小,所以很可能会出现累乘结果下溢出的现象,而在代数中有ln(a*b)=ln(a)+ ln(b),因此我们可以把条件概率累乘转换为对数累加。这并不影响结果的判断。
2.2.词袋模型
一般来说,对于涉及文本的数据类型,我们都会选择词袋模型。
顾名思义,我们将一段话中的每个单词单独提取出来,统计每个单词出现的次数,因为只统计出现过的单词,所以最小值为1,同样,将统计完成的数据转化成概率后对其进行判断。还有一种模型叫词集模型,只统计单词是否出现,很显然,不同单词的出现频率很大程度上决定一封邮件是否为垃圾邮件,所以本次实验我们抛弃了这种模型。
2.3.垃圾邮件分类
from numpy import *
import re
#切割文本,将非单个字母的单词转换成小写字母
def textParse(bigString):
listOfTokens = re.split(r'\W+', bigString)
return [tok.lower() for tok in listOfTokens if