朴素贝叶斯文本分类
from numpy import *
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'],
['my','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 createVocabList(dataSet):
#新建一个存放词条的集合
vocabSet=set([])
for document in dataSet:
#将文档列表转为集合的形式,保证每个词条的唯一性
#然后与vocabSet取并集,向vocabSet中添加没有出现
#的新的词条
vocabSet=vocabSet|set(document)
#再将集合转化为列表,便于接下来的处理
return list(vocabSet)
#词集模型对应词汇出现与否
#该函数可以用来生成输入文档对应的词条对应向量
#vocabSet是先前生成的不重复词条列表 input是输入用来检测的文档
def setOfWords2Vec(vocabSet,inputSet):
#新建一个长度为vocabSet的列表,并且各维度元素初始化为0
returnVec=[0]*len(vocabSet)
#遍历文档中的每一个词条
for word in inputSet:
#如果词条在词条列表中出现
if word in vocabSet:
#通过列表获取当前word的索引(下标)
#将词条向量中的对应下标的项由0改为1
returnVec[vocabSet.index(word)]=1
else: print('the word: %s is not in my vocabulary! '%'word')
#返回inputet转化后的词条向量
return returnVec
#词袋模型,对应词汇出现次数
def bagOfWord2VecMN(vocabList,inputSet):
returnVec=[0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]+=1
return returnVec
#trainMatrix时输入的m*n的由每篇文档的词条向量组成的文档矩阵,一行就是一个文档。trainCategory是文档矩阵的对应的标签向量是n*1的矩阵
def trainNBO(trainMatrix,trainCategory):
#文档数量
numTrainDocs=len(trainMatrix)
#一个文档中词汇的数量
numWords=len(trainMatrix[0])
# 所有文档中属于类1所占的比例p(c=1)侮辱性文档
pAbusive=sum(trainCategory)/float(numTrainDocs)
#分类0中的文档对应词汇的数量
p0Num=ones(numWords)
#分类1的词汇
p1Num=ones(numWords)
#分类1中的文档对应词汇的数量
p0Denom=2.0
#分类1中词汇的数量
p1Denom=2.0
for i in range(numTrainDocs):
#当前遍历的文档是分类1侮辱性文档时
if trainCategory[i]==1:
#将当前的文章词汇加入分类一的词汇表中
p1Num+=trainMatrix[i]
p1Denom+=sum(trainMatrix[i])
else:
# 将当前的文章词汇加入分类0的词汇表中
p0Num+=trainMatrix[i]
p0Denom+=sum(trainMatrix[i])
p1Vect=log(p1Num/p1Denom)#分类0中不同词汇出现的概率
p0Vect=log(p0Num/p0Denom)#分类1中不同词汇出现的概率
return p0Vect,p1Vect,pAbusive
#vec2Classify:待测试分类的词条向量 p0Vec:类别0所有文档中各个词条出现的频数p(wi|c0)
#p0Vec:类别1所有文档中各个词条出现的频数p(wi|c1) pClass1:类别为1的文档占文档总数比例
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
# 根据朴素贝叶斯分类函数分别计算待分类文档属于类1和类0的概率
p1=sum(vec2Classify*p1Vec)+log(pClass1)
p0=sum(vec2Classify*p0Vec)+log(1-pClass1)
if p1>p0:
return 1
else:
return 0
def testingNB():
listOposts,listClasses=loadDataSet()
myVocabList=createVocabList(listOposts)
traimMat=[]
for posticDoc in listOposts:
traimMat.append(setOfWords2Vec(myVocabList,posticDoc))
p0V,p1V,pAb=trainNBO(array(traimMat),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))
testingNB()
使用朴素贝叶斯过滤垃圾邮件
from numpy import *
#统计所有文档中出现的词条列表
def createVocabList(dataSet):
#新建一个存放词条的集合
vocabSet=set([])
for document in dataSet:
#将文档列表转为集合的形式,保证每个词条的唯一性
#然后与vocabSet取并集,向vocabSet中添加没有出现
#的新的词条
vocabSet=vocabSet|set(document)
#再将集合转化为列表,便于接下来的处理
return list(vocabSet)
#词集模型对应词汇出现与否
#该函数可以用来生成输入文档对应的词条对应向量
#vocabSet是先前生成的不重复词条列表 input是输入用来检测的文档
def setOfWords2Vec(vocabSet,inputSet):
#新建一个长度为vocabSet的列表,并且各维度元素初始化为0
returnVec=[0]*len(vocabSet)
#遍历文档中的每一个词条
for word in inputSet:
#如果词条在词条列表中出现
if word in vocabSet:
#通过列表获取当前word的索引(下标)
#将词条向量中的对应下标的项由0改为1
returnVec[vocabSet.index(word)]=1
else: print('the word: %s is not in my vocabulary! '%'word')
#返回inputet转化后的词条向量
return returnVec
#词袋模型,对应词汇出现次数
def bagOfWord2VecMN(vocabList,inputSet):
returnVec=[0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]+=1
return returnVec
#trainMatrix时输入的m*n的由每篇文档的词条向量组成的文档矩阵,一行就是一个文档。trainCategory是文档矩阵的对应的标签向量是n*1的矩阵
def trainNBO(trainMatrix,trainCategory):
#文档数量
numTrainDocs=len(trainMatrix)
#一个文档中词汇的数量
numWords=len(trainMatrix[0])
# 所有文档中属于类1所占的比例p(c=1)侮辱性文档
pAbusive=sum(trainCategory)/float(numTrainDocs)
#分类0中的文档对应词汇的数量
p0Num=ones(numWords)
#分类1的词汇
p1Num=ones(numWords)
#分类1中的文档对应词汇的数量
p0Denom=2.0
#分类1中词汇的数量
p1Denom=2.0
for i in range(numTrainDocs):
#当前遍历的文档是分类1侮辱性文档时
if trainCategory[i]==1:
#将当前的文章词汇加入分类一的词汇表中
p1Num+=trainMatrix[i]
p1Denom+=sum(trainMatrix[i])
else:
# 将当前的文章词汇加入分类0的词汇表中
p0Num+=trainMatrix[i]
p0Denom+=sum(trainMatrix[i])
p1Vect=log(p1Num/p1Denom)#分类0中不同词汇出现的概率
p0Vect=log(p0Num/p0Denom)#分类1中不同词汇出现的概率
return p0Vect,p1Vect,pAbusive
#vec2Classify:待测试分类的词条向量 p0Vec:类别0所有文档中各个词条出现的频数p(wi|c0)
#p0Vec:类别1所有文档中各个词条出现的频数p(wi|c1) pClass1:类别为1的文档占文档总数比例
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
# 根据朴素贝叶斯分类函数分别计算待分类文档属于类1和类0的概率
p1=sum(vec2Classify*p1Vec)+log(pClass1)
p0=sum(vec2Classify*p0Vec)+log(1-pClass1)
if p1>p0:
return 1
else:
return 0
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):
#读取当前一个文件中的每一个单词
wordList=textParse(open('F:\\learn\\machinelearninginaction\\Ch04\\email\\spam\\%d.txt'%i).read())
#将当前文件的单词以一个列表的形式存入
docList.append(wordList)
#将当前文件的单词以一个元素存入
fullText.extend(wordList)
#将当前文件的标签存入
classList.append(1)
wordList=textParse(open('F:\\learn\\machinelearninginaction\\Ch04\\email\\ham\\%d.txt'%i).read())
print('wordlist',wordList)
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
print('doclist',docList)
#生成一个包含所有文章全部词汇且不重复的向量
vocabList=createVocabList(docList)
trainingSet=list(range(50))
testSet=[]
#从训练集中选了10个右键作为测试集以索引的方式存入randIndex中
for i in range(10):
randIndex=int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[]
trainClasses=[]
print('vaocalist',vocabList)
#将训练集中的每一个文章转化为词向量存入trainMat对应的标签存入trainClass
for docIndex in trainingSet:
trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
trainClasses.append(classList[docIndex])
print('mat',trainMat)
#调用训练函数计算每一个词汇在0情况下的概率和1情况下的概率
p0V,p1V,pSpam=trainNBO(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('错误率是', float(errorCount)/len(testSet))
spamTest()
原文中的代码:listOfTokens = re.split(r’\W*’, bigString)
修改为:listOfTokens = re.split(r’\W+’, bigString)
使用朴素贝叶斯分类器从个人广告中获取区域倾向
原文的rss不可用这里改为了:
‘http://www.nasa.gov/rss/dyn/image_of_the_day.rss’
‘http://sports.yahoo.com/nba/teams/hou/rss.xml’
import feedparser
from numpy import *
#统计所有文档中出现的词条列表
def createVocabList(dataSet):
#新建一个存放词条的集合
vocabSet=set([])
for document in dataSet:
#将文档列表转为集合的形式,保证每个词条的唯一性
#然后与vocabSet取并集,向vocabSet中添加没有出现
#的新的词条
vocabSet=vocabSet|set(document)
#再将集合转化为列表,便于接下来的处理
return list(vocabSet)
#词集模型对应词汇出现与否
#该函数可以用来生成输入文档对应的词条对应向量
#vocabSet是先前生成的不重复词条列表 input是输入用来检测的文档
def setOfWords2Vec(vocabSet,inputSet):
#新建一个长度为vocabSet的列表,并且各维度元素初始化为0
returnVec=[0]*len(vocabSet)
#遍历文档中的每一个词条
for word in inputSet:
#如果词条在词条列表中出现
if word in vocabSet:
#通过列表获取当前word的索引(下标)
#将词条向量中的对应下标的项由0改为1
returnVec[vocabSet.index(word)]=1
else: print('the word: %s is not in my vocabulary! '%'word')
#返回inputet转化后的词条向量
return returnVec
#词袋模型,对应词汇出现次数
def bagOfWord2VecMN(vocabList,inputSet):
returnVec=[0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)]+=1
return returnVec
#trainMatrix时输入的m*n的由每篇文档的词条向量组成的文档矩阵,一行就是一个文档。trainCategory是文档矩阵的对应的标签向量是n*1的矩阵
def trainNBO(trainMatrix,trainCategory):
#文档数量
numTrainDocs=len(trainMatrix)
#一个文档中词汇的数量
numWords=len(trainMatrix[0])
# 所有文档中属于类1所占的比例p(c=1)侮辱性文档
pAbusive=sum(trainCategory)/float(numTrainDocs)
#分类0中的文档对应词汇的数量
p0Num=ones(numWords)
#分类1的词汇
p1Num=ones(numWords)
#分类1中的文档对应词汇的数量
p0Denom=2.0
#分类1中词汇的数量
p1Denom=2.0
for i in range(numTrainDocs):
#当前遍历的文档是分类1侮辱性文档时
if trainCategory[i]==1:
#将当前的文章词汇加入分类一的词汇表中
p1Num+=trainMatrix[i]
p1Denom+=sum(trainMatrix[i])
else:
# 将当前的文章词汇加入分类0的词汇表中
p0Num+=trainMatrix[i]
p0Denom+=sum(trainMatrix[i])
p1Vect=log(p1Num/p1Denom)#分类0中不同词汇出现的概率
p0Vect=log(p0Num/p0Denom)#分类1中不同词汇出现的概率
return p0Vect,p1Vect,pAbusive
#vec2Classify:待测试分类的词条向量 p0Vec:类别0所有文档中各个词条出现的频数p(wi|c0)
#p0Vec:类别1所有文档中各个词条出现的频数p(wi|c1) pClass1:类别为1的文档占文档总数比例
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
# 根据朴素贝叶斯分类函数分别计算待分类文档属于类1和类0的概率
p1=sum(vec2Classify*p1Vec)+log(pClass1)
p0=sum(vec2Classify*p0Vec)+log(1-pClass1)
if p1>p0:
return 1
else:
return 0
def textParse(bigString):
import re
listOfTokens = re.split(r'\W+', bigString)
return [tok.lower() for tok in listOfTokens if len(tok)>2]
#计算所有文章的词汇列表中使用频率最多的前30个词汇
def calcMostFreq(vocabList,fullText):
import operator
freqDict={}
for token in vocabList:
freqDict[token]=fullText.count(token)
sortedFreq=sorted(freqDict.items(),key=operator.itemgetter(1),reverse=True)
return sortedFreq[:30]
def localWords(feed1,feed0):
import feedparser
docList=[]#文章列表每一个元素是一篇文章的所有词汇
classList=[]#文章是否是侮辱性文章的对应标签列表
fullText=[]#全部文章的词汇列表
minLen=min(len(feed1['entries']),len(feed0['entries']))
for i in range(minLen):
wordList=textParse(feed1['entries'][i]['summary'])
docList.append(wordList)
fullText.append(wordList)
classList.append(1)
wordList=textParse(feed0['entries'][i]['summary'])
docList.append(wordList)
fullText.append(wordList)
classList.append(0)
#生成一个包含所有文章全部词汇且不重复的向量
vocabList=createVocabList(docList)
#计算出出现频率最高的30个词汇
top30Words=calcMostFreq(vocabList,fullText)
#去除出现次数最高的词
for pairW in top30Words:
if pairW[0] in vocabList:
print(pairW[0])
vocabList.remove(pairW[0])
trainingSet=list(range(2*minLen))
testSet=[]
##从训练集中选了20个作为测试集以索引的方式存入randIndex中
for i in range(20):
randIndex=int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[]
trainClasses=[]
# 将训练集中的每一个文章转化为词向量存入trainMat对应的标签存入trainClass
for docIndex in trainingSet:
trainMat.append(bagOfWord2VecMN(vocabList,docList[docIndex]))
trainClasses.append(classList[docIndex])
# 调用训练函数计算每一个词汇在0情况下的概率和1情况下的概率
p0V,p1V,pSpam=trainNBO(array(trainMat),array(trainClasses))
errorCount=0
for docIndex in testSet:
# 生成测试集每一篇文章的对应词向量
wordVector=bagOfWord2VecMN(vocabList,docList[docIndex])
# 预测文章类型
if classifyNB(array(wordVector),p0V,p1V,pSpam)!=classList[docIndex]:
errorCount+=1
print('错误率是',float(errorCount)/len(testSet))
return vocabList,p0V,p1V
#最具表征性的词汇显示函数
def getTopWords(ny,sf):
import operator
vocabList,p0V,p1V=localWords(ny,sf)
topNY=[]
topSF=[]
# 遍历每个类中各个单词的概率值
for i in range(len(p0V)):
# 往相应元组列表中添加概率值大于阈值的单词及其概率值组成的二元列表
if p0V[i]>-6.0:topSF.append((vocabList[i],p0V[i]))
if p1V[i] > -6.0: topSF.append((vocabList[i], p1V[i]))
#对列表按照每个二元列表中的概率值项进行排序,排序规则由大到小
sortedSF=sorted(topSF,key=lambda pair:pair[1],reverse=True)
print('SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**')
# 遍历列表中的每一个二元条目列表
for item in sortedSF:
# 打印每个二元列表中的单词字符串元素
print(item[0])
sortedNY = sorted(topNY, key=lambda pair: pair[1], reverse=True)
print('SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**')
for item in sortedNY:
print(item[0])
ny=feedparser.parse('http://www.nasa.gov/rss/dyn/image_of_the_day.rss')
sf=feedparser.parse('http://sports.yahoo.com/nba/teams/hou/rss.xml')
getTopWords(ny,sf)
小结
尽管朴素贝叶斯的条件独立性假设存在一定的问题,但是朴素贝叶斯算法仍然能取得比较理想的分类预测结果。
此外,朴素贝叶斯在数据较少的情况下仍然适用,虽然例子中为两类类别的分析,但是朴素贝叶斯可以处理多分类的情况;朴素贝叶斯的一个不足的地方是,对输入的数据有一定的要求,需要花费一定的时间进行数据的处理和解析。朴素贝叶斯中用来计算的数据为标称型数据,我们需要将字符串特征转化为相应的离散值,用于后续的统计和计算。