(1)程序清单4-1 词表到向量的转换函数
#---------------------------从文本中构建词条向量-------------------------
#1 要从文本中获取特征,需要先拆分文本,这里特征是指来自文本的词条,每个词
#条是字符的任意组合。词条可以理解为单词,当然也可以是非单词词条,比如URL
#IP地址或者其他任意字符串
# 将文本拆分成词条向量后,将每一个文本片段表示为一个词条向量,值为1表示出现
#在文档中,值为0表示词条未出现
#导入numpy
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)
#根据词条列表中的词条是否在文档中出现(出现1,未出现0),将文档转化为词条向量
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
(2)程序清单4-2 朴素贝叶斯分类器训练函数
#训练算法,从词向量计算概率p(w0|ci)...及p(ci)
#@trainMatrix:由每篇文档的词条向量组成的文档矩阵
#@trainCategory:每篇文档的类标签组成的向量
def trainNB0(trainMatrix,trainCategory):
#获取文档矩阵中文档的数目
numTrainDocs=len(trainMatrix)
#获取词条向量的长度
numWords=len(trainMatrix[0])
#所有文档中属于类1所占的比例p(c=1)
pAbusive=sum(trainCategory)/float(numTrainDocs)
#创建一个长度为词条向量等长的列表
p0Num=zeros(numWords);p1Num=zeros(numWords)#改进:p0Num=ones(numWords);p1Num=ones(numWords)
p0Denom=0.0;p1Denom=0.0#改进:p0Denom=2.0;p1Denom=2.0
#遍历每一篇文档的词条向量
for i in range(numTrainDocs):
#如果该词条向量对应的标签为1
if trainCategory[i]==1:
#统计所有类别为1的词条向量中各个词条出现的次数
p1Num+=trainMatrix[i]
#统计类别为1的词条向量中出现的所有词条的总数
#即统计类1所有文档中出现单词的数目
p1Denom+=sum(trainMatrix[i])
else:
#统计所有类别为0的词条向量中各个词条出现的次数
p0Num+=trainMatrix[i]
#统计类别为0的词条向量中出现的所有词条的总数
#即统计类0所有文档中出现单词的数目
p0Denom+=sum(trainMatrix[i])
#利用NumPy数组计算p(wi|c1)
p1Vect=p1Num/p1Denom #为避免下溢出问题,后面会改为log()
#利用NumPy数组计算p(wi|c0)
p0Vect=p0Num/p0Denom #为避免下溢出问题,后面会改为log()
return p0Vect,p1Vect,pAbusive
(3)程序清单4-3:朴素贝叶斯分类器
#朴素贝叶斯分类函数
#@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.0-pClass1)
if p1>p0:
return 1
else:
return 0
#分类测试整体函数
def testingNB():
#由数据集获取文档矩阵和类标签向量
listOPosts,listClasses=loadDataSet()
#统计所有文档中出现的词条,存入词条列表
myVocabList=createVocabList(listOPosts)
#创建新的列表
trainMat=[]
for postinDoc in listOPosts:
#将每篇文档利用words2Vec函数转为词条向量,存入文档矩阵中
trainMat.append(setOfWords2Vec(myVocabList,postinDoc))\
#将文档矩阵和类标签向量转为NumPy的数组形式,方便接下来的概率计算
#调用训练函数,得到相应概率值
p0V,p1V,pAb=trainNB0(array(trainMat),array(listClasses))
#测试文档
testEntry=['love','my','dalmation']
#将测试文档转为词条向量,并转为NumPy数组的形式
thisDoc=array(setOfWords2Vec(myVocabList,testEntry))
#利用贝叶斯分类函数对测试文档进行分类并打印
print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))
#第二个测试文档
testEntry1=['stupid','garbage']
#同样转为词条向量,并转为NumPy数组的形式
thisDoc1=array(setOfWords2Vec(myVocabList,testEntry1))
print(testEntry1,'classified as:',classifyNB(thisDoc1,p0V,p1V,pAb))
(4)程序清单4-4:朴素贝叶斯词袋模型
def bagOfWords2VecMN(vocabList,inputSet):
#词袋向量
returnVec=[0]*len(vocabList)
for word in inputSet:
if word in vocabList:
#某词每出现一次,次数加1
returnVec[vocabList.index(word)]+=1
return returnVec
(5)应用1:过滤垃圾邮件
#贝叶斯算法实例:过滤垃圾邮件
#处理数据长字符串
#1 对长字符串进行分割,分隔符为除单词和数字之外的任意符号串
#2 将分割后的字符串中所有的大些字母变成小写lower(),并且只
#保留单词长度大于3的单词
def testParse(bigString):
import re
listOfTokens=re.split(r'\W*',bigString)
return [tok.lower() for tok in listOPosts if len(tok)>2]
def spamTest():
#新建三个列表
docList=[];classList=[];fullTest=[]
#i 由1到26
for i in range(1,26):
#打开并读取指定目录下的本文中的长字符串,并进行处理返回
wordList=testParse(open('email/spam/%d.txt' %i).read())
#将得到的字符串列表添加到docList
docList.append(wordList)
#将字符串列表中的元素添加到fullTest
fullTest.extend(wordList)
#类列表添加标签1
classList.append(1)
#打开并取得另外一个类别为0的文件,然后进行处理
wordList=testParse(open('email/ham/&d.txt' %i).read())
docList.append(wordList)
fullTest.extend(wordList)
classList.append(0)
#将所有邮件中出现的字符串构建成字符串列表
vocabList=createVocabList(docList)
#构建一个大小为50的整数列表和一个空列表
trainingSet=range(50);testSet=[]
#随机选取1~50中的10个数,作为索引,构建测试集
for i in range(10):
#随机选取1~50中的一个整型数
randIndex=int(random.uniform(0,len(trainingSet)))
#将选出的数的列表索引值添加到testSet列表中
testSet.append(trainingSet[randIndex])
#从整数列表中删除选出的数,防止下次再次选出
#同时将剩下的作为训练集
del(trainingSet[randIndex])
#新建两个列表
trainMat=[];trainClasses=[]
#遍历训练集中的吗每个字符串列表
for docIndex in trainingSet:
#将字符串列表转为词条向量,然后添加到训练矩阵中
trainMat.append(setOfWords2Vec(vocabList,fullTest[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('the error rate is:',float(errorCount)/len(testSet))
(6)应用2:从个人广告中获取区域倾向
6.1 获取统计相关数据
#实例:使用朴素贝叶斯分类器从个人广告中获取区域倾向
#RSS源分类器及高频词去除函数
def calMostFreq(vocabList,fullTest):
#导入操作符
import operator
#创建新的字典
freqDict={}
#遍历词条列表中的每一个词
for token in vocabList:
#将单词/单词出现的次数作为键值对存入字典
freqDict[token]=fullTest.count(token)
#按照键值value(词条出现的次数)对字典进行排序,由大到小
sortedFreq=sorted(freqDict.items(),keys=operator.itemgetter(1),reverse=true)
#返回出现次数最多的前30个单词
return sortedFreq[:30]
def localWords(feed1,feed0):
import feedparser
#新建三个列表
docList=[];classList=[];fullTest=[]
#获取条目较少的RSS源的条目数
minLen=min(len(feed1['entries']),len(feed0['entries']))
#遍历每一个条目
for i in range(minLen):
#解析和处理获取的相应数据
wordList=textParse(feed1['entries'][i]['summary'])
#添加词条列表到docList
docList.append(wordList)
#添加词条元素到fullTest
fullTest.extend(wordList)
#类标签列表添加类1
classList.append(1)
#同上
wordList=testParse(feed0['entries'][i]['summary'])
docList.append(wordList)
fullTest.extend(wordList)
#此时添加类标签0
classList.append(0)
#构建出现的所有词条列表
vocabList=createVocabList(docList)
#找到出现的单词中频率最高的30个单词
top30Words=calMostFreq(vocabList,fullTest)
#遍历每一个高频词,并将其在词条列表中移除
#这里移除高频词后错误率下降,如果继续移除结构上的辅助词
#错误率很可能会继续下降
for pairW in top30Words:
if pairW[0] in vocabList:
vocabList.remove(pairW[0])
#下面内容与函数spaTest完全相同
trainingSet=range(2*minLen);testSet=[]
for i in range(20):
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('the error rate is:',float(errorCount)/len(testSet))
return vocabList,p0V,p1V
6.2 对得到的的数据进行分析
#最具表征性的词汇显示函数
def getTopWords(ny,sf):
import operator
#利用RSS源分类器获取所有出现的词条列表,以及每个分类中每个单词出现的概率
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):topNY.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])