优点:可以处理多类别问题,在数据较少的情况下依然有效
缺点:对输入数据的准备方式较敏感
如果p1(x,y) > p2(x,y),则(x,y)为红色一类,类别为1。
如果p1(x,y) 推导: 如果p(c1 | x,y)> p(c2 | x,y),那么属于类别c1 如果p(c1 | x,y)< p(c2 | x,y),那么属于类别c2 5、算法分析 输出的是向量文档,向量的每个元素为1或0,分别表示词汇表中的单词在输入文档中是否出现 调用此函数结果:3、什么是条件概率?
4、使用条件概率进行分类
二、代码实现
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] #1代表侮辱性文字,0代表正常言论
return postingList,classVec
2、创建一个包含在所有文档中出现的不重复词的列表
#创建一个包含在所有文档中出现的不重复词的列表
def createVocabList(dataSet):
vocabSet=set([]) #创建一个空集
#将每篇文档返回的新词集合添加到该集合
for document in dataSet:
vocabSet=vocabSet|set(document)#用于求两个集合的并集
return list(vocabSet)
3、比较词汇表和输入文档,看输入文档中的字符哪些在词汇表中出现过
#比较词汇表和输入文档,看输入文档中的字符哪些在词汇表中出现过
#vocabList:词汇表
#inputSet:某个文档
#文档词集模型:每个词只能出现一次
def setOfWords2Vec(vocabList,inputSet):
returnVec=[0]*len(vocabList) #创建一个和词汇表等长的向量,将其元素都设置为0
for word in inputSet:#遍历文档中所有单词,如果出现词汇表中的单词,则将输出文档向量中对应的值设置为1
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else:
print("the word: %s is not in my Vocabulary!" % word)
#输出的是向量文档,向量的每个元素为1或0,分别表示词汇表中的单词在输入文档中是否出现
return returnVec
#词袋模型:每个词可出现多次
def bagOfwrods2VecMN(vocabList,inputSet):
returnVec=[0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
4、测试
import bayes
from numpy import *
import feedparser
#创建一些实验样本
listOPosts,listClasses=bayes.loadDataSet()
#创建一个包含在所有文档中出现的不重复词的列表
myVocabList=bayes.createVocabList(listOPosts)
print(myVocabList)
#比较词汇表和输入文档,看输入文档中的字符哪些在词汇表中出现过
returnVec=bayes.setOfWords2Vec(myVocabList,listOPosts[0])
print(returnVec)
5、朴素贝叶斯分类器训练函数
#朴素贝叶斯分类器训练函数
#计算文档中的各个单词在各个分类中出现的概率(在0分类和1分类中出现的概率分别是多少)
#trainMatrix:文档矩阵
#trainCategory:每篇文档类别标签所构成的向量
#注意:这是一个两分类问题,计算p(1),则可由1-p(1)得到p(0),对于多于两分类问题,则需要对代码稍加修改
def trainNB0(trainMatrix,trainCategory):
numTrainDocs=len(trainMatrix) #6:表示一共有6个元素项
numWords=len(trainMatrix[0]) #32:表示第一个元素项有32个字符
#trainCategory:[0, 1, 0, 1, 0, 1]
pAbusive=sum(trainCategory)/float(numTrainDocs) #计算类别为侮辱性文字1类别出现的概率
p0Num = ones(numWords)#32个元素的1向量
p1Num = ones(numWords)
p0Denom=2.0
p1Denom=2.0
for i in range(numTrainDocs):
#一旦某个词在某一文档出现,则该词对应的个数就加1,
if trainCategory[i] == 1:#1代表侮辱性文字,而且在所有文档中,该文档的宗词数也应加一
p1Num+=trainMatrix[i] #向量相加
p1Denom+=sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect=log(p1Num/p1Denom)
p0Vect=log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive
6、朴素贝叶斯分类函数
#朴素贝叶斯分类函数
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
7、测试
for postinDoc in listOPosts:
trainMat.append(bayes.setOfWords2Vec(myVocabList,postinDoc))
pv0,pv1,pAb=bayes.trainNB0(trainMat,listClasses)
print(pv0)
print(pv1)
print(pAb)
#测试分类函数
testEntry = [ 'my', 'dog','is','cute']
thisDoc = array(bayes.setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as:', bayes.classifyNB(thisDoc, pv0, pv1, pAb))
8、封装测试函数
def testingNB():
listOPosts, listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
trainMat = []
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
pv0, pv1, pAb = trainNB0(trainMat, listClasses)
testEntry=['love','my','dalmation']
thisDoc=array(setOfWords2Vec(myVocabList,testEntry))
print(testEntry,'classified as:',classifyNB(thisDoc,pv0,pv1,pAb))
testEntry=['stupid','garbage']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print(testEntry, 'classified as:', classifyNB(thisDoc, pv0, pv1, pAb))
#封装测试函数
bayes.testingNB()
三、应用:垃圾邮件分类案例
1、接收一个大字符串并将其解析为字符串列表
#接收一个大字符串并将其解析为字符串列表
def textParse(bigString):
import re
listOfTokens = re.split(r'\\W*',bigString)
#去掉少于两个字符的字符串,并将所有字符串转化为小写
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
2、文件解析及完整的垃圾邮件测试函数
#文件解析及完整的垃圾邮件测试函数
def spamTest():
docList=[]
classList=[]
fullText=[]
#导入spam和ham下的文本文件,并将它们解析为词列表
for i in range(1,26):
wordList=textParse(open('email/spam/%d.txt'%i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
wordList=textParse(open('email/ham/%d.txt'%i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
#创建词汇表
vocabList=createVocabList(docList)
#构建训练集和测试集
trainingSet=list(range(50)) #共50封邮件,表示从0-49的整数列表
testSet=[]
#其中10封邮件被随机选为测试集
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))
errorCount=0
#遍历测试集对邮件进行分类并验证
for docIndex in testSet:
wordVector=setOfWords2Vec(vocabList,docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:
errorCount+=1
print ('this error rate is : ' ,float(errorCount)/len(testSet))