一、学习背景

垃圾邮件的问题一直困扰着人们,传统的垃圾邮件分类的方法主要有"关键词法"和"校验码法"等,然而这两种方法效果并不理想。其中,如果使用的是“关键词”法,垃圾邮件中如果这个关键词被拆开则可能识别不了,比如,“中奖”如果被拆成“中 --- 奖”可能会识别不了。后来,直到提出了使用“贝叶斯”的方法才使得垃圾邮件的分类达到一个较好的效果,而且随着邮件数目越来越多,贝叶斯分类的效果会更加好。

我们想采用的分类方法是通过多个词来判断是否为垃圾邮件,但这个概率难以估计,通过贝叶斯公式,可以转化为求垃圾邮件中这些词出现的概率。

二、贝叶斯公式

贝叶斯定理 由英国数学家贝叶斯 ( Thomas Bayes 1702-1761 ) 发展,用来描述两个条件 概率 之间的关系

已知两个独立事件A和B,事件B发生的前提下,事件A发生的概率可以表示为P(A|B),即上图中橙色部分占红色部分的比例,即:

  • P(A) 称为”先验概率”,即在B事件发生之前,我们对A事件概率的一个判断。如:正常收到一封邮件,该邮件为垃圾邮件的概率就是“先验概率”

  • P(A|B)称为”后验概率”, 即在B事件发生之后,我们对A事件概率的重新评估。如:邮件中含有“中奖”这个词,该邮件为垃圾邮件的概率就是“后验概率”

  • P(B|A)/P(B)是可能性函数,这是一个调整因子,使得预估概率更接近真实概率。

  • 条件概率就是:后验概率 = 先验概率 x 调整因子

因为要计算两次概率,关于它们的分母,是这个样本的属性在全部样本中的概率。而这两次计算,它们的分母是不变的,所以我们只要计算分子就行。于是有了下面的结论:

即:

朴素贝叶斯分类器(Naïve Bayes Classifier)采用了“属性条件独立性假设”,即每个属性独立地对分类结果发生影响。为方便公式标记,不妨记P(C=c|X=x)为P(c|x)。在假设每个属性都独立的情况下,贝叶斯公式可以修改为:

分母是相同的,于是去掉分母,得:

最终我们利用这个公式,在代码中实现概率的计算来对样本进行分类。

三、使用朴素贝叶斯进行垃圾邮件分类

1.算法思路

分类标准:当 P(垃圾邮件|文字内容)> P(正常邮件|文字内容)时,我们认为该邮件为垃圾邮件,但是单凭单个词而做出判断误差肯定相当大,因此我们可以将所有的词一起进行联合判断。假设我们进行判断的词语有“获奖”、“贷款”、“无利息”,则需要判断P(垃圾邮件|获奖,贷款,无利息)与P(正常|获奖,贷款,无利息),使用贝叶斯公式,P(垃圾邮件|获奖,贷款,无利息)可以变为:

假设所有词语独立同分布,可以得到

同理可得P(正常|获奖,贷款,无利息)

因此,对P(垃圾邮件|获奖,贷款,无利息)与P(正常|获奖,贷款,无利息)的比较,只需要对分子进行对比。

但是如果对多个词的P(内容|正常/垃圾)进行相乘时,可能会因为某个词的概率很小从而导致最后的结果为0(超出计算机的精度),因此可以对P(内容|正常/垃圾)取自然对数,即ln P(内容|正常/垃圾)。

因此可以变为

2.数据集准备

数据来源于国外的一些垃圾邮件和正常邮件

其中ham是正常邮件,spam是垃圾邮件。

3.数据导入

import os
import re
import string
import math
DATA_DIR = 'enron'
target_names = ['ham', 'spam']
def get_data(DATA_DIR):subfolders = ['enron%d' % i for i in range(1,7)] #获得enron下面的文件夹data = []target = []for subfolder in subfolders:#垃圾邮件 spamspam_files = os.listdir(os.path.join(DATA_DIR, subfolder, 'spam')) #将文件夹路径进行组合for spam_file in spam_files: #遍历所有垃圾文件with open(os.path.join(DATA_DIR, subfolder, 'spam', spam_file), encoding="latin-1") as f:data.append(f.read())target.append(1)#正常邮件 pamham_files = os.listdir(os.path.join(DATA_DIR, subfolder, 'ham'))for ham_file in ham_files:with open(os.path.join(DATA_DIR, subfolder, 'ham', ham_file), encoding="latin-1") as f:data.append(f.read())target.append(0)return data, targetX, y = get_data(DATA_DIR)
#print(X,y)

邮件内容存储在data中,标签存储在target当中,“1”表示为垃圾邮件,“0”表示为正常邮件。下图为截取部分结果。

4.分析数据并进行算法训练

定义一个类对数据进行预处理

class SpamDetector_1(object):#清除空格def clean(self, s):translator = str.maketrans("", "", string.punctuation)return s.translate(translator)#分开每个单词def tokenize(self, text):text = self.clean(text).lower()return re.split("\W+", text)#计算某个单词出现的次数def get_word_counts(self, words):word_counts = {}for word in words:word_counts[word] = word_counts.get(word, 0.0) + 1.0return word_counts

计算P(垃圾邮件)和P(正常邮件);词汇表(即正常邮件和垃圾邮件中出现的所有单词,方便进行拉普拉斯平滑);垃圾邮件和非垃圾邮件的词频,即给定词在垃圾邮件和非垃圾邮件中出现的次数。选取了第100封之后的邮件作为训练集,前面一百封邮件作为测试集。

class SpamDetector_2(SpamDetector_1):# X:data,Y:target标签(垃圾邮件或正常邮件)def fit(self, X, Y):self.num_messages = {}self.log_class_priors = {}self.word_counts = {}# 建立一个集合存储所有出现的单词self.vocab = set()# 统计spam和ham邮件的个数self.num_messages['spam'] = sum(1 for label in Y if label == 1)self.num_messages['ham'] = sum(1 for label in Y if label == 0)# 计算先验概率,即所有的邮件中,垃圾邮件和正常邮件所占的比例self.log_class_priors['spam'] = math.log(self.num_messages['spam'] / (self.num_messages['spam'] + self.num_messages['ham']))self.log_class_priors['ham'] = math.log(self.num_messages['ham'] / (self.num_messages['spam'] + self.num_messages['ham']))self.word_counts['spam'] = {}self.word_counts['ham'] = {}for x, y in zip(X, Y):c = 'spam' if y == 1 else 'ham'# 构建一个字典存储单封邮件中的单词以及其个数counts = self.get_word_counts(self.tokenize(x))for word, count in counts.items():if word not in self.vocab:self.vocab.add(word)#确保self.vocab中含有所有邮件中的单词# 下面语句是为了计算垃圾邮件和非垃圾邮件的词频,即给定词在垃圾邮件和非垃圾邮件中出现的次数。# c是0或1,垃圾邮件的标签if word not in self.word_counts[c]:self.word_counts[c][word] = 0.0self.word_counts[c][word] += countMNB = SpamDetector_2()
MNB.fit(X[100:], y[100:])

5.测试算法

对测试集进行测试,判断是垃圾邮件还是正常邮件,并计算出准确度

class SpamDetector(SpamDetector_2):def predict(self, X):result = []flag_1 = 0# 遍历所有的测试集for x in X:counts = self.get_word_counts(self.tokenize(x))  # 生成可以记录单词以及该单词出现的次数的字典spam_score = 0ham_score = 0flag_2 = 0for word, _ in counts.items():if word not in self.vocab: continue#下面计算P(内容|垃圾邮件)和P(内容|正常邮件),所有的单词都要进行拉普拉斯平滑else:# 该单词存在于正常邮件的训练集和垃圾邮件的训练集当中if word in self.word_counts['spam'].keys() and word in self.word_counts['ham'].keys():log_w_given_spam = math.log((self.word_counts['spam'][word] + 1) / (sum(self.word_counts['spam'].values()) + len(self.vocab)))log_w_given_ham = math.log((self.word_counts['ham'][word] + 1) / (sum(self.word_counts['ham'].values()) + len(self.vocab)))# 该单词存在于垃圾邮件的训练集当中,但不存在于正常邮件的训练集当中if word in self.word_counts['spam'].keys() and word not in self.word_counts['ham'].keys():log_w_given_spam = math.log((self.word_counts['spam'][word] + 1) / (sum(self.word_counts['spam'].values()) + len(self.vocab)))log_w_given_ham = math.log( 1 / (sum(self.word_counts['ham'].values()) + len(self.vocab)))# 该单词存在于正常邮件的训练集当中,但不存在于垃圾邮件的训练集当中if word not in self.word_counts['spam'].keys() and word in self.word_counts['ham'].keys():log_w_given_spam = math.log( 1 / (sum(self.word_counts['spam'].values()) + len(self.vocab)))log_w_given_ham = math.log((self.word_counts['ham'][word] + 1) / (sum(self.word_counts['ham'].values()) + len(self.vocab)))# 把计算到的P(内容|垃圾邮件)和P(内容|正常邮件)加起来spam_score += log_w_given_spamham_score += log_w_given_hamflag_2 += 1# 最后,还要把先验加上去,即P(垃圾邮件)和P(正常邮件)spam_score += self.log_class_priors['spam']ham_score += self.log_class_priors['ham']# 最后进行预测,如果spam_score > ham_score则标志为1,即垃圾邮件if spam_score > ham_score:result.append(1)else:result.append(0)flag_1 += 1return result
MNB = SpamDetector()
MNB.fit(X[100:], y[100:])
pred = MNB.predict(X[:100])
true = y[:100]accuracy = 0
for i in range(100):if pred[i] == true[i]:accuracy += 1
print(accuracy) 

最后得到准确率为99%

机器学习--使用朴素贝叶斯进行垃圾邮件分类相关推荐

  1. Python实现基于朴素贝叶斯的垃圾邮件分类 标签: python朴素贝叶斯垃圾邮件分类 2016-04-20 15:09 2750人阅读 评论(1) 收藏 举报 分类: 机器学习(19) 听说

    Python实现基于朴素贝叶斯的垃圾邮件分类 标签: python朴素贝叶斯垃圾邮件分类 2016-04-20 15:09 2750人阅读 评论(1) 收藏 举报  分类: 机器学习(19)  听说朴 ...

  2. 机器学习之朴素贝叶斯实现垃圾邮件过滤

    一.朴素贝叶斯概述 朴素贝叶斯法是基于贝叶斯定理与特征条件独立性假设的分类方法.对于给定的训练集,首先基于特征条件独立假设学习输入输出的联合概率分布(朴素贝叶斯法这种通过学习得到模型的机制,显然属于生 ...

  3. [CS229学习笔记] 5.判别学习算法与生成学习算法,高斯判别分析,朴素贝叶斯,垃圾邮件分类,拉普拉斯平滑

    本文对应的是吴恩达老师的CS229机器学习的第五课.这节课介绍了判别学习算法和生成学习算法,并给出了生成学习算法的一个实例:利用朴素贝叶斯进行垃圾邮件分类. 判别学习(Discriminative L ...

  4. 朴素贝叶斯法 - 垃圾邮件分类

    本文基于朴素贝叶斯构建一个分类垃圾邮件的模型,研究对象是英文的垃圾邮件. 邮件内容保存在txt文件中,其中分为训练样本train和测试样本test. 在训练样本中正常邮件命名为:pos:垃圾邮件命名为 ...

  5. AI基础:朴素贝叶斯与垃圾邮件分类

    来,继续回顾基础算法 文章目录 背景&贝叶斯原理 贝叶斯分类器 朴素贝叶斯分类器 西瓜数据集下的朴素贝叶斯示例 朴素贝叶斯分类的优缺点 朴素贝叶斯关键问题 朴素贝叶斯企业中的应用案例 基于朴素 ...

  6. 朴素贝叶斯(垃圾邮件分类)

    一.基于贝叶斯决策理论的分类方法 朴素贝叶斯是经典的机器学习算法之一,也是为数不多的基于概率论的分类算法.对于大多数的分类算法,在所有的机器学习分类算法中,朴素贝叶斯和其他绝大多数的分类算法都不同.比 ...

  7. 【机器学习】朴素贝叶斯实现垃圾邮件过滤

    朴素贝叶斯法概述 朴素贝叶斯法是基于贝叶斯定理与特征条件独立性假设的分类方法.对于给定的训练集,首先基于特征条件独立假设学习输入输出的联合概率分布(朴素贝叶斯法这种通过学习得到模型的机制,显然属于生成 ...

  8. 机器学习实战之朴素贝叶斯与垃圾邮件分类

    文章目录 一.实现原理 1.1 贝叶斯理论与公式 1.2 朴素贝叶斯分类器 1.3 拉普拉斯修正 1.4 分类小案例 二.代码实现 2.1 数据准备与处理 2.2 创建词汇表 2.3 构建词袋/词集模 ...

  9. 基于朴素贝叶斯的垃圾邮件分类-着重理解拉普拉斯变换

    1. 引言 在正式学习朴素贝叶斯之前,需要明确的是机器学习所要实现的是基于有限的训练样本集尽可能准确地估计出后验概率P(c|x),即根据特征得到所属类别的概率,首先引入两个概念. 判别式模型(disc ...

最新文章

  1. Java反射机制--笔记
  2. 实现if_如何解决开发中 if...esle 代码过多的问题,强烈推荐!
  3. 求首尾相接的数组的最大子数组和
  4. 【学无止境】基于ThinkPHP的OAuth2.0实现 ------ OAuth2.0个人学习笔记 One
  5. 树莓派超声波模块测距
  6. 迭代之嵌套的for循环
  7. JS编程建议——52:建议使用splice删除数组
  8. 运行时修改Standard shader的Mode
  9. 计算机专业基础 -- 数据结构入门与算法基础知识
  10. php获取省市区区划代码,使用PHP解析行政区划代码
  11. 软件开发系统分析规格说明
  12. 智能蓝牙技术原理及设计方案集锦
  13. VS 2008的64位编译环境的安装和使用
  14. 八数码问题c语言,八数码问题的可解性
  15. Android Binder传递文件描述符原理分析
  16. 原来网站上可以这样嵌套动态google地图
  17. 个人的尚学堂数据库oracle笔记(3)
  18. 当年绑架李嘉诚之子后,张子强与李嘉诚对话的细节
  19. 车载网络与计算机网络有什么不同,浅谈汽车车载网络的应用
  20. 数仓和数据中台长期霸权,数据湖最稳

热门文章

  1. TTL(RGB)接口液晶显示屏的调试方法
  2. HDU 5238 Calculator(中国剩余定理+线段树)
  3. ❤️爆肝新一代大数据存储宠儿,梳理了2万字 “超硬核” 文章!❤️
  4. 安卓模拟器绕过模拟器检测正常用电脑玩手机游戏的最好解决方法
  5. vue即时通讯,一个很好用的插件
  6. Android根据图片路径获取图片名字
  7. 右键文件夹提示“No localized file found - emedloc.dll”
  8. Illegal mix of collations (utf8mb4_0900_ai_ci,IMPLICIT) and (utf8mb4_0900_as_ci,IMPLICIT) for operat
  9. 配色表和配色网站:获取好看的配色
  10. python excel动态图表_那些年做过的动态图表-实用漂亮的Excel动态图表