任务描述
本关任务:根据本关所学有关朴素贝叶斯的知识,编写基于朴素贝叶斯理论进行文本分类的程序,并通过所有测试用例。
相关知识
为了完成本关任务,你需要掌握:
-
贝叶斯决策理论思想;
-
朴素贝叶斯分类器的实现。
贝叶斯决策理论
在学习朴素贝叶斯分类之前,我们先回顾一下贝叶斯决策理论和条件概率。贝叶斯决策理论的核心思想是选择最高概率对应的类别,也就是选择具有最高概率的决策。贝叶斯准则是计算条件概率的有效方法,可以告诉我们如何交换条件概率中的条件与结果,即如果已知P(X∣C),要求P(C∣X),那么就可以使用下面的计算方法: P(Ci∣X)=P(X)P(X∣Ci)P(Ci)
假设我们有一个二维数据集,由两类数据组成,现在我们结合贝叶斯决策理论使用条件概率来给这些数据点分类。即给定数据点(x,y),判断是属于类别1还是类别2的方法是,分别计算该数据点来自类别1和来自类别2的概率。所以真正需要比较的是P(C1∣x,y)和P(C2∣x,y)。若已知从给定类别中取出该数据的概率,即P(x,y∣Ci),应用贝叶斯准则可以得到: P(Ci)=P(x,y)P(x,y∣Ci)
当P(C1∣x,y)>P(C2∣x,y),那么属于类别1; 当P(C2∣x,y)>P(C1∣x,y),那么属于类别2;
以上是贝叶斯准则的简要理论,我们在对文档进行分的类常用算法朴素贝叶斯分类- 器中“朴素”一词基于两个假设:
- 特征之间相互独立,在上述二维数据中的体现就是 x 与 y 相互独立;
- 每个特征同等重要。即 x 与 y 有同样的重要性。
在应用于文档分类时,尽管很多情况下特征难以完全符合上述假设,但朴素贝叶斯的实际效果却很好。接下来我们将介绍如何使用朴素贝叶斯理论进行文本分类。
朴素贝叶斯分类器的实现
在文档分类中,整个文档(如一封电子邮件)是实例,文档中的某些元素构成特征。我们把每个词的出现或不出现作为一个特征。整个文本分类的过程分为三步:
-
拆分文本,获取特征。在英文文档分类中,特征来自文本的词条(token),一个词条可以是单词,也可以是 URL、IP 地址等任意其他字符串;
-
将文本数字化,构建词向量。每一个文本片段表示为一个词条向量,其中值为1表示词条出现在文档中,0表示词条未出现;
-
计算条件概率并分类。应用朴素贝叶斯分类原理,通过词向量计算条件概率。这里w是一个向量,由多个数值组成,它代表着由多个单词组成的一段文本或者一组单词。
基于朴素贝叶斯理论进行文本分类的具体实现: 1、准备数据,从文本中构建词向量 先将所有文档中出现过的词构建词汇表,然后把每篇文档中的词转换成词汇表上的向量。
def setofWords2Vec(vocabList,inputSet): # 将每个文档转换成词向量
returnVec=[0]*len(vocabList) # 创建一个与词汇表等长且所有元素都为0的向量
for word in inputSet: # 遍历文档
if word in vocabList: # 若文档中出现词表中的词
returnVec[vocabList.index(word)]=1 # 则文档向量中的对应值设为1
else:
print ("the word: %s is not in my Vocabulary!" % word)
return returnVec # 得到的与词汇表同等长度的词向量
2、从词向量计算概率 要得到类别概率值,首先需要计算P(W∣Ci)和P(Ci)。P(Ci)容易获得,用文档数除以总文档数即可,再计算P(W∣Ci)。朴素贝叶斯中假设特征相互独立,这里体现为每个词条相互独立。将P(W∣Ci)展开成P(W0,W1,W2,...,Wn∣Ci),根据假设: P(W0,W1,W2,...,Wn∣Ci)=P(W0∣Ci)P(W1∣Ci)P(W2∣Ci)...P(Wn∣Ci) 我们可以计算上述概率,参考代码如下:
for i in range(numTrainDocs):
if trainCategory[i]==1: #如果是负面文档
p1Num+=trainMatrix[i] #文档对应的词语数量全部加1,向量相加
p1Denom+=sum(trainMatrix[i]) #负面文档词语的总数量
else:
p0Num+=trainMatrix[i] #正常文档对应的词语数量向量
p0Denom+=sum(trainMatrix[i]) #正常文档词语的总数量
p1Vect=p1Num/p1Denom
p0Vect=p0Num/p0Denom
3、进行分类 准备好概率向量和文档概率后,按照贝叶斯准则公式将上述概率进行计算,得到朴素贝叶斯分类函数从而进行分类。参考代码如下:
#计算各概率向量的乘积
if len(p0Cond): # 若p0Cond不为空,即p0VectClassify不全为0
pC0=reduce(operator.mul, p0Cond, 1) # 计算概率向量内元素乘积
else:
pC0=0
if len(p1Cond): # 计算概率
pC1=reduce(operator.mul, p1Cond, 1)
else:
pC1=0
p1=pC1*pAb
p0=pC0*(1.0-pAb)
if p1 > p0: # 基于朴素贝叶斯理论进行概率比较
return 1
else:
return 0
编程要求
在右侧编辑器中的 Begin-End 之间补充 Python 代码,完成基于朴素贝叶斯对所输入文本进行文本分类,并输出文本分类结果。其中文本内容通过 input 从后台获取。
测试说明
平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。
测试输入:
has flea
maybe not take him
预期输出:
分类结果为: # 由人工标注的文本类别,0代表负面文字,1代表普通文字
['has', 'flea']: 0
['maybe', 'not', 'take', 'him']: 1
参考代码:
from functools import reduce
import operator
from numpy import array, zeros
def trainNB(trainMatrix, trainCategory):
numTrainDocs = len(trainMatrix) # 文档数量
numWords = len(trainMatrix[0]) # 第一篇文档的长度,也就是词汇表的长度
pAbusive = sum(trainCategory) / float(numTrainDocs) # 负面文档占总文档比例
p0Num = zeros(numWords) # 初始化概率
p1Num = zeros(numWords)
p0Denom = 0
p1Denom = 0
for i in range(numTrainDocs):
if trainCategory[i] == 1: # 如果是负面文档
p1Num += trainMatrix[i] # 文档对应的词语数量全部加1,向量相加
p1Denom += sum(trainMatrix[i]) # 负面文档词语的总数量
else:
p0Num += trainMatrix[i] # 正常文档对应的词语数量向量
p0Denom += sum(trainMatrix[i]) # 正常文档词语的总数量
p1Vect = p1Num / p1Denom # 对p1Num的每个元素做除法,即负面文档中出现每个词语的概率
p0Vect = p0Num / p0Denom # 对p0Num的每个元素做除法,即正常文档中出现每个词语的概率
return p0Vect, p1Vect, pAbusive
def classifyNB(vec2Classify, trainMatrix, trainCategory):
p0Vect, p1Vect, pAb = trainNB(trainMatrix, trainCategory)
# 计算待分类文档词条对应的条件概率
p1VectClassify = vec2Classify * p1Vect
p0VectClassify = vec2Classify * p0Vect
p1Cond = [];
p0Cond = []
for i in range(len(p1VectClassify)):
if p1VectClassify[i] == 0:
continue
else:
p1Cond.append(p1VectClassify[i])
for i in range(len(p0VectClassify)):
if p0VectClassify[i] == 0:
continue
else:
p0Cond.append(p0VectClassify[i])
# 任务:完成对各概率向量的计算
# ********** Begin *********#
if len(p0Cond): # 若p0Cond不为空,即p0VectClassify不全为0
pC0=reduce(operator.mul, p0Cond, 1) # 计算概率向量内元素乘积
else:
pC0=0
if len(p1Cond): # 计算概率
pC1=reduce(operator.mul, p1Cond, 1)
else:
pC1=0
p1=pC1*pAb
p0=pC0*(1.0-pAb)
# ********** End **********#
if p1 > p0:
return 1
else:
return 0