上一章介绍了贝叶斯分类的理论基础,下面举个例子说明。
有如下数据集:
P(Y=1)=915,P(Y=−1)=615
对特征 X(1),Y=1
P(X(1)=1|Y=1)=29,P(X(1)=2|Y=1)=39,P(X(1)=3|Y=1)=49
对特征 X(2),Y=1
P(X(2)=S|Y=1)=19,P(X(2)=M|Y=1)=49,P(X(2)=L|Y=1)=49
对特征 X(1),Y=−1
P(X(1)=1|Y=−1)=36,P(X(1)=2|Y=−1)=26,P(X(1)=3|Y=−1)=16
对特征 X(2),Y=−1
P(X(2)=S|Y=−1)=36,P(X(2)=M|Y=−1)=26,P(X(2)=L|Y=−1)=16
对于给定的 x=(2,S)T
只需对 X(1)=2和X(2)=S 时候的进行判断
P(Y=1)P(X(1)=2|Y=1)P(X(2)=S|Y=1)=915∗39∗19=145
P(Y=−1)P(X(1)=2|Y=−1)P(X(2)=S|Y=−1)=615∗26∗36=345
则属于 −1 类
提取所有邮件中的词汇,组成词汇表,这里的词汇表中每个单词只能出现一次。
def loadDataSet():
postingList=[['my','dog','has','flea','problem','help','please'],
['maybe','not','take','him','to','dog','park','stupid'],
['my','dalmation','is','so','cute','I','love','him'],
['stop','posting','stupid','workless','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 creatVocabList(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
loadDataSet() 是测试的数据
createVocabList() 创建词汇表, set 是元素只能出现一次的集合, | 是Python中的并集的一次,在集合中不断的加入新的词汇。
setOfWordsVec() 函数,输入参数是词汇表和要判断的文档,这里的判断是,只要文档中的原始在词汇表中出现了无论你出现几次,就值为1,返回的向量是和词汇表等长,只包含 0,1 的向量,代表对于位置是否在词汇表中出现。
该函数被称为词集模型,记录单词是否出现。
P(ck|w)=P(w|ck)P(ck)P(w)=P(w0|ck)P(w1|ck),...,P(wn|ck)P(w)
计算每个类别中的文档数目
对每篇训练文档:
===对每个类别:
======如果词条出现在文档中,则增加该词条的计数
======增加所有出现词条的计数值
===对每个类别:
======对每个词条:
=========将该词条的数目除以总词条的数目得到条件概率
===返回每个类别的条件概率
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
# p0Num = zeros(numWords)
# p1Num = zeros(numWords)
# p0Denom = 0.0
# p1Denom = 0.0
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+=sum(trainMatrix[i])
else:
p0Num+=trainMatrix[i]
p0Denom+=sum(trainMatrix[i])
# p1Vect = p1Num/p1Denom
# p0Vect = p0Num/p0Denom
p1Vect = log(p1Num/p1Denom)
p0Vect = log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive
上面的函数返回了条件概率和先验概率
为防止出现0的情况,对其中注释部分进行了修改
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 bagOfwords2VecMN(vocabList,inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]+=1
return returnVec
该函数被称为词袋模型,统计每个单词出现的次数。
def textParse(bigString):
import re
listOfTokens = re.split(r'\W*',bigString)
return [tok.lower() for tok in listOfTokens if len(tok)>3]
将字符转换成小写,并过滤掉长度小于3的单词
def spamTest():
docList= []
classList= []
fullText=[]
for i in range(1,26):
wordList = textParse(open('email/spam/%d.txt'%i).read())
docList.append(wordList)
fullText.append(wordList)
classList.append(1)
wordList = textParse(open('email/ham/%d.txt'%i).read())
docList.append(wordList)
fullText.append(wordList)
classList.append(0)
vocabList = creatVocabList(docList)
trainingSet = 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(bagOfwords2VecMN(vocabList,docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam= trainNB0(array(trainMat),array(trainClasses))
errorCount = 0
for docIndex in testSet:
wordVector= bagOfwords2VecMN(vocabList,docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam)!= classList[docIndex]:
errorCount+=1
print 'error email:',docList[docIndex]
print 'the error rate is:',float(errorCount)/len(testSet)
测试程序
在50封邮件中,正常邮件和垃圾邮件各占25,在在其中随机抽取10封电子邮件,预测其所在的类别。
运行几次发现错误率在6-10%之间。
1.朴素贝叶斯分类分类的结果受类的均衡程度影响比较大,如果某个类的数据比较多,则其先验概率比较大,很可能使测试数据都分到这个类,所有在分类时候要对类别的数据进行均衡。
2.邮件分类的词汇表是训练集所有的单词组成的
在计算后条件概率的时候,实际上把正类邮件在一起考虑,负类邮件在一起考虑。
若被分到正类,计算测试邮件中单词,在词汇表中出现的每个单词出现的概率,也即条件概率。训练集中正类所占的比例就是先验概率。每个单词的条件概率的乘积再乘以先验概率就是,该测试样本属于正类的概率。
负类,同上
3.在提取单词作为词汇表时候,要过滤掉单词长度比较短的如:is 、a 、an、the,等,至于过录掉长度为几的单词,需要自己测试。
4.在朴素贝叶斯定理中我们认为特征之间是相互独立的,然而邮件中的单词不一定是相互独立的。
5.对于一些复杂的邮件,受特点的词汇影响比较大分类的准确率会很差的。比如:恐怖分子在准备发生恐怖袭击的时候,邮件讨论的话题一定是关于炸弹、弹药的词汇。然而如果是个弹药专家,ta的邮件中也弹药方面的词汇也是比较多的,不能直接简单的根据条件概率判断,邮件的发送者的身份对邮件的内容影响比较大,同时许多情况下邮件的发送者身份有不知道,所有要添加人工因素(这个我就不知道了),来提高准确率。