朴素贝叶斯算法识别邮件

垃圾邮件分类:

不管是邮件,还是短信,或者论坛贴吧,我们都会看到类似下面的垃圾信息

卖房的推广信息,信用卡信息,贷款信息等

总之这些对于我们正经人来说,都是垃圾,那我们就要一起设计一个简单的垃圾邮件过滤器。

问题   我们怎么实现垃圾邮件的识别呢??

我们怎么知道这个邮件是垃圾邮件呢?我们的大脑根据什么推断出这封邮件是垃圾文件呢?故此我们需要让计算机去学习这一判断过程。

那我们大脑怎么识别的呢?

最开始,我们自己估计也分不清垃圾邮件,但是看得邮件多了经历多了,我就会发现有些邮件是骗子,是在推销,是在卖假发票,根据什么判断的呢,因为有些词在垃圾邮件中出现的频率明显高,比如:垃圾邮件里,会经常出现发票,赚钱,优惠,折扣,促销的词汇,因为他们的目的性很强,就是为了推广,促销,走货!

而正常邮件里,大多数的词汇,主要用于日常的生活或者工作,像你,我,他,嗯呢,好哒,这些人称代词和日常交流用语比较多,这是因为我们要沟通和表达彼此的状态。

故此我们需要正常划分正常文件和垃圾文件的区别。

数学理论支持:

朴素贝叶斯

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法 。最为广泛的两种分类模型是决策树模型(Decision Tree Model)和朴素贝叶斯模型(Naive Bayesian Model,NBM)。

和决策树模型相比,朴素贝叶斯分类器(Naive Bayes Classifier,或 NBC)发源于古典数学理论,有着坚实的数学基础,以及稳定的分类效率。同时,NBC模型所需估计的参数很少,对缺失数据不太敏感,算法也比较简单。理论上,NBC模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为NBC模型假设属性之间相互独立,这个假设在实际应用中往往是不成立的,这给NBC模型的正确分类带来了一定影响。

对于一个分类问题而言,我们其实只要有条件概率:

就可以预测每个数据点的类别。而朴素贝叶斯就是利用贝叶斯公式计算上述条件概率的模型

我们先写出贝叶斯公式:

显然,如果我们有概率

就可以直接计算出结果了

然而,P(X1,X2,...,Xp|Y=k) 是一个联合分布,即使假设每个自变量都仅有 0 和 1 两个 level,向量 (X1,X2,...,Xp) 也有个 level,是关于 p 的指数函数。如果直接用贝叶斯公式计算会面临数据量不够的问题,因此朴素贝叶斯作了一个关键的假设:特征独立性假设,即假设特征与特征之间是独立的,

在特征独立性假设的条件下,

朴素贝叶斯通过特征独立性假设解决了数据量不足的问题..

 数据来源:博主 算法学习者 (我们先不需要性格好不好这一列)

现在随便给出一个男生(不帅,矮,不上进)求女生嫁与不嫁的概率

最终化简为:

求得即可!!

算法步骤:

引用到我们的垃圾文件当中:

1、从电子邮箱中收集垃圾和非垃圾邮件训练集。

2、读取全部训练集,删除其中的干扰字符,例如*。、,等等,然后分词,删除长度为1的单个字。

3、统计全部训练集中词语的出现次数,截取出现次数最多的前N(可以根据实际情况进行调整)个。

4、根据每个经过第2步预处理后垃圾邮件和非垃圾邮件内容生成特征向量,统计第3步中得到的N个词语分别在本邮件中的出现频率。

5、根据第4步中得到特征向量和已知邮件分类创建并训练朴素贝叶斯模型。

6、读取测试邮件,参考第2步,对邮件文本进行预处理,提取特征向量。

7、使用第5步中训练好的模型,根据第6步提取的特征向量对邮件进行分类。

代码:

数据集准备:

省略....

一共155个文本数据

数据集下载点我!!!!!! (来自网上的数据集)

密码:q369

库导入:

from re import sub
from os import listdir
from collections import Counter 
from itertools import chain
from numpy import array
from jieba import cut
from sklearn. naive_bayes import MultinomialNB

未安装的库请自行安装

例如:jieba库安装:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jieba

完整部分:

#存放所有文件中的单词
#每个元素是一个子列表,其中存放一个文件中的单词
allWords = []
def getWordsFromFile(txtFile):
 words =[]
 with open (txtFile,encoding=' utf8') as fp:
 for line in fp:
 line = line.strip()
#过滤干扰字符或无效字符
 line = sub(r'[ !,-.:;?、。!(),:;?]','',line)
 line = cut (line)
#过滤长度为1的词
 line = filter(lambda word: len(word)>1,line)
 words.extend (line)
 return words
def getTopNWords (topN):
#按文件编号顺序处理当前文件夹中所有记事本文件#共151封邮件内容,0.txt到126.txt是垃圾邮件内容#127.txt到150.txt为正常邮件内容
 txtFiles = ['C:/Users/16941/Desktop/train/'+str(i)+'.txt' for i in range(151)]#获取全部单词
 for txtFile in txtFiles :
 allWords.append(getWordsFromFile(txtFile))#获取并返回出现次数最多的前topN个单词
 freq = Counter(chain(*allWords))
 return [w[0] for w in freq. most_common(topN)]#全部训练集中出现次数最多的前400个单词
topWords = getTopNWords (600)
#获取特征向量,前400个单词的每个单词在每个邮件中出现的频率
vector = []
for words in allWords :
 temp = list (map (lambda x: words.count(x), topWords))
 vector. append(temp)
vector = array (vector)
#邮件标签,1表示垃圾邮件,0表示正常邮件
labels = array ([1]*127 + [0]*24)
#创建模型,使用已知训练集进行训练
model = MultinomialNB()
model.fit(vector,labels)
def predict (txtFile):
#获取指定邮件文件内容,返回分类结果
 words = getWordsFromFile(txtFile)
 currentVector = array(tuple (map (lambda x: words.count(x),topWords)))
 result = model. predict (currentVector. reshape(1,-1))
 return '垃圾邮件' if result==1 else '正常邮件'
print (predict('C:/Users/16941/Desktop/train/135.txt'))
print (predict('C:/Users/16941/Desktop/train/122.txt'))
print (predict('C:/Users/16941/Desktop/train/154.txt'))
print (predict('C:/Users/16941/Desktop/train/150.txt') )
print (predict('C:/Users/16941/Desktop/train/145.txt') )

注意的是代码部分的文件路径要改成自己的才可以!

结果展示:

我们分别打开135和122检测一下:

 

可以看出还是不错的!!

总结:

疑问:为什么要删除干扰符号,一般垃圾文件的干扰奇怪符号比正常邮件多得很!

回答:干扰字符会影响分词效果,当然也可以用干扰字符的数量判断垃圾文件,关键是看你的定义,这里采用的是朴素贝叶斯算法,删除干扰符效果会好一些。

参考:

董付国 Python小屋

作者:Saebomoh原文地址:https://blog.csdn.net/weixin_59997235/article/details/128017463

%s 个评论

要回复文章请先登录注册