首页 > 编程语言 >基于朴素贝叶斯算法实现垃圾邮件分类

基于朴素贝叶斯算法实现垃圾邮件分类

时间:2022-12-21 22:33:29浏览次数:42  
标签:vocabList append 贝叶斯 算法 垃圾邮件 邮件 trainMatrix

一、背景
垃圾邮件的问题一直困扰着人们,传统的垃圾邮件分类的方法主要有"关键词法"和"校验码法"等,然而这两种方法效果并不理想。其中,如果使用的是“关键词”法,垃圾邮件中如果这个关键词被拆开则可能识别不了,比如,“中奖”如果被拆成“中奖”可能会识别不了。后来,直到提出了使用“贝叶斯”的方法才使得垃圾邮件的分类达到一个较好的效果,而且随着邮件数目越来越多,贝叶斯分类的效果会更加好。
我们想采用的分类方法是通过多个词来判断是否为垃圾邮件,但这个概率难以估计,通过贝叶斯公式,可以转化为求垃圾邮件中这些词出现的概率。

二、贝叶斯公式的介绍
贝叶斯定理由英国数学家贝叶斯 ( Thomas Bayes 1702-1761 ) 发展,用来描述两个条件概率之间的关系,比如 P(A|B) 和 P(B|A)。
(1)条件概率公式
设A,B是两个事件,且P(B)>0,则在事件B发生的条件下,事件A发生的条件概率为:
P(A|B) = P(AB)/P(B)
(2)由条件概率公式得出乘法公式: P(AB)=P(A|B)P(B)=P(B|A)P(A)
P(A|B) = P(AB)/P(B)可变形为:
可以这样来看贝叶斯公式:
P(A) 称为”先验概率”,即在B事件发生之前,我们对A事件概率的一个判断。如:正常收到一封邮件,该邮件为垃圾邮件的概率就是“先验概率”
P(A|B)称为”后验概率”, 即在B事件发生之后,我们对A事件概率的重新评估。如:邮件中含有“中奖”这个词,该邮件为垃圾邮件的概率就是“后验概率”
(3)全概率公式:
全概率公式的意义在于,当直接计算P(A)较为困难,而P(Bi), P(A|Bi) (i=1,2,...)的计算较为简单时,可以利用全概率公式计算P(A)。

三、系统设计
(1)收集数据集和设置训练集和测试集数量:
先搜寻有关垃圾邮件的数据集,其中含有垃圾邮件和非垃圾邮件的数据集,按照题目要求,我从中选取了10份正常邮件和6份垃圾邮件作为训练集,选择了8份邮件作为测试集(邮件文件名小于10的是正常邮件,大于10的是垃圾邮件)
(2)对训练集使用enron进行分词,并且要用中文停用表进行简单的过滤,然后再使用正则表达式过滤邮件中的非中文字符
(3)建立词袋子模型(词语之间没有固定顺序):构成一个正常邮件组和垃圾邮件组的没有重复的词频字典,即每个词语的词频表示为正常邮件与垃圾邮件中该词语出现的次数。
(4)所以筛选出前一些个出现频率高的词语作正常邮件组和垃圾邮件组的特征词向量来表示正常邮件和垃圾邮件。
(5)测试集的每一封邮件也需要做同样的处理,通过计算每个邮件的p(s/w)来得到对分类影响最大的一些个词语。当测试集中的词语同时出现在垃圾邮件词典和正常邮件词典中,我们就需要计算 ,这表示测试集出现词时,它是垃圾邮件的概率;
当测试集的词语只出现在正常邮件词典中,而没有出现在垃圾邮件的词典中,此时设,不将其设置为0的原因是为了防止时,再计算贝叶斯公式概率是会使得整个概率变成0,朴素贝叶斯方法失效,最后如果测试集的词语既不出现在垃圾邮件词典中,也不出现在正常邮件词典中时,我就将因为它暂时无法其是垃圾邮件还是正常邮件,所以我就将其设置为判断垃圾邮件或者非垃圾邮件的概率临界点的值。计算之后得到了对测试集邮件中重要的那些个词语是否为垃圾邮件的对应着“词语”。
(6)最后对得到的词利用2式的核心公式计算贝叶斯概率,如果P>阈值ɑ(我将其设置为0.6),则判定为垃圾邮件,否则则判定为正常邮件。
(7)最后根据其判断结果的正确的个数,计算模型的正确率。同时还可以计算出模型的准确率和召回率。
从中可以发现正常邮件和垃圾邮件中的经常出现的词语是大不相同的,所以可以根据垃圾邮件和正常邮件中出现词语的频率作为垃圾邮件分类的标准。

四、实现
1.准备数据



2.向量的转换实现
def loadDataSet():
postingList = [['stop', 'posting', 'stupid', 'worthless', 'garbage'],
['maybe', 'not', 'take', 'him', 'to', 'dog'],
['my', 'dalmation', 'cute', 'I', 'love', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid'],
['steak', 'how', 'to', 'stop', 'him','mr', 'licks', 'ate', 'my' ]]
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:
if word in vocabList:
returnVec[vocabList.index(word)] = 1 # 若出现了单词表中的单词,则将对应值设置为1
else:
print("单词:%s 不存在!" % word)
return returnVec

测试函数效果

创建实验样本

listPosts, listClasses = loadDataSet()
print('数据集\n', listPosts)

创建词汇表

myVocabList = createVocabList(listPosts)
print('词汇表:\n', myVocabList)

输出文档向量

print(setOfwords2Vec(myVocabList, listPosts[4]))
结果:

3.定义函数,词袋模型,切分文本

训练朴素贝叶斯分类器

def trainNB0(trainMatrix, trainCategory):
# 获得训练文档总数
numTrainDocs = len(trainMatrix)
# 计算每篇文档的词总数
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory) / float(numTrainDocs)
p0Num = zeros(numWords)
p1Num = zeros(numWords)
p0Denom = 0.0
p1Denom = 0.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
# 向量相加,统计侮辱类的条件概率,即p(w0|1),p(w1|1),p(w2|1)..
p1Num += trainMatrix[i]
# 累加每篇文档的总词量
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = p1Num / p1Denom
p0Vect = p0Num / p0Denom
return p0Vect, p1Vect, pAbusive

训练朴素贝叶斯分类器

def trainNB0(trainMatrix, trainCategory):
# 获得训练文档总数
numTrainDocs = len(trainMatrix)
# 计算每篇文档的词总数
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory) / float(numTrainDocs)
p0Num = zeros(numWords)
p1Num = zeros(numWords)
p0Denom = 0.
p1Denom = 0.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
# 向量相加,统计侮辱类的条件概率,即p(w0|1),p(w1|1),p(w2|1)..
p1Num += trainMatrix[i]
# 累加每篇文档的总词量
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = p1Num / p1Denom
p0Vect = p0Num / p0Denom
return p0Vect, p1Vect, pAbusive

def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
p1=sum(vec2Classifyp1Vec)+log(pClass1)
p0=sum(vec2Classify
p0Vec)+log(1.0-pClass1)
if p1>p0:#比较类别概率
return 1
else:
return 0

def bagOfWords2VecMN(vocabList, inputSet): # 词袋模型
returnVec = [0] * len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec

def textParse(bigString): # 切分文本
import re
listOfTokens = re.split(r'\W+', bigString)
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
五、测试集
构建测试集进行测试

垃圾邮件测试

def spamTest():
docList = []
classList = []
fullText = []
for i in range(1, 26):
wordList = textParse(open('E:/pycode/homework/email/spam/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1) # 将垃圾邮件标记为1
wordList = textParse(open('E:/pycode/homework/email/ham/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0) # 将正常邮件标记为0
vocabList = createVocabList(docList)
trainingSet = list(range(50))
testSet = []
for i in range(10):
randIndex = int(random.uniform(0, len(trainingSet)))
testSet.append(trainingSet[randIndex])
del (trainingSet[randIndex])
trainMat = []
trainClasses = []
for docIndex in trainingSet: # 遍历训练集
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V, p1V, pSpam = trainNB1(array(trainMat), array(trainClasses))

print('词表:\n', vocabList)
print('p0v:\n', p0V)
print('p1v:\n', p1V)
print('pSpam:\n', pSpam)

errorCount = 0
for docIndex in testSet:  # 遍历测试集
    wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
    if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
        errorCount += 1
        print('分类错误集', docList[docIndex])
print('错误率:', float(errorCount) / len(testSet))  # 计算错误率
return float(errorCount) / len(testSet)

spamTest()
结果:

六、对垃圾邮件进行分类

邮件分类器

def classifyEmail():
docList = [] # 文档列表
classList = [] # 文档标签
fullText = [] # 全部文档内容集合
for i in range(1, 26): # 遍历垃圾邮件和非垃圾邮件各25个
wordList = textParse(open('E:/pycode/homework/email/spam/%d.txt' % i).read()) # 读取垃圾邮件,将大字符串并将其解析为字符串列表
docList.append(wordList) # 垃圾邮件加入文档列表
fullText.extend(wordList) # 把当前垃圾邮件加入文档内容集合
classList.append(1) # 1表示垃圾邮件,标记垃圾邮件
wordList = textParse(open('E:/pycode/homework/email/ham/%d.txt' % i).read()) # 读非垃圾邮件,将大字符串并将其解析为字符串列表
docList.append(wordList) # 非垃圾邮件加入文档列表
fullText.extend(wordList) # 把当前非垃圾邮件加入文档内容集合
classList.append(0) # 0表示垃圾邮件,标记非垃圾邮件,

vocabList = createVocabList(docList)  # 创建不重复的词汇表
trainingSet = list(range(50))  # 为训练集添加索引
trainMat = []  # 创建训练集矩阵训练集类别标签系向量
trainClasses = []  # 训练集类别标签
for docIndex in trainingSet:  # for循环使用词向量来填充trainMat列表
    trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))  # 把词集模型添加到训练矩阵中
    trainClasses.append(classList[docIndex])  # 把类别添加到训练集类别标签中
p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))  # 朴素贝叶斯分类器训练函数

testList = textParse(open('E:/pycode/homework/email/test/2.txt').read())  # 读取邮件,将大字符串并将其解析为字符串列表
testVector = bagOfWords2VecMN(vocabList, testList)  # 获得测试集的词集模型
if classifyNB(array(testVector), p0V, p1V, pSpam):
    result = "垃圾邮件"
else:
    result = "正常邮件"
print("输入邮件内容为: ")
print(' '.join(testList))
print('该邮件被分类为: ', result)


标签:vocabList,append,贝叶斯,算法,垃圾邮件,邮件,trainMatrix
From: https://www.cnblogs.com/lh123456789/p/16997386.html

相关文章

  • [机器学习] t-SNE聚类算法实践指南
    ​ 转载于比PCA降维更高级——(R/Python)t-SNE聚类算法实践指南-阿里云开发者社区作者介绍:Saurabh.jaju2  Saurabh是一名数据科学家和软件工程师,熟练分析各种数据集和......
  • 【算法实践】他山之石,可以攻玉--利用完全二叉树快速实现堆排序
    前言什么是堆堆是一种数据结构,它是完全二叉树或者是近似完全二叉树的一种数据结构,树中每个结点的值都不小于(或不大于)其左右孩子结点的值。何为完全二叉树完全二叉树是一种......
  • 一文看懂什么递归(算法小结)
    前言递归是算法中一种非常重要的思想,应用也很广,小到阶乘,再在工作中用到的比如统计文件夹大小,大到Google的PageRank算法都能看到,也是面试官很喜欢的考点最近看了不少......
  • 一、贝叶斯回归_numpy实现
    importnumpyasnpfromscipy.statsimportchi2,multivariate_normalfromutils.data_metricsimportmean_squared_errorfromutils.data_manipulationimporttra......
  • 算法-如何理解递归,写好递归函数
    不是每个程序员天生对递归理解深刻,刚入大一时候,当别人写出第一个求最大公约数的递归函数时,对其多么的惊叹,竟然可以不用循环,竟然代码可以这么简洁,确实递归在大多数情况下实......
  • PyTorch 深度学习实践(梯度下降算法)
    梯度下降上课代码importnumpyasnpimportmatplotlib.pyplotaspltx_data=[1.0,2.0,3.0]y_data=[2.0,4.0,6.0]w=1.0defforward(x):returnx*wdefcost(xs,y......
  • 一文看懂:MD5、AES和RSA算法这三者之间的区别
    在计算机安全领域,MD5、AES和RSA算法的应用比较广泛,它们可用来避免密码明文传输的漏洞危害。但是,这3种算法有什么区别呢?什么是MD5MD5信息摘要算法,一种被广泛使用的密码散列函......
  • 一文看懂:MD5、AES和RSA算法这三者之间的区别
    在计算机安全领域,MD5、AES和RSA算法的应用比较广泛,它们可用来避免密码明文传输的漏洞危害。但是,这3种算法有什么区别呢?什么是MD5MD5信息摘要算法,一种被广泛使用的密码散列函......
  • 一文看懂:MD5、AES和RSA算法这三者之间的区别
    在计算机安全领域,MD5、AES和RSA算法的应用比较广泛,它们可用来避免密码明文传输的漏洞危害。但是,这3种算法有什么区别呢?什么是MD5MD5信息摘要算法,一种被广泛使用的密码散列......
  • R语言Gibbs抽样的贝叶斯简单线性回归仿真分析|附代码数据
    全文下载链接:http://tecdat.cn/?p=4612最近我们被客户要求撰写关于Gibbs抽样的研究报告,包括一些图形和统计输出。贝叶斯分析的许多介绍都使用了相对简单的教学实例(例如,根......