机器学习实验之朴素贝叶斯(垃圾邮件判断)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
机器学习实训实验报告(四)
专业班级学号姓名实验项目名称:利用朴素贝叶斯过滤垃圾邮件
实验内容:
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),x 2(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']]
classV ec = [0,1,0,1,0,1] #类别:1代表侮辱性文字,0代表正常
return postingList,classVec
#函数说明:将切分的词条整理成不重复的词条列表
def createV ocabList(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[vocabList.index(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]) #计算每篇文档的词条数
1,2,...Sj1,2,...Sj,SjSj为特征j不同的取值数。
输出为实例X(test)X(test)的分类。
算法流程如下:
1) 如果没有Y的先验概率,则计算Y的K个先验概率:P(Y=Ck)=(mk+λ)/(m+Kλ)P(Y=C k)=(mk+λ)/(m+Kλ),否则
P(Y=Ck)P(Y=Ck)为输入的先验
概率。
2) 分别计算第k个类
别的第j维特征的第l个个取值条件概率:
P(Xj=xjl|Y=Ck)P(Xj=xjl|Y=Ck)
a)如果是离散值:
P(Xj=xjl|Y=Ck)=mkjl+λmk+SjλP( Xj=xjl|Y=Ck)=mkjl+λmk+Sjλ
λλ可以取值为1,或者其他大于0的数字。
b)如果是稀疏二项离散值:
P(Xj=xjl|Y=Ck)=P(j|Y=Ck)xjl+(1−P(j|Y=Ck)(1−xjl)P(Xj=xjl|Y=Ck) =P(j|Y=Ck)xjl+(1−P(j|Y=Ck)(1−xjl)
此时ll只有两种取值。
c)如果是连续值不需要计算各个l的取值概率,直接求正态分布的参数:
P(Xj=xj|Y=Ck)=12πσ2k−−−−√exp(−(xj−μk)22σ2k)P(Xj=xj|Y=C k)=12πσk2exp(−(xj−μk)22σ
k2)
需要求出μk和
σ2kμk和σk2。
μkμk为在样本类别CkCk中,所有XjXj的平均值。
σ2kσk2为在样本类别CkCk中,所有XjXj的方差。
pAbusive = sum(trainCategory)/float(numTrainDocs) #文档属于侮辱类的概率
p0Num = zeros(numWords); p1Num = zeros(numWords)
#词条出现数初始化为1
p0Denom = 0.0; p1Denom = 0.0 #分母初始化为0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
#统计属于侮辱类的总词数,出现一次,次数+1
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
#统计属于非侮辱类的总词数,出现一次,次数+1
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
#对应个数除以总数,此处可以用log()防止下溢出
p1Vect = p1Num/p1Denom
p0Vect = 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
else:
return 0
#函数说明:便利函数,封装操作
def testingNB():
listOPosts,listClasses = loadDataSet() #加载数据
myV ocabList = createV ocabList(listOPosts) #整理词条
trainMat=[]
#遍历listOPosts,向trainMat插入向量化后的listOPosts
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
#记:侮辱类的条件概率数组,非侮辱类的条件概率数组,文档是侮辱类的概率
testEntry = ['love', 'my', 'dalmation']
#根据myV ocabList,向量化testEntry
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
#输出分类
print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
#根据myV ocabList,向量化testEntry
testEntry = ['stupid', 'garbage']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
#函数说明:朴素贝叶斯词袋模型
3)对于实例
X(test)X(test),分别计算:
P(Y=Ck)∏j=1nP(Xj=x(test)j|Y=C k)P(Y=Ck)∏
j=1nP(Xj=xj(test)|Y=Ck)
4)确定实例
X(test)X(test)的分类CresultCresult
Cresult=argmax
CkP(Y=Ck)∏j=1nP(Xj=X( test)j|Y=Ck)
调试过程中的关键问题及修改:1、
错误:
正则分割函数pile():
结果为全部是空格和逗号
解决方法:
改为pile('[ ,.]+')
意思是按空格和.分割
2、
报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 199: illegal multibyte sequence
原因:是打印的某种编码类型的字符串到终端,所以由于编码不匹配,导致出现此问题。
解决方法:
查阅资料后发现是文件里有个乱码,在ham文件夹中在23.txt里第二行去掉那个?就可以了,
运行结果:
4-1
4-2
4-3
4-4
优化后的分割
一封电子邮件处理结果
4-5
每次运行结果不同:
实验总结:
学习朴素贝叶斯需要许多的基础知识,例如条件概率、贝叶斯定理、分类器等,要知道它们的概念,理解它们的在朴素贝叶斯分类的起到的作用,充当了说明角色,通过这次学习这些基本的理论知识我有了进一步的认识,当然在代码方面还是有许多欠缺的地方。
我觉得这门课和概率论的关系十分密切,而学习概率论与数理统计最重要的就是要学习书本中渗透的一种全新的思维方式。
统计与概率的思维方式,和逻辑推理不一样,它是不确定的,也就是随机的思想。
这也是一个人思维能力最主要的体现,整个学习过程中要紧紧围绕这个思维方式进行。
做这个实验,对问题需要有更深层次的思考,因而学起来也是很吃力的。
不过收获也是很多的。
实验成绩评定
评分小项分值得分总分:
1.实验报告格式排版10分
2.实验设计思路(科学性、可行性、创新性) 30分
3.实验代码编写(规范性、正确性、复杂性) 30分
4.实验结果分析(正确性、合理性) 20分
5.实验心得总结10分。