4.1 基于贝叶斯决策理论的分类方法
优点:在数据较少的情况下仍然有效,可以处理多类别问题。
缺点:对于输入数据的准备方式较为敏感。
适用数据类型:标称型数据。
贝叶斯决策理论
朴素贝叶斯是贝叶斯决策理论的一部分,所以讲述朴素贝叶斯之前有必要快速了解一下贝叶斯决策理论。
贝叶斯决策理论的核心思想,即选择具有最高概率的决策。
如果p1>p2(1,2为两个类别),那么类别为1.
4.2 条件概率
条件概率==p(a|b)==表示在事件b发生的条件下a发生的概率。
p(a|b)=p(ab)/p(b)
而 p(ab)=p(b|a)p(a)
4.3 使用条件概率来分类
分类准则:
比较P(c1|x, y) 与 P(c2|x, y) 的大小,认为结果属于概率大的类别。P(c1|x, y)表示给定某个由x、y表示的数据点,那么该数据点来自类别c1的概率。
4.4 使用朴素贝叶斯进行文档分类
朴素贝叶斯是贝叶斯分类器的一个扩展,是用于文档分类的常用算法。
两个假设:(1)朴素:特征之间相互独立
(2)每个特征同等重要
朴素贝叶斯分类器通常有两种实现方式:一种基于贝努利模型实现,一种基于多项式模型实现。这里采用前一种实现方式。该实现方式中并不考虑词在文档中出现的次数,只考虑出不出现,因此在这个意义上相当于假设词是等权重的。
4.5 使用 Python 进行文本分类
4.5.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','grabage'],
['mr','licks','ate','my','steak','how',\
'to','stop','him'],
['quit','buying','worthless','dog','food','stupid']]
classVec=[0,1,0,1,0,1] #1代表侮辱性文字(stupid)
return postingList,classVec
#创建包含文档中所有单词(不重复)列表
def createVocabList(dataSet):
vocabSet=set([]) #创造一个空集合
for document in dataSet:
vocabSet=vocabSet | set(document) #集合并运算
return list(vocabSet)
#把单词列表转换为文档向量
def setOfWorld2Vec(vocabList,inputSet):
returnVec=[0]*len(vocabList) #创建对应的向量
for word in inputSet: # word 为目标单词
if word in vocabList:
returnVec[vocabList.index(word)]=1 #对应索引标记1
else:
print("the word: %s is not in my Vocabulary!" %word)
return returnVec
4.5.2 训练算法:从词向量计算概率
该函数的伪代码如下:
计算每个类别中的文档数目
对每篇训练文档:
对每个类别:
如果词条出现在文档中→ 增加该词条的计数值
增加所有词条的计数值
对每个类别:
对每个词条:
将该词条的数目除以总词条数目得到条件概率
返回每个类别的条件概率
def trainNB0(trainMatrix,trainCategory): #文档矩阵,文档类别标签组成的向量
numTrainDocs=len(trainMatrix) #单个文档个数
numWords=len(trainMatrix[0])
pAbusive=sum(trainCategory)/float(numTrainDocs) #含有侮辱性总数/文档总数,即P(1)
p0Denom=0.0
p1Denom=0.0
p0Num=zeros(numWords)
p1Num=zeros(numWords)
for i in range(numTrainDocs):
if trainCategory[i]==1:
p1Num+=trainMatrix[i]
p1Denom+=sum(trainMatrix[i])
else:
p0Num+=trainMatrix[i]
p0Denom+=sum(trainMatrix[i])
p1Vect=p1Num/p1Denom
p0Vect=p0Num/p0Denom
return p0Vect,p1Vect,pAbusive
该函数为统计单词列表中每个单词在0 和 1 两个分类中出现的概率,即P(w|c)
我们需要找出0和1两个分类中概率最大的单词(特征),可以粗略的用概率最大的单词来作为判断是否为某分类。
4.5.3 测试算法:根据现实情况修改分类器
(1)利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,即计算p(w0|1)p(w1|1)p(w2|1)。如果其中一个概率值为0,那么最后的乘积也为0。为降低这种影响,可以将所有词的出现数初始化为1,并将分母初始化为2。
(2)多个概率相乘(<1)数值过小下溢四舍五入得到不正确答案,因此进行log处理
朴素贝叶斯分类函数
#
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
#
def testingNB():
listOPosts,listClasses=loadDataSet()
myVocabList=createVocabList(listOPosts)
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList,postinDoc))
p0V,p1V,pAb=trainNB0(array(trainMat),array(listClasses))
testEntry=['love','my','dalmation']
thisDoc=array(setOfWords2Vec(myVocabList,testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
testEntry=['stupid','garbage']
thisDoc=array(setOfWords2Vec(myVocabList,testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
4.5.4 准备数据:文档词袋模型
将每个词的出现与否作为一个特征,这可以被描述为词集模型(set-of-words model)。如果一个词在文档中出现不止一次,这可能意味着包含该词是否出现在文档中所不能表达的某种信息,这种方法被称为词袋模型(bag-of-words model)。
因此需要统计出现次数,而不是仅仅出现设置为1。
4.6 示例:使用朴素贝叶斯过滤垃圾邮件
4.6.1 准备数据:切分文本
(1)利用正则表达式切割,能够删除标点符号。
(2)利用长度判断是否为空格,删去空格并统一大小写。
import re
reg=re.compile('\\W+')
l=reg.split(s)
a=[per.lower() for per in l if len(per)>0]
4.6.2 测试算法:使用朴素贝叶斯进行交叉验证
#切割文本
def textParse(bigString):
import re
listOfTokens=re.split(r'\W+',bigString)#正则表达式删除标点
return [tok.lower() for tok in listOfTokens if len(tok)>2]#删除空格
#
def spamTest():
docList=[];classList=[];fullText=[]
for i in range(1,26): #26个文本
wordList=textParse(open('spam\%d.txt' %i).read()) #返回单词向量
docList.append(wordList) #每行添加一个向量
fullText.extend(wordList)
classList.append(1) #分类1
wordList=textParse(open('ham\%d.txt' %i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0) #分类0
vocabList=createVocabList(docList) #转化为列表单词
trainingSet=list(range(50))
testSet=[]
for i in range(10): #十个样本
randIndex=int(random.uniform(0,len(trainingSet))) #随机选出一个
testSet.append(trainingSet[randIndex]) #添加到测试集合中
del(trainingSet[randIndex]) #删除训练集里边的测试
trainMat=[]
trainClasses=[]
for docIndex in trainingSet:
trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam=trainNB0(array(trainMat),array(trainClasses))#由训练集计算出的P(w|c)
errorCount=0
for docIndex in testSet:
wordVector=setOfWords2Vec(vocabList,docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:
errorCount+=1
print('the error rate is:',float(errorCount)/len(testSet))