python实现基于朴素贝叶斯的垃圾分类算法


Posted in Python onJuly 09, 2019

一、模型方法

       本工程采用的模型方法为朴素贝叶斯分类算法,它的核心算法思想基于概率论。我们称之为“朴素”,是因为整个形式化过程只做最原始、最简单的假设。朴素贝叶斯是贝叶斯决策理论的一部分,所以讲述朴素贝叶斯之前有必要快速了解一下贝叶斯决策理论。假设现在我们有一个数据集,它由两类数据组成,数据分布如下图所示。

python实现基于朴素贝叶斯的垃圾分类算法

        我们现在用p1(x,y)表示数据点(x,y)属于类别1(图中用圆点表示的类别)的概率,用p2(x,y)表示数据点(x,y)属于类别2(图中用三角形表示的类别)的概率,那么对于一个新数据点(x,y),可以用下面的规则来判断它的类别:

如果 p1(x,y) > p2(x,y),那么类别为1。

如果 p2(x,y) > p1(x,y),那么类别为2。

       也就是说,我们会选择高概率对应的类别。这就是贝叶斯决策理论的核心思想,即选择具有最高概率的决策。

在本工程中我们可以使用条件概率来进行分类。其条件概率公式如下:

python实现基于朴素贝叶斯的垃圾分类算法

       其中粗体w表示这是一个向量,它是有多个值组成。对于类别i表示分类的个数,在本工程中i=0时,c0表示非垃圾邮件。i=1时,c1表示垃圾邮件。w展开为一个个独立特征,那么就可以将上述概率写作p(w0,w1,w2..wN|ci)。这里假设所有词都互相独立,该假设也称作条件独立性假设,它意味着可以使用p(w0|ci)p(w1|ci)p(w2|ci)...p(wN|ci)来计算上述概率,这就极大地简化了计算的过程,这也是被称为朴素贝叶斯的原因。在本工程中wj代表第i个单词特征,而p(wj|ci)则代表了在垃圾邮件(或非垃圾邮件)中,第j个单词出现的概率;而p(w|ci)则表示在垃圾邮件(或非垃圾邮件)中的全体向量特征(单词向量特征)出现的概率;而p(ci| w)则表示在全体向量特征(单词向量特征)下是垃圾邮件(或非垃圾邮件)的概率。本工程项目主要是计算p(ci|w);p(ci)则表示是垃圾邮件(或非垃圾邮件)的概率。

二、系统设计

python实现基于朴素贝叶斯的垃圾分类算法

数据的收集及保存

邮件的收集来源于网上,保存在email文件夹中。其中email分两个子文件,一个为ham文件夹(保存非垃圾邮件),另一个为spam文件夹(保存垃圾邮件)。ham与spam中各保存25各邮件,保存格式为x.txt(x为1到25)。

训练集和测试集的选取

由于收集的邮件个数有限,故选取80%的邮件作为训练集,其方式为随机选取。剩余20%邮件作为测试集。

特征向量构建

特征向量的构建分为两种,一个为对训练集的特征向量构建。一个为测试集的特征向量构建。对于训练集特征向量只需要分为两类,因为邮件只分为垃圾邮件和非垃圾邮件。特征向量分为对训练集中所有垃圾邮件中构成的特征向量(记做w)和训练集中所有非垃圾邮件构成特征向量(记做w')。对于w的计算实际就是统计所有训练集中垃圾邮件中的每个单词的出现情况,出现则次数加1。其计数初值为1,按照正常情况应为0,因为用的朴素贝叶斯算法,假设所有词都互相独立 ,就有p(w|ci) = p(w0|ci)p(w1|ci)p(w2|ci)...p(wN|ci)。所以当第i个单词wi在其特征向量中没有出现,则有p(wi|ci) =0,这就导致了p(w|ci)导致结果的不正确性。所以我们索性将所有单词默认出现1遍,所以从1开始计数。对于w'的计算和w的计算方法相同,这里就不在赘述。

对于测试集的特征向量构建就是对每个邮件中单词出现的次数进行统计,其单词表可以来源于50个邮件中的所有单词。对于每一个邮件中单词如果出现就加1,其计数初值为0。每个测试集的邮件都需构建特征向量。其特征向量在python中可用列表表示。

构建贝叶斯分类器

对于分类器的训练其目的训练三个参数为p1Vect(w中每个单词出现的概率构成的特征向量)、p0Vect(w'中每个单词出现的概率构成的特征向量)和pAbusive(训练集中垃圾邮件的概率)。对于p1Vect、p0Vect计算可能会造成下溢出,这 是 由 于 太 多 很 小 的 数 相 乘 造 成 的 。 当 计 算 乘 积p(w0|ci)p(w1|ci)p(w2|ci)...p(wN|ci)时,由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。一种解决办法是对乘积取自然对数。在代数中有ln(a*b) = ln(a)+ln(b),于是通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。图1给出函数f(x)与ln(f(x))的曲线。检查这两条曲线,就会发现它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。

python实现基于朴素贝叶斯的垃圾分类算法

所以p1Vect = log(w/p1Denom),p0Vect = log(w'/p0Denom),其中p1Denom、p0Denom分别为垃圾邮件中单词的总数和非垃圾邮件中单词的总数。而pAbusive 就等于训练集中垃圾邮件总数与训练集中邮件总数之比。

测试集验证与评估

对于判断是否为垃圾邮件,只需对每个邮件判断p(c0|w)(不是垃圾邮件的概率)与p(c1|w)(是垃圾邮件的概率)。

q如果p(c0|w) > p(c1|w),那么该邮件为非垃圾邮件。

q如果 p(c0|w) < p(c1|w),那么该邮件为垃圾邮件。

       然而p(ci|w)(i=0或1)的计算则依赖于p(w|ci)与p(ci)的计算,p(w)无需计算。所以最终结果依赖于pi = p(w|ci)·p(ci)。由于p(w|ci)很小,可能向下溢出。所以我们取以10为底的对数得log(pi) = log(p(w|ci))+log(p(ci)),所以可得以下结论:

q如果log(p0) > log(p1),那么该邮件为非垃圾邮件。

q如果log(p0) < log(p1),那么该邮件为垃圾邮件。

其中p(w|ci)为在垃圾邮件(或非垃圾邮件)中的全体向量特征(单词向量特征)出现的概率,p(ci)为训练集中垃圾邮件(或非垃圾邮件)的概率。

三、系统演示与实验结果分析对比

       由训练集(40个)和测试集(个)的样本数目比较小,所以测试的分类结果正确性为90%-100%之间,如下图所示:

python实现基于朴素贝叶斯的垃圾分类算法

python实现基于朴素贝叶斯的垃圾分类算法

        本工程只是对邮件进行二分类,贝叶斯算法也可以处理多分类问题,如新闻的分类,如分成军事、体育、科技等等。当然本工程只是对英文的垃圾邮件分类,但也可以对中文的垃圾邮件分类(可用python中的jieba的库模块进行对中文分词)。

四、代码实现

#coding=UTF-8
import random
from numpy import *
 
#解析英文文本,并返回列表
def textParse(bigString):
 #将单词以空格划分
 listOfTokens = bigString.split()
 #去除单词长度小于2的无用单词
 return [tok.lower() for tok in listOfTokens if len(tok)>2]
 
#去列表中重复元素,并以列表形式返回
def createVocaList(dataSet):
 vocabSet = set({})
 #去重复元素,取并集
 for document in dataSet:
 vocabSet = vocabSet | set(document)
 return list(vocabSet)
 
#统计每一文档(或邮件)在单词表中出现的次数,并以列表形式返回
def setOfWordsToVec(vocabList,inputSet): 
 #创建0向量,其长度为单词量的总数
 returnVec = [0]*len(vocabList)
 #统计相应的词汇出现的数量
 for word in inputSet:
 if word in vocabList:
  returnVec[vocabList.index(word)] += 1
 return returnVec
 
#朴素贝叶斯分类器训练函数
def trainNB0(trainMatrix,trainCategory): 
 #获取训练文档数
 numTrainDocs = len(trainMatrix)
 #获取每一行词汇的数量
 numWords = len(trainMatrix[0])
 #侮辱性概率(计算p(Ci)),计算垃圾邮件的比率
 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
 else :
 return 0
#test
def spamtest():
 #导入并解析文本文件
 docList =[];classList=[];fullText = []
 for i in range(1,26):
 #读取第i篇垃圾文件,并以列表形式返回
 wordList = textParse(open('email/spam/{0}.txt'.format(i)).read())
 #转化成二维列表
 docList.append(wordList)
 #一维列表进行追加
 fullText.extend(wordList)
 #标记文档为垃圾文档
 classList.append(1)
 #读取第i篇非垃圾文件,并以列表形式返回
 wordList = textParse(open('email/ham/{0}.txt'.format(i)).read())
 #转化成二维列表
 docList.append(wordList)
 #一维列表进行追加
 fullText.extend(wordList)
 #标记文档为非垃圾文档
 classList.append(0)
 #去除重复的单词元素
 vocabList = createVocaList(docList)
 #训练集,选40篇doc
 trainingSet = [x for x in range(50)]
 #测试集,选10篇doc
 testSet = []
 #选出10篇doc作测试集
 for i in range(10):
 randIndex = int(random.uniform(0,len(trainingSet)))
 testSet.append(trainingSet[randIndex])
 del trainingSet[randIndex]
 trainMat = [];trainClasses=[]
 #选出40篇doc作训练集
 for docIndex in trainingSet:
 trainMat.append(setOfWordsToVec(vocabList, docList[docIndex]))
 trainClasses.append(classList[docIndex])
 p0V,p1V,pSpam = trainNB0(array(trainMat), array(trainClasses))
 #对测试集分类
 errorCount = 0
 for docIndex in testSet:
 wordVector = setOfWordsToVec(vocabList,docList[docIndex])
 if classifyNB(array(wordVector), p0V, p1V, pSpam)!=classList[docIndex]:
  errorCount+=1
 print("错误率为:{0}".format(float(errorCount)/len(testSet)))
spamtest()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
详解Python中的type()方法的使用
May 21 Python
Python文本相似性计算之编辑距离详解
Nov 28 Python
go和python变量赋值遇到的一个问题
Aug 31 Python
python测试mysql写入性能完整实例
Jan 18 Python
Django跨域请求问题的解决方法示例
Jun 16 Python
Python脚本按照当前日期创建多级目录
Mar 01 Python
centos7之Python3.74安装教程
Aug 15 Python
python 对任意数据和曲线进行拟合并求出函数表达式的三种解决方案
Feb 18 Python
Python利用FFT进行简单滤波的实现
Feb 26 Python
python矩阵运算,转置,逆运算,共轭矩阵实例
May 11 Python
解决Python3.8运行tornado项目报NotImplementedError错误
Sep 02 Python
python爬虫 requests-html的使用
Nov 30 Python
python把ipynb文件转换成pdf文件过程详解
Jul 09 #Python
深入了解Python枚举类型的相关知识
Jul 09 #Python
Python 的AES加密与解密实现
Jul 09 #Python
python+numpy按行求一个二维数组的最大值方法
Jul 09 #Python
使用Python轻松完成垃圾分类(基于图像识别)
Jul 09 #Python
Python分析彩票记录并预测中奖号码过程详解
Jul 09 #Python
python求最大值,不使用内置函数的实现方法
Jul 09 #Python
You might like
一个简单的PHP投票程序源码
2007/03/11 PHP
php imagecreatetruecolor 创建高清和透明图片代码小结
2010/05/15 PHP
ThinkPHP空模块和空操作详解
2014/06/30 PHP
PHP单元测试配置与使用方法详解
2019/12/27 PHP
Jquery实现三层遍历删除功能代码
2013/04/23 Javascript
Nodejs sublime text 3安装与配置
2014/06/19 NodeJs
jQuery中slideUp()方法用法分析
2014/12/24 Javascript
javascript结合fileReader 实现上传图片
2015/01/30 Javascript
jquery实现相册一下滑动两次的方法
2015/02/09 Javascript
JavaScript实现基于Cookie的存储类实例
2015/04/10 Javascript
jQuery结合AJAX之在页面滚动时从服务器加载数据
2015/06/30 Javascript
jquery实现鼠标滑过显示二级下拉菜单效果
2015/08/24 Javascript
javascript表单事件处理方法详解
2016/05/15 Javascript
AngularJS创建自定义指令的方法详解
2016/11/03 Javascript
JavaScript实现元素滚动条到达一定位置循环追加内容
2017/12/28 Javascript
ajaxfileupload.js实现上传文件功能
2019/04/19 Javascript
JavaScript中的 new 命令
2019/05/22 Javascript
微信小程序登陆注册功能的实现代码
2019/12/10 Javascript
[02:24]DOTA2痛苦女王 英雄基础教程
2013/11/26 DOTA
python通过zlib实现压缩与解压字符串的方法
2014/11/19 Python
python中管道用法入门实例
2015/06/04 Python
人生苦短我用python python如何快速入门?
2018/03/12 Python
Python实现合并同一个文件夹下所有PDF文件的方法示例
2018/04/28 Python
浅谈Python中(&amp;,|)和(and,or)之间的区别
2019/08/07 Python
如何在Python对Excel进行读取
2020/06/04 Python
Python eval函数原理及用法解析
2020/11/14 Python
html5的canvas方法使用指南
2014/12/15 HTML / CSS
奥地利智能家居和智能生活网上商店:tink.at
2019/10/07 全球购物
求职信写作要突出重点
2014/01/01 职场文书
简历的个人自我评价范文
2014/01/03 职场文书
集体婚礼证婚词
2014/01/13 职场文书
爱与责任演讲稿
2014/05/20 职场文书
会员活动策划方案
2014/08/19 职场文书
党干部专题民主生活会对照检查材料思想汇报
2014/10/06 职场文书
不服劳动仲裁起诉书
2015/05/20 职场文书
vue3中的组件间通信
2021/03/31 Vue.js