1.已知一个文本集合为:
[[‘my’, ‘dog’,‘has’,’false’,’problems’,’help’,’please’],
[‘maybe’,’not’,’take’,’him’,’to’,’dog’,’park’,’stupid’],
[‘my’,’dalmation’,’is’,’so’,’cute’,’I’,’love’,’him’,’my’],
[‘stop’,‘posting’,‘stupid’,‘worthless’,‘garbage’], [‘mr’,‘licks’,‘ate’,‘my’,‘steak’,‘how’,‘to’,‘stop’,‘him’],
[‘quit’,‘buying’,‘worthless’,‘dog’,‘food’,‘stupid’]]
此数据集有6个文本,其对应标签为classVec={0,1,0,1,0,1},标签为1表示此文本带有侮辱性词语,否则标签为0。要求:
(1)得到数据集的所有出现的单词构成的无重复词的词典。即为:
[‘cute’, ‘love’, ‘help’, ‘garbage’, ‘quit’, ‘I’, ‘problems’, ‘is’, ‘park’, ‘stop’, ‘flea’, ‘dalmation’, ‘licks’, ‘food’, ‘not’, ‘him’, ‘buying’, ‘posting’, ‘has’, ‘worthless’, ‘ate’, ‘to’, ‘maybe’, ‘please’, ‘dog’, ‘how’, ‘stupid’, ‘so’, ‘take’, ‘mr’, ‘steak’, ‘my’]
(2)根据词典将原始的6个文本表示成0或1数字构成的词向量形式。例如,第一个文本对应的词向量为:
[0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1]
(3)利用朴素贝叶斯分类模型。
(4)现有两个文本:[‘love’, ‘my’, ‘dalmation’], [‘stupid’, ‘garbage’],用(3)得到的朴素贝叶斯分类器对其进行分类,即给出其标签为0(非侮辱性文本)或1(侮辱性文本)。
2.在(1)-(4)的基础上,对给出的50个邮件,其中25个垃圾邮件,25个非垃圾邮件进行分类,随机选取20个垃圾邮件和20个非垃圾邮件作为训练集,剩余10个文本为测试集,用训练集文本得到朴素贝叶斯文本分类器的多项式模型或贝努力模型,然后对测试集文本进行测试,得到其accuracy值。
代码如下:
# -*- coding: utf-8 -*-
from numpy import* #导入所有库
def loadDataSet(): #载入数据和标签
postingList=[
['my','dog','has','flea','problems','help','please'],
['maybe','not','take','him','dog','part','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
###集合去重###
def createVocabList(dataSet): #创建一个【无重复】的空列表,输入数据集
vocabSet=set([]) #创建空集合,初始化
for document in dataSet: #读取文件中的数据
vocabSet=vocabSet | set(document) #创建两个集合的并集
return list(vocabSet) #以列表形式返回【无重复的】词汇集
###输入文档去重得词向量###
def setOfWords2Vec(vocabList,inputSet): #输入词汇表和文档
returnVec=[0]*len(vocabList) #创建一个其中所含元素都为0的向量
for word in inputSet: #遍历输入的数据集
#判断单词是否出现在词典列表中,每个文本用【0-不赞同和1-赞同】数字表示成词向量形式,最后6个文本集合形成6个词向量
if word in vocabList:
returnVec[vocabList.index(word)]=1
else:
print("the word: %s is not in my Vocabulary!" %word)
# print(returnVec)
return returnVec #返回得到的词向量文档
###朴素贝叶斯模型分类模型###
def trainNB0(trainMatrix,trainCategory): #训练得到得到贝叶斯分类模型,输入文档向量和标签向量
numTrainDocs=len(trainMatrix) #计算出文档向量的行数
numWords=len(trainMatrix[0]) #计算出文档向量的列数
pAbusive=sum(trainCategory)/float(numTrainDocs) #任意文档属于侮辱性文档的概率
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=log(p1Num/p1Denom) #防止下溢出,自然对数处理
p0Vect=log(p0Num/p0Denom)
return p0Vect,p1Vect,pAbusive #返回任意文档属于侮辱性文档的概率,词汇在侮辱性文档中出现概率,词汇在非侮辱性文档中出现概率
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 #输出1是垃圾邮件
else:
return 0 #输出0不是垃圾邮件
def testingNB(): #用两个测试样本用朴素贝叶斯文本分类器对其进行分类
listOposts,listClasses=loadDataSet()
myVocablist=createVocabList(listOposts)
print(myVocablist)
trainMat=[]
for postinDoc in listOposts:
trainMat.append(setOfWords2Vec(myVocablist, postinDoc))
p0V,p1V,pAb=trainNB0(trainMat,listClasses)
testEntry=['love','my','dalmation']
thisDoc=array(setOfWords2Vec(myVocablist, testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc, p0V, p1V,pAb))
testEntry=['stupid','garbge']
thisDoc=array(setOfWords2Vec(myVocablist, testEntry))
print(testEntry,'classified as: ',classifyNB(thisDoc, p0V, p1V,pAb))
def textParse(bigString): #切分文本,接受一个大字符串并将其解析为字符串列表
import re
listOftokens=re.split(r'\w*',bigString) #\W表示非单词字符,*表示匹配前一个字符0次或无限次
return [tok.lower() for tok in listOftokens if len(tok)>2] #去掉少于2个字符串并将所有字符串转换为小写
###垃圾邮箱分类###
def spamTest():
docList=[] #文档列表
classList=[] #标签列表
for i in range(1,26):
wordList=textParse(open('E:/pywork/test/sy-7/email/spam/%d.txt' %i).read()) #打开spam文档,切分文本
docList.append(wordList) #append向列表尾部添加一个新的元素,将整个wordList添加进去,即文本为基本单位
classList.append(1) #标签表示为spam
wordList=textParse(open('E:/pywork/test/sy-7/email/ham/%d.txt' %i).read()) # 打开ham文档,切分文本
docList.append(wordList)
classList.append(0) #标签表示为ham
vocabList=createVocabList(docList) #以上导入文本并解析为不重复的词列表
trainingSet=list(range(50)) #随机构建训练集
testSet=[]
times=0
while True:
randIndex=int(random.uniform(0,len(trainingSet))) #选择出的数字对应的文档被添加到测试集
if classList[trainingSet[randIndex]]==1:
testSet.append(trainingSet[randIndex])
del (trainingSet[randIndex])
times +=1
if times==5:
break
while True:
randIndex=int(random.uniform(0,len(trainingSet)))
if classList[trainingSet[randIndex]]==0:
testSet.append(trainingSet[randIndex])
del (trainingSet[randIndex])
times+=1
if times==10:
break
trainMat=[];trainClasses=[]
for docIndex in trainingSet: #得测试集和测试标签
trainMat.append(setOfWords2Vec(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam=trainNB0(array(trainMat),array(trainClasses))
rightCount=0
for docIndex in testSet: #遍历测试集,对其中每封电子邮件进行分类
wordVector=setOfWords2Vec(vocabList,docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam)==classList[docIndex]:
rightCount+=1 #如果邮件分类正确,则正确数加1
# print('The right rate of this test is:',float(rightCount)/len(testSet))
return float(rightCount)/len(testSet)
def multiTest():
numTests=10;rightSum=0.0
for k in range(numTests):
rightSum += spamTest()
# print('after %d iterations the average reeor rate is:%f' %(numTests,rightSum/float(numTests)))
testingNB()
multiTest()