admin 管理员组

文章数量: 887021


2024年1月23日发(作者:化学常量元素和微量元素)

机器学习实训实验报告( 四 )

专业 班级 学号 姓名

实验项目名称:利用朴素贝叶斯过滤垃圾邮件

实验内容:

1、了解概率分类器的意义,理解条件概率的计算方法

2、了解朴素贝叶斯的理论知识,了解基于以上理论知识构建分类器的方法

3、根据朴素贝叶斯的一般步骤进行过滤垃圾邮件的任务

实验过程:

算法分析:

简介:

朴素贝叶斯算法的分类模型是基于Bayes定理的,下面就简单介绍一下Bayes定理.设X为一个类别未知的数据样本,H为某个假设,C表示类别集合,若数据样本X属于一个特定的类别c,那么分类问题就是决定P(H/X),即在获得数据样本X时,H假设成立的概率.由于P(H) , P(X),

P(X/H)的概率值可以从(供学习使用的)数据集合中得到,Bayes定理描述了如何根据P(H) ,

P(X), P(X/H)计算获得的P(H/X),有关的具体公式定义描述如下

算法过程:

我们假设训练集为m个样本n个维度,如下:

(x(1)1,x(1)2,...x(1)n,y1),(x(2)1,x(2)2,...x(2)n,y2),...(x(m)1,x(m)2,...x(m)n,ym)(x1(1),x2(1),...xn(1),y1),(x1(2),x2(2),...xn(2),y2),...(x1(m),x2(m),...xn(m),ym)

共有K个特征输出类别,分别为C1,C2,...,CKC1,C2,...,CK,每个特征输出类别的样本个数为m1,m2,...,mKm1,m2,...,mK,在第k个类别中,如果是离散特征,则特征XjXj各个类别取值为mjlmjl。其中l取值为源程序代码:

from numpy import *

import re

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

#函数说明:将切分的词条整理成不重复的词条列表

def createVocabList(dataSet):

vocabSet = set([]) ##创建一个空的不重复列表

for document in dataSet:

vocabSet = vocabSet | set(document) #取并集

return list(vocabSet)

#函数说明:根据vocabList,将inputSet向量化,每个元素为1或0

def setOfWords2Vec(vocabList, inputSet):

returnVec = [0]*len(vocabList) #创建一个其中所含元素都为0的向量

for word in inputSet: #遍历每个词条

if word in vocabList: #如果词条存在于词汇表中,则置1

returnVec[(word)] = 1

else: print ("the word: %s is not in my Vocabulary!" %

word)

return returnVec

#函数说明:朴素贝叶斯分类器训练函数

def trainNB0(trainMatrix,trainCategory):

numTrainDocs = len(trainMatrix) #计算训练的文档数目

numWords = len(trainMatrix[0]) #计算每篇文档的词条数

pAbusive = sum(trainCategory)/float(numTrainDocs) #文档属于侮辱类的概率

p0Num = zeros(numWords); p1Num = zeros(numWords)

输出为实例X(test)X(test) #词条出现数初始化为1

p0Denom = 0.0; p1Denom = 0.0 #分母初始化为0

的分类。

for i in range(numTrainDocs):

算法流程如下:

if trainCategory[i] == 1:

#统计属于侮辱类的总词数,出现一次,次数+1

1) 如果没有Y的先验 p1Num += trainMatrix[i]

概率,则计算Y的K个先验概率: p1Denom += sum(trainMatrix[i])

else:

P(Y=Ck)=(mk+λ)/(m+Kλ)P(Y=C #统计属于非侮辱类的总词数,出现一次,次数+1

k)=(mk+λ)/(m+Kλ),否则 p0Num += trainMatrix[i]

P(Y=Ck)P(Y=Ck)为输入的先验 p0Denom += sum(trainMatrix[i])

概率。

#对应个数除以总数,此处可以用log()防止下溢出

p1Vect = p1Num/p1Denom

2) 分别计算第k个类 p0Vect = p0Num/p0Denom

别的第j维特征的第l个个取值条 return p0Vect,p1Vect,pAbusive

件概率:#返回属于侮辱类的条件概率数组,属于非侮辱类的条件概率数组,文档属于侮辱类的概率

P(Xj=xjl|Y=Ck)P(Xj=xjl|Y=Ck)

a)如果是离散值:

#函数说明:朴素贝叶斯分类器分类函数

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):

P(Xj=xjl|Y=Ck)=mkjl+λmk+SjλP( #对应元素相乘,且所有词的对应值相加,并将此值加入到对Xj=xjl|Y=Ck)=mkjl+λmk+Sjλ

数概率中

λλ可以取值为1, p1 = sum(vec2Classify * p1Vec) + log(pClass1)

p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)

或者其他大于0的数字。

if p1 > p0:

return 1

b)如果是稀疏二项 else:

离散值:

return 0

P(Xj=xjl|Y=Ck)=P(j|Y=Ck)xjl+(1#函数说明:便利函数,封装操作

−P(j|Y=Ck)(1−xjl)P(Xj=xjl|Y=Ck)def testingNB():

=P(j|Y=Ck)xjl+(1−P(j|Y=Ck)(1− listOPosts,listClasses = loadDataSet() #加载数据

myVocabList = createVocabList(listOPosts) #整理词条

xjl)

trainMat=[]

此时ll只有两种 #遍历listOPosts,向trainMat插入向量化后的listOPosts

取值。

for postinDoc in listOPosts:

(setOfWords2Vec(myVocabList,

c)如果是连续值不postinDoc))

需要计算各个l的取值概率,直 p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))

#记:侮辱类的条件概率数组,非侮辱类的条件概率数组,文接求正态分布的参数:

档是侮辱类的概率

P(Xj=xj|Y=Ck)=12πσ2k−−−−√ testEntry = ['love', 'my', 'dalmation']

exp(−(xj−μk)22σ2k)P(Xj=xj|Y=C #根据myVocabList,向量化testEntry

thisDoc = array(setOfWords2Vec(myVocabList, testEntry))

k)=12πσk2exp(−(xj−μk)22σ #输出分类

k2)

print (testEntry,'classified as:

',classifyNB(thisDoc,p0V,p1V,pAb))

需要求出μk和 #根据myVocabList,向量化testEntry

σ2kμk和σk2。 μkμk为在样本类 testEntry = ['stupid', 'garbage']

别CkCk中,所有XjXj的平均值。 thisDoc = array(setOfWords2Vec(myVocabList, testEntry))

(testEntry,'classified as:

σ2kσk2为在样本类别CkCk中, print

',classifyNB(thisDoc,p0V,p1V,pAb))

所有XjXj的方差。

#函数说明:朴素贝叶斯词袋模型

1,2,...Sj1,2,...Sj,SjSj为特征j不同的取值数。

3)对于实例X(test)X(test),分别计算:

P(Y=Ck)∏j=1nP(Xj=x(test)j|Y=Ck)P(Y=Ck)∏j=1nP(Xj=xj(test)|Y=Ck)

4)确定实例X(test)X(test)的分类CresultCresult

Cresult=argmaxCkP(Y=Ck)∏j=1nP(Xj=X(test)j|Y=Ck)

调试过程中的关键问题及修改:

1、

错误:

正则分割函数e():

结果为全部是空格和逗号

解决方法:

改为e('[ ,.]+')

意思是按空格和.分割

2、

报错:UnicodeDecodeError: 'gbk'

codec can't decode byte 0xae in

position 199: illegal multibyte

sequence

原因:是打印的某种编码类型的字符串到终端,所以由于编码不匹配,导致出现此问题。

解决方法:

查阅资料后发现是文件里有个乱码,在ham文件夹中在里第二行去掉那个?就可以了,

def bagOfWords2VecMN(vocabList, inputSet):

returnVec = [0]*len(vocabList) #创建一个其中所含元素都为0的向量

for word in inputSet: #遍历每个词条

if word in vocabList: #如果词条存在于词汇表中,则计数加一

returnVec[(word)] += 1

return returnVec

#函数说明:#将字符串转换为字符列表

def textParse(bigString):

#将特殊符号作为切分标志进行字符串切分,即非字母、非数字

listOfTokens = ('rW+', bigString)

#除了单个字母,例如大写的I,其它单词变成小写

return [() for tok in listOfTokens if len(tok) > 2]

#函数说明:测试朴素贝叶斯分类器

def spamTest():

docList = []; classList = []; fullText = []

for i in range(1, 26): #遍历25个txt文件

#读取每个垃圾邮件,并字符串转换成字符串列表

wordList =

textParse(open('C:/Users/asus/Desktop/spam/%' % i).read())

(wordList)

(wordList)

(1) #标记垃圾邮件,1表示垃圾文件

#读取每个非垃圾邮件,并字符串转换成字符串列表

wordList =

textParse(open('C:/Users/asus/Desktop/ham/%' % i).read())

(wordList)

(wordList)

(0) #标记非垃圾邮件,1表示垃圾文件

vocabList = createVocabList(docList) #创建词汇表,不重复

trainingSet = list(range(50)); testSet = []

#创建存储训练集的索引值的列表和测试集的索引值的列表

for i in range(10): #从50个邮件中,随机挑选出40个作为训练集,10个做测试集

#随机选取索索引值

randIndex = int(m(0, len(trainingSet)))

(trainingSet[randIndex]) #添加测试集的索引值

del(trainingSet[randIndex]) #在训练集列表中删除添加到测试集的索引值

trainMat = []; trainClasses = [] #创建训练集矩阵和训练集类别标签系向量

for docIndex in trainingSet: #遍历训练集

(bagOfWords2VecMN(vocabList,

docList[docIndex]))

#将生成的词集模型添加到训练矩阵中

(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 #错误计数加1

print("分类错误的测试集:",docList[docIndex])

print('错误率:%.2f%%' % (float(errorCount) / len(testSet) *

100))

#主函数(前面部分’’’ ’’’已注释)

if __name__ == '__main__':

"4-1"

'''listOposts,listClasses=loadDataSet()

myVocabList=createVocabList(listOposts)

print(myVocabList)'''

"4-2"

'''listOposts,listClasses=loadDataSet()

myVocabList=createVocabList(listOposts)

trainMat=[]

for i in listOposts:

(setOfWords2Vec(myVocabList,i))

p0v,p1v,pAb=trainNB0(trainMat,listClasses)

print("p0v:%s"% p0v);print("p1v:%s"% p1v);print("pAb:%s"%

pAb);'''

"4-3"

#testingNB()

"4-4"

'''mysent='This book is the best on python or M.L. I have ever

laid eyes upon.'

#print (()) #()方法分割

regex=e('[ ,.]+')

#listoftokens=(mysent) #按空格和.分割

#print(listoftokens)

emailtext= open('C:/Users/asus/Desktop/ham/').read()

listoftokens=(emailtext)

print (listoftokens)'''

"4-5"

spamTest()

spamTest()

运行结果:

4-1

4-2

4-3

4-4

优化后的分割

一封电子邮件处理结果

4-5

每次运行结果不同:

实验总结:

学习朴素贝叶斯需要许多的基础知识,例如条件概率、贝叶斯定理、分类器等,要知道它们的概念,理解它们的在朴素贝叶斯分类的起到的作用,充当了说明角色,通过这次学习这些基本的理论知识我有了进一步的认识,当然在代码方面还是有许多欠缺的地方。

我觉得这门课和概率论的关系十分密切,而学习概率论与数理统计最重要的就是要学习书本中渗透的一种全新的思维方式。统计与概率的思维方式,和逻辑推理不一样,它是不确定的,也就是随机的思想。这也是一个人思维能力最主要的体现,整个学习过程中要紧紧围绕这个思维方式进行。做这个实验,对问题需要有更深层次的思考,因而学起来也是很吃力的。不过收获也是很多的。

评分小项

1.实验报告格式排版

实验2.实验设计思路(科学性、可行性、创新性)

成绩评定

3.实验代码编写(规范性、正确性、复杂性)

4.实验结果分析(正确性、合理性)

5.实验心得总结

分值

10分

30分

30分

20分

10分

得分

总分:


本文标签: 概率 类别 实验 训练 学习