您的位置:首页 > 编程语言 > Python开发

使用朴素贝叶斯分类器进行文档分类

2017-03-04 22:36 281 查看
朴素贝叶斯分类器
基本方法

后验概率最大化的含义

朴素贝叶斯法参数估计
极大似然估计

贝叶斯估计

朴素贝叶斯的一般过程

实战进行文档分类

参考文献

朴素贝叶斯分类器

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练数据集,首先基于特征条件独立假设学习输入/输出的联合概率分布;然后基于此模型,对于给定的输入x,利用贝叶斯定理求出后验概率最大的y。之所以称其为“朴素”,就是因为做出了特征条件独立的假设。

优点: 在数据较少的情况下仍然有效,可以处理多类别问题

缺点: 对于输入数据的准备方式较为敏感

适用数据类型: 标称型数据

基本方法

假定训练数据集

T={(x1,y1),(x2,y2),...,(xn,yn)}

是由P(X,Y) 独立同分布产生。

朴素贝叶斯法通过训练数据集学习联合概率分布P(X,Y) 。具体地,学习以下先验概率分布和条件概率分布,先验概率分布

P(Y=ck),k=1,2,...,K

条件概率分布

P(X=x|Y=ck)=P(X(1),...,X(n)=x(n)|Y=ck),k=1,2,,...,K

于是学习到联合概率分布P(X,Y).

P(X,Y)=P(X=x|Y=ck)⋅P(Y=ck)

条件概率分布有指数级数量的参数,起估计实际是不可行的。x(j) 可能取值Sj 个,j = 1,2,…,n,Y的可能取值有K个,那么参数个数为K∏nj=1Sj,这意味着维度灾难。

朴素贝叶斯法对条件概率分布作了条件独立性的假设,由于这是一个较强的假设,朴素贝叶斯法也由其得名。具体地,条件独立性假设是

P(X=x|Y=ck)=P(x(1)=x(1),...,X(n)=x(n)|Y=ck)=∏j=1nP(X(j)=x(j)|Y=ck)

朴素贝叶斯法实际上学习到生成数据的机制,所以属于生成模型,条件独立性交涉使朴素贝叶斯法变得简单,但有时会牺牲一定的分类准确性。比如在作自然语言处理时,两个词之间往往存在这很大的关联性,“我”之后经常跟谓语。但是从实际使用上来看,朴素贝叶斯分类器的效果往往不错。

朴素贝叶斯法分类,通过学习到的模型计算后验概率分布P(Y=ck|X=x), 将后验概率最大的类作为x的类输出。后验概率根据贝叶斯定理进行:

P(Y=ck|X=x)=P(X=x|Y=ck)P(Y=ck)∑kP(X=x|Y=ck)P(Y=ck)=P(Y=ck)∏jP(X(j)=x(j)|Y=ck)∑kP(Y=ck)∏jP(X(j)=x(j)|Y=ck)

这时朴素贝叶斯法分类的基本公式。于是,朴素贝叶斯分类器可以表示为

y=f(x)=argmaxckP(Y=ck)∏jP(X(j)=x(j)|Y=ck)∑kP(Y=ck)∏jP(X(j)=x(j)|Y=ck)

由于上式分母对于所有的ck 都是一样的,所以,分母在实际计算的时候可以省略。

后验概率最大化的含义

朴素贝叶斯法将实例分到后验概率最大的类中,这等价于期望风险最小化。具体证明请参阅《统计机器学习》

朴素贝叶斯法参数估计

在朴素贝叶斯法中,学习意味着估计P(Y=ck) 和$P(X^{(j)} = x^{(j)} | Y = c_k). 可以应用极大似然估计法估计相应的概率,也可以采用贝叶斯估计。后者较为常用,原因下边会叙述。

极大似然估计

P(Y=ck)=∑Ni=1I(yi=ck)N,k=1,2,...,K

设第j个特征x(j) 可能取值为{aj1,aj2,...,ajSj}, 条件概率的极大似然估计为

P(X(j)=ajl|Y=ck)=∑Ni=1I(x(j)i=ajl,yi=ck)∑Ni=1I(yi=ck)

j=1,2,...,n;l=1,2,...,Sj;,k=1,2,...,K

贝叶斯估计

用朴素贝叶斯法需要计算多个概率连乘以获得条件概率,但是用极大似然估计可能会出现其中一个概率为零的情况,比如当某一个特征的某一种取值在训练数据集中缺失时就会出现这种情况。解决这一问题的方法是采用贝叶斯估计。具体地,条件概率的贝叶斯估计是

Pλ(X(j)=ajl|Y=ck)=∑Ni=1I(x(j)i=ajl,yi=ck)+λ∑Ni=1I(yi=ck)+Sjλ

式中λ≥0.等价于在随机变量的各个取值的频数上赋予一个正数,当λ=0 时,就是极大似然估计。常取λ=1,这时称为拉普拉斯平滑。显然,对于任何l=1,2,...,Sj,k=1,2,,...,K,有

Pλ(X(j)=ajl|Y=ck)>0

∑l=1SjPλ(X(j)=ajl|Y=ck)

表明贝叶斯估计的结果确实是一种概率分布。同样的先验概率的贝叶斯估计为

Pλ(Y=ck)=∑Ni=1I(Yi=Ck)+λN+Kλ

朴素贝叶斯的一般过程

收集数据: 可以使用任何方法。

准备数据: 需要数值型或布尔型数据

分析数据:有大量特征时,绘制特征作用不大,此时使用直方图效果更好

训练算法:计算不同的独立特征的条件概率,类的先验概率

测试算法:计算后验概率,计算错误率

使用算法:一个常见的朴素贝叶斯分类器应用是文本分类。可以在任意的分类场景中和使用朴素贝叶斯分类器,不一定非要是文本。

朴素贝叶斯算法多用来处理离散性数据,在遭遇连续型数据时可以采用高斯分布和核密度估计等诸多方法。

实战:进行文档分类

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

#################################################
# 建立朴素贝叶斯模型用以进行文本分类
# BlueCitizen  2017/3/4
#################################################

#import matplotlib.pyplot as plt
import numpy as np

#import os

#my_dir = os.path.dirname(__file__)
#pic_name = 'NativeBayes.jpg'

#model_flag = 1 # vocabulary bag model, 0 reprensting vocabulary set model

##########################################
# Bayes Start
##########################################
class Bayes(object):
def __init__(self, model_flag = 0):
self.vocabList = [] ##vocabulary(use hash algorithm to optimize searching)
self.classLabel = []
self.condProb = dict() ##conditional probability {label : pVoca--list}
self.priorProb = dict() ##prior probability {label : pClass}
self.model_flag = model_flag

# Create a vocabulary list according to the dataset(no repeat element)
def createVocabList(self,dataset):
vocabSet = set([])
for entry in dataset:
vocabSet = vocabSet | set(entry)
self.vocabList = list(vocabSet)

# Transfer the document to vocabulary vector according to vocabulary set model,
# that means what we record is whether the word appears not the appearance frequency
def setOfDoc2Vec(self,inputDoc):
returnVec = [0] * len(self.vocabList)
for word in inputDoc:
if word in self.vocabList:
returnVec[self.vocabList.index(word)] = 1
return returnVec

# Transfer the document to vocabulary vector according to vocabulary bag model,
# that means what we record is the words' appearance frequency in a document
def bagOfDoc2Vec(self,inputDoc):
returnVec = [0] * len(self.vocabList)
for word in inputDoc:
if word in self.vocabList:
returnVec[self.vocabList.index(word)] = 1
return returnVec

# Transfer the document list to vocabulary array
def createVocabMatrix(self,dataset):
vocabMatrix = []
if self.model_flag:
for item in dataset:
vocabMatrix.append(self.bagOfDoc2Vec(item))
else:
for item in dataset:
vocabMatrix.append(self.setOfDoc2Vec(item));
return np.array(vocabMatrix)

def train(self, dataset, classLabels):

self.createVocabList(dataset)
trainMatrix = self.createVocabMatrix(dataset)# transfer the document to vocabulary vector

numDocs = len(classLabels)
vocabTotalNum = dict() # total vocabularies's amount of each class{label: vocab total amount}
numClasses = dict() # amount of each class's document{label: count}
vocabFreq = dict() # the vocabulary's frequency {label: vocab count array}
for i in range(numDocs):
if classLabels[i] not in self.classLabel:
self.classLabel.append(classLabels[i])
vocabTotalNum[classLabels[i]] = 2 #laplace smoothing
numClasses[classLabels[i]] = 0
vocabFreq[classLabels[i]] = np.ones(len(self.vocabList))#laplace smoothing
numClasses[classLabels[i]] += 1
vocabFreq[classLabels[i]] += trainMatrix[i]
vocabTotalNum[classLabels[i]] += sum(trainMatrix[i])

for classLabel in self.classLabel:# calculate the conditional probability and prior probability
self.condProb[classLabel] = np.log(vocabFreq[classLabel] / vocabTotalNum[classLabel])
self.priorProb[classLabel] = np.log(numClasses[classLabel] / numDocs)

def classify(self, dataset):
mat2classify = self.createVocabMatrix(dataset)
result = []

for entry in mat2classify:
pClass = {}
for label in self.classLabel:
pClass[label] = sum(entry * self.condProb[label]) + self.priorProb[label]
result.append(max(pClass, key=lambda label: pClass[label]))

return result
##########################################
# Bayes End
##########################################

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] # 1 reprensting the abusive comments, 0 reprensting normal comments
return postingList, classVec

if __name__ == "__main__":

listPosts, listClasses = loadDataSet()
bayes = Bayes()

bayes.train(listPosts,listClasses)
print(bayes.condProb)

testEntry = [['stop','him','dalmation'],
['stupid','love']]
print(bayes.classify(testEntry))


程序输出

[0,1]


可见,对于即使含有
love
也还是会对含有
stupid
的句子输出侮辱性的语句判断。

参考文献

[1] 《统计机器学习》 李航

[2] 《机器学习实战》Peter Harrington
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息