朴素贝叶斯理论
贝叶斯定理
理解贝叶斯定理需要整清楚两个概念:一个是联合概率p(X=x,Y=y),也就是X=x,Y=y的概率;另一个是条件概率p(Y=y/X=x),也就是在X=x的情况下,变量Y=y的概念。再看看联合概率和条件概率的关系:
p(A,B) = p(A) x p(B/A) = p(B) x p(A/B)
调整一下,得到下面的表达式,称为贝叶斯定理:
在文本分类中,A可以作为文本的类别,B表示一个文本,条件概念p(A/B)表示文本B属于A的概率。p(A)表示类别A的先验概率,p(B)表示文本B的先验概率,p(B/A)表示文本B的后验概率。
举一个小案例,
有房 | 婚姻状况 | 年收入 | 拖欠贷款 |
---|---|---|---|
是 | 单身 | 125K | 否 |
否 | 已婚 | 120K | 否 |
是 | 单身 | 70K | 否 |
否 | 离异 | 95K | 是 |
否 | 单身 | 90K | 是 |
否 | 单身 | 85K | 是 |
否 | 已婚 | 75K | 否 |
类别有两个:是拖欠贷款和否拖欠贷款,我们可以用A0和A1表示,B表示某一个人,B1,B2, B3表示这个人上面的三个属性:有房,婚姻状况和年收入。P(A0/B),P(A1/B)分别表示B属于A0和A1的条件概率,容易想到哪个概率大,B就属于哪个分类。
其实我们要计算两次这个公式:p(A0/B)和(A1/B),然后比较大小。
对于p(A0/B)和(A1/B),只需要比较大小就可以,所以对于分母都是p(B1,B2,B3),可以不用计算了。只需要比较p(A0)p(B1,B2,B3/A0)和p(A1)p(B1,B2,B3/A1)的大小。p(A0)和P(A1)很好算,就是A0和A1所占比率,上面表p(拖欠贷款=是)=
37
,p(拖欠贷款=否)=
47
。
现在主要问题就是计算p(B1,B2,B3/A),也就是本章的重点:朴素贝叶斯。
朴素贝叶斯
朴素贝叶斯在估计类条件概率时假设属性之间条件独立,可以形式化的理解为: p(B1,B2,B3/A)=p(B1/A)×p(B2/A)×p(B3/A)
条件独立性
先了解一下条件独立的概念,设有X,Y,Z三个变量,对于给定Z,X条件独立于Y,
p(X/Y,Z)=p(X/Z)
处理到这,是不是觉得朴素贝叶斯属性之间条件独立的假设让问题处理变得简单很多,当然简化处理也带来一些问题,因为我们知道朴素贝叶斯的属性条件独立的假设在实际中是不存在的,为了解决这一问题,有人提出了贝叶斯信念网络。在这里先不多说了,继续我们朴素贝叶斯,虽然其假设前提不准确,但在大样本的训练集下,其分类效果是非常好的,而且处理过程也比较简单。
连续性属性
前面提到的属性主要还是指离散性属性,那么对于连续性属性,我们应该如何处理,使得我们的朴素贝叶斯模型依然通行。主要有两种处理方法:
(1)连续属性离散化
(2)假设连续变量服从某种概率分布
高斯分布通常被用来表示连续属性的类条件概率分布:
该分布有两个参数u和 σ2 ,参数 uij 可以用类与 yi 所有训练集中 Xi 的样本均值E xi , σ2ij 可以用这些训练样本方差 s2 来估计。
m估计
p(B1,B2,B3/A)=p(B1/A)×p(B2/A)×p(B3/A)
存在一个潜在问题,如果有一个属性的类条件概率等于0,则整个类的后验概率就等于0。为了消除这种影响,使用m估计。
条件概率:
n为类 yi 实例总数, nc 为取值 xi 的样例数,m称为等价样本大小,p为类 yi 记录中 xi 的先验概率。
二项独立模型
二项独立模型是朴素贝叶斯最常见的实现模型,二项独立模型使用二值向量来表示文档, wi =1表示单词出现, wi =0表示单词没有出现。文本就可以表示为 Vi =(1,0,1,0,1,10,0,0,0,0,1)这种形式,用下面的例子来说明一下。
def loadDataSet():
postingList =[['my','dog','has','flea','problems','help','please'],
['maybe','not','take','him','to','dog','park','stupid'],
['my','dalmation','is','so','cute','I','love','him'],
['stop','posting','stupid','worthless','garbage'],
['mr','licks','ate','my','steak','how','to','stop','him'],
['quit','buying','worthless','dog','food','stupid']]
classVec = [0,1,0,1,0,1]
return postingList,classVec
显然我们需要先建立一个词库
def createVocabList(dataSet):
vocabSet = set([])
for document in dataSet:
vocabSet=vocabSet|set(document)
return list(vocabSet)
词库建好之后,就是将文本进行二值向量来表示了
def setOfWords2Vec(vocabList,inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else: print"the word :%s is not in my Vocabulary!"% word
return returnVec
接下来就是计算类先验概率和属性的类条件概率,也就是计算p(Y= yi )以及p( Xi=1 / yi )和p( Xi=0 / yi ),结合在一起就是下面公式:
def trainNBO(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
p0Num = ones(numWords);p1Num = ones(numWords)
p0Denom = 2.0; p1Denom = 2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += 1
else :
p0Num += trainMatrix[i]
p0Denom += 1
p1Vect = log(p1Num/p1Denom)
p0Vect = log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive
最后就是计算文本类别了,这里取了对数,方便计算。
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1 = sum(vec2Classify * p1Vec) + log(pClass1)
p0 = sum(vec2Classify * p0Vec) + log(1.0-pClass1)
if p1 > p0:
return 1
else :
return 0
多项式模型
文档
di=(t1,t2,...,tk)
,
ti
表示第i个单词出现的次数。
∑ti 表示在类别 yi 的所有文档中单词i出现的次数
∑t 表示来类别 yi 的所有文档中出现的单词总数