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中的strftime()方法的使用
May 22 Python
Python中运算符&quot;==&quot;和&quot;is&quot;的详解
Oct 08 Python
Python的CGIHTTPServer交互实现详解
Feb 08 Python
对python程序内存泄漏调试的记录
Jun 11 Python
selenium+python设置爬虫代理IP的方法
Nov 29 Python
Python中类的创建和实例化操作示例
Feb 27 Python
10招!看骨灰级Pythoner玩转Python的方法
Apr 15 Python
Django ORM 常用字段与不常用字段汇总
Aug 09 Python
python logging添加filter教程
Dec 24 Python
python opencv 图像边框(填充)添加及图像混合的实现方法(末尾实现类似幻灯片渐变的效果)
Mar 09 Python
Python搭建Keras CNN模型破解网站验证码的实现
Apr 07 Python
在django admin中配置搜索域是一个外键时的处理方法
May 20 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中单个数据库字段多列显示(单字段分页、横向输出)
2014/07/28 PHP
mac系统下为 php 添加 pcntl 扩展
2016/08/28 PHP
PHP实现的简单留言板功能示例【基于thinkPHP框架】
2018/12/07 PHP
jquery.combobox中文api和例子,修复了上面的小bug
2011/03/28 Javascript
flash调用js中的方法,让js传递变量给flash的办法及思路
2013/08/07 Javascript
javascript表单验证使用示例(javascript验证邮箱)
2014/01/07 Javascript
js实现Select列表内容自动滚动效果代码
2015/08/20 Javascript
Ext JS动态加载JavaScript创建窗体的方法
2016/06/23 Javascript
完全深入学习Bootstrap表单
2016/11/28 Javascript
bootstrap为水平排列的表单和内联表单设置可选的图标
2017/02/15 Javascript
Javascript实现登录记住用户名和密码功能
2017/03/22 Javascript
Vue.js中的组件系统
2019/05/30 Javascript
vuex vue简单使用知识点总结
2019/08/29 Javascript
微信小程序如何实现radio单选框单击打勾和取消
2020/01/21 Javascript
JavaScript实现HSL拾色器
2020/05/21 Javascript
js实现滚动条自动滚动
2020/12/13 Javascript
Python中使用haystack实现django全文检索搜索引擎功能
2017/08/26 Python
分析python动态规划的递归、非递归实现
2018/03/04 Python
对python中的pop函数和append函数详解
2018/05/04 Python
python图的深度优先和广度优先算法实例分析
2019/10/26 Python
浅谈cv2.imread()和keras.preprocessing中的image.load_img()区别
2020/06/12 Python
html5使用canvas实现跟随光标跳动的火焰效果
2014/01/07 HTML / CSS
SQL数据库笔试题
2016/03/08 面试题
如果让你测试一台高速激光打印机,你都会进行哪些测试
2012/12/04 面试题
超市开业庆典活动策划方案
2014/09/15 职场文书
初中教师个人工作总结
2015/02/10 职场文书
2014年底个人工作总结
2015/03/10 职场文书
2015年小学中秋节活动总结
2015/03/23 职场文书
MBA推荐信怎么写
2015/03/25 职场文书
道歉情书大全
2015/05/12 职场文书
2016大学生优秀志愿者事迹材料
2016/02/25 职场文书
个人售房合同协议书
2016/03/21 职场文书
一篇文章弄懂MySQL查询语句的执行过程
2021/05/07 MySQL
使用Python拟合函数曲线
2022/04/14 Python
处理canvas绘制图片模糊问题
2022/05/11 Javascript
Win10服务全部禁用了怎么启动?Win10服务全部禁用解决方法
2022/09/23 数码科技