【机器学习实战】朴素贝叶斯:过滤垃圾邮件

【机器学习实战】朴素贝叶斯:过滤垃圾邮件

0.收集数据

这里采用的数据集是《机器学习实战》提供的邮件文件,该文件有hamspam 两个文件夹,每个文件夹中各有25条邮件,分别代表着 正常邮件垃圾邮件

这里需要注意的是需要将 email 文件夹放在 py 代码文件同一级的地方。若放在其他地方,需要修改博主代码中的相对地址才可正常执行。
在这里插入图片描述

1.解析数据

我们需要将我们的文本文件导入到程序里面,其中主要参数如下:

  • d o c L i s t : docList: docList 是一个二维数组,一共记录了50封邮件的内容。
  • f u l l T e x t : fullText: fullText是50封邮件中出现的所有单词的一个大的单词列表(有重复单词)
  • c l a s s L i s t : classList: classList用于记录当前邮件是 正常邮件 还是 垃圾邮件01 进行区分。
  • v o c a b L i s t : vocabList : vocabList是一个单词均不重复的词汇表。
# 导入并解析文本文件for i in range(1, 26):  # 因为每个文件夹各有文件25个wordList = textParse(open('email/spam/%d.txt' % i, encoding="ISO-8859-1").read())  # 读取文件docList.append(wordList)  # 用于存储所有文件的单词列表,二维数组fullText.extend(wordList)  # 这个列表用于存储所有文件的单词,将它们合并成一个大的单词列表classList.append(1)wordList = textParse(open('email/ham/%d.txt' % i, encoding="ISO-8859-1").read())docList.append(wordList)fullText.extend(wordList)classList.append(0)vocabList = createVocabList(docList)  # 创建不重复的词汇表# 邮件裁词
def textParse(bigString):regEx = re.compile(r'\W')listOfTokens = regEx.split(bigString)var = [tok.lower() for tok in listOfTokens if len(tok) > 2]  # 只返回长度大于2的情况return var# 创建词汇表
def createVocabList(dataSet):vocabSet = set([])  # 创建一个无序且不重复的集合对象for document in dataSet:vocabSet = vocabSet | set(document)  # 创建两个集合的并集return list(vocabSet)

ps:因为这里的邮件全是英文邮件,所以读取的时候编码是 encoding="ISO-8859-1"

2.区分“测试集”和“训练集”

这里我们一共创建了10个测试集,每取一个测试集就将其的索引从trainingSet 中删除。故trainingSet 最后剩下的40个索引就是训练集,testSet中的10个索引就是测试集。

  • 测试集:用于判断朴素贝叶斯分类是否有问题。
  • 训练集:用于训练朴素贝叶斯分类器的参数。
	trainingSet = list(range(50))  # 训练集的索引,0-49(因为ham和spam各有25个,故一共有50个)trainingSet = trainingSettestSet = []# 随机构造训练集for i in range(10):  # 表示只创建10个测试集、剩下的都是训练集# 函数生成一个0到len(trainingSet)之间的随机浮点数,然后取整,得到一个随机的索引值randIndex。randIndex = int(random.uniform(0, len(trainingSet)))testSet.append(trainingSet[randIndex])  # 将随机选择的索引值randIndex添加到测试集列表testSet中。trainingSet.pop(randIndex)  # 删除训练集中对应的测试集的索引值,以确保不会重复选择作为测试集。

3.训练算法

朴素贝叶斯算法往简单说,就是计算出当前参数为不同情况的概率,最后哪个可能性的概率大,那么他就是哪一类。

3.1 统计词汇出现的次数

# 朴素贝叶斯词袋模型
def bagOfWords2VecMN(vocabList, inputSet):returnVec = [0] * len(vocabList)  # 创建一个长度为vocabList的列表returnVec,并将列表中的每个元素都初始化为0for word in inputSet:if word in vocabList:returnVec[vocabList.index(word)] += 1  # 在词库里出现次数return returnVec

3.2.训练函数

将各个邮件中词汇出现次数的词袋,和最初记录每个邮件是 正常邮件 还是 垃圾邮件 的列表传入trainNB0计算出每个词汇是正常还是垃圾的可能性。

# 朴素贝叶斯分类器训练函数
def trainNB0(trainMatrix, trainCategory):numTrainDocs = len(trainMatrix)numWords = len(trainMatrix[0])pAbusive = sum(trainCategory) / float(numTrainDocs)  # 侮辱性单词出现的概率p0Num = ones(numWords)  # 为了防止出现 0 * x 的情况p1Num = ones(numWords)p0Denom = 2.0  # 为了防止分母为0的情况p1Denom = 2.0for 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)  # log是为了防止数据太小导致下溢出return p0Vect, p1Vect, pAbusive

3.3分类器

根据我们确定的计算概率公式,计算出它各个分类的可能性然后进行比较,返回我们最好的决定。

# 朴素贝叶斯分类函数
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):p1 = sum(vec2Classify * p1Vec) + log(pClass1)p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)if p1 > p0:return 1else:return 0

4.完整代码

import re
from numpy import *# 创建词汇表
def createVocabList(dataSet):vocabSet = set([])  # 创建一个无序且不重复的集合对象for document in dataSet:vocabSet = vocabSet | set(document)  # 创建两个集合的并集return list(vocabSet)# 朴素贝叶斯词袋模型 setOfWords2Vec 升级版本
def bagOfWords2VecMN(vocabList, inputSet):returnVec = [0] * len(vocabList)  # 创建一个长度为vocabList的列表returnVec,并将列表中的每个元素都初始化为0for 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])pAbusive = sum(trainCategory) / float(numTrainDocs)  # 侮辱性单词出现的概率p0Num = ones(numWords)  # 为了防止出现 0 * x 的情况p1Num = ones(numWords)p0Denom = 2.0  # 为了防止分母为0的情况p1Denom = 2.0for 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)  # log是为了防止数据太小导致下溢出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 1else:return 0# 邮件裁词
def textParse(bigString):regEx = re.compile(r'\W')listOfTokens = regEx.split(bigString)var = [tok.lower() for tok in listOfTokens if len(tok) > 2]  # 只返回长度大于2的情况return vardef spamTest():docList = []classList = []fullText = []# 导入并解析文本文件for i in range(1, 26):  # 因为每个文件夹各有文件25个wordList = textParse(open('email/spam/%d.txt' % i, encoding="ISO-8859-1").read())  # 读取文件docList.append(wordList)  # 用于存储所有文件的单词列表,二维数组fullText.extend(wordList)  # 这个列表用于存储所有文件的单词,将它们合并成一个大的单词列表classList.append(1)wordList = textParse(open('email/ham/%d.txt' % i, encoding="ISO-8859-1").read())docList.append(wordList)fullText.extend(wordList)classList.append(0)vocabList = createVocabList(docList)  # 创建不重复的词汇表trainingSet = list(range(50))  # 训练集的索引,0-49(因为ham和spam各有25个,故一共有50个)trainingSet = trainingSettestSet = []# 随机构造训练集for i in range(10):  # 表示只创建10个测试集、剩下的都是训练集# 函数生成一个0到len(trainingSet)之间的随机浮点数,然后取整,得到一个随机的索引值randIndex。randIndex = int(random.uniform(0, len(trainingSet)))testSet.append(trainingSet[randIndex])  # 将随机选择的索引值randIndex添加到测试集列表testSet中。trainingSet.pop(randIndex)  # 删除训练集中对应的测试集的索引值,以确保不会重复选择作为测试集。trainMat = []trainClasses = []for docIndex in trainingSet:# 将选中的训练集索引的文本,和词汇表进行对比计算词汇出现的次数trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))trainClasses.append(classList[docIndex])  # 将文档的类别标签添加到trainClasses列表中# 调用trainNB0函数,传入训练数据的特征向量和类别标签,进行朴素贝叶斯训练,得到分类器的参数p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))errorCount = 0  # 计算错误次数,初始值为0# 对测试集分类for docIndex in testSet:wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])  # 计算出现次数if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:  # 计算结果并判断是否判断正确errorCount += 1print("classification error", docList[docIndex])print('the error rate is: ', float(errorCount) / len(testSet))if __name__ == '__main__':spamTest()

结果截图:
在这里插入图片描述

5.总结

个人感觉该方法的分类准确率,对准备的数据以及概率计算方法很敏感,可能一点点的改变就会导致最后的统计结果天差地别。总的来说,朴素贝叶斯并不难,代码也相对比较好理解,这一章就顺利通过啦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/45459.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【校招VIP】java语言考点之List和扩容

考点介绍: List是最基础的考点,但是很多同学拿不到满分。本专题从两种实现子类的比较,到比较复杂的数组扩容进行分析。 『java语言考点之List和扩容』相关题目及解析内容可点击文章末尾链接查看!一、考点题目 1、以下关于集合类…

vue技术学习

vue快速入门 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>vue快速入门</title> </head> <body> <!--老师解读 1. div元素不是必须的&#xff0c;也可以是其它元素&#xff0…

操作系统——操作系统内存管理基础

文章目录 1.内存管理介绍2.常见的几种内存管理机制3.快表和多级页表快表多级页表总结 4.分页机制和分段机制的共同点和区别5.逻辑(虚拟)地址和物理地址6.CPU 寻址了解吗?为什么需要虚拟地址空间? 1.内存管理介绍 操作系统的内存管理主要是做什么&#xff1f; 操作系统的内存…

Apache DolphinScheduler 支持使用 OceanBase 作为元数据库啦!

DolphinScheduler是一个开源的分布式任务调度系统&#xff0c;拥有分布式架构、多任务类型、可视化操作、分布式调度和高可用等特性&#xff0c;适用于大规模分布式任务调度的场景。目前DolphinScheduler支持的元数据库有Mysql、PostgreSQL、H2&#xff0c;如果在业务中需要更好…

要跟静音开关说再见了!iPhone15新变革,Action按钮引领方向

有很多传言称iPhone 15 Pro会有很多变化&#xff0c;但其中一个变化可能意味着iPhone体验从第一天起就有的一项功能的终结。我说的是静音开关&#xff0c;它可以让你轻松地打开或关闭iPhone的铃声。 根据越来越多的传言&#xff0c;iPhone 15 Pro和iPhone 15 Pro Max将拆除静音…

基于.Net Core开发的医疗信息LIS系统源码

SaaS模式.Net Core版云LIS系统源码 医疗信息LIS系统是专为医院检验科设计的一套实验室信息管理系统&#xff0c;能将实验仪器与计算机组成网络&#xff0c;使病人样品登录、实验数据存取、报告审核、打印分发&#xff0c;实验数据统计分析等繁杂的操作过程实现了智能化、自动化…

【Git】(四)子模块

1、增加子模块 进入准备添加子模块所在的目录&#xff0c;例如library。 git submodule add -b 1.0.0.0 gitgitee.com:sunriver2000/SubModule.git参数-b用于指定子模块分支。 2、更新子模块 git submodule update --progress --init --recursive --force --remote -- "…

初出茅庐的小李博客之STM32CubeMx配置定时器的编码器模式

STM32CubeMx配置定时器的编码器模式 上次文章写了编码器是如何工作的&#xff0c;今天就来用STM32F103C8T6的TIM3的通道1跟通道2编写一个编码器识别程序。 编程思路&#xff1a; A相:TIM3_CH1 B相:TIM3_CH2 SWITCH:PB5&#xff08;外部中断的方式&#xff09; 实现效果&a…

STM32 串口复习

按数据通信方式分类&#xff1a; 串行通信&#xff1a;数据逐位按顺序依次传输。传输速率较低&#xff0c;抗干扰能力较强&#xff0c;通信距离较长&#xff0c;I/O资源占用较少&#xff0c;成本较低。并行通信&#xff1a;数据各位通过多条线同时传输。 按数据传输方向分类&…

Django进阶:DRF(Django REST framework)

什么是DRF&#xff1f; DRF即Django REST framework的缩写&#xff0c;官网上说&#xff1a;Django REST framework是一个强大而灵活的工具包&#xff0c;用于构建Web API。 简单来说&#xff1a;通过DRF创建API后&#xff0c;就可以通过HTTP请求来获取、创建、更新或删除数据(…

linux vscode 下开发

linux vscode 下开发 javajdk插件查看调用层次 java jdk 各种JAVA JDK的镜像分发 编程宝库 - 技术改变世界 jdk 镜像 ubuntu22.04 安装 # Linux x64 64位 jdk-8u351-linux-x64.tar.gztar -zxf jdk-8u351-linux-x64.tar.gz mv jdk1.8.0_351 jdk8/ vim ~/.pr…

Java并发编程之线程池详解

目录 &#x1f433;今日良言:不悲伤 不彷徨 有风听风 有雨看雨 &#x1f407;一、简介 &#x1f407;二、相关代码 &#x1f43c;1.线程池代码 &#x1f43c;2.自定义实现线程池 &#x1f407;三、ThreadPoolExecutor类 &#x1f433;今日良言:不悲伤 不彷徨 有风听风 有…

【汇编语言】关于“段”的总结

文章目录 各种段三种段具体案例截图数据段、栈段、代码段同时使用不同段地址数据段、栈段、代码段同时使用一个段地址![在这里插入图片描述](https://img-blog.csdnimg.cn/45c299950ad949e3a90b7ed012b3a9ee.png) 各种段 1、基础 物理地址 段地址 x 16 偏移地址 2、做法 编…

【数据结构】双链表

链表&#xff08;二&#xff09; 文章目录 链表&#xff08;二&#xff09;00 引入01 类的搭建02 得到链表的长度03 打印链表04 查找是否包含关键字key是否在链表当中05 头插法06 尾插法07 任意位置插入08 删除关键字为key的节点09 删除所有值为key的节点10 清空11 LinkedList常…

leetcode 198. 打家劫舍

2023.8.19 打劫问题是经典的动态规划问题。先设一个dp数组&#xff0c;dp[i]的含义为&#xff1a;前 i 个房屋能盗取的最高金额。 每间房屋无非就是偷&#xff0c;或者不偷这两种情况&#xff0c;于是可以写出递推公式&#xff1a; …

LeetCode235. 二叉搜索树的最近公共祖先

235. 二叉搜索树的最近公共祖先 文章目录 [235. 二叉搜索树的最近公共祖先](https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/)一、题目二、题解方法一&#xff1a;递归方法二&#xff1a;迭代 一、题目 给定一个二叉搜索树, 找到该树中两个指定…

依赖预构建与静态资源处理

依赖预构建 vite是一个基于浏览器原生ES-Module的前端构建工具。 当你首次启动vite的时候&#xff0c;vite会在本地加载你的站点之前预构建项目依赖。 原因&#xff1a; CommonJS和UMD兼容性&#xff1a;在开发阶段中&#xff0c;Vite的开发服务器将所有的代码视为原生ES模块。…

浅谈日常使用的 Docker 底层原理-三大底座

适合的读者&#xff0c;对Docker有过简单了解的朋友&#xff0c;想要进一步了解Docker容器的朋友。 前言 回想我这两年&#xff0c;一直都是在使用 Docker&#xff0c;看过的视频、拜读过的博客&#xff0c;大都是在介绍 Docker 的由来、使用、优点和发展趋势&#xff0c;但对…

VMWare Workstation 17 Pro 网络设置 桥接模式 网络地址转换(NAT)模式 仅主机模式

文章目录 网络模式配网要求CentOSDHCP虚拟网络桥接模式默认配置测试手动配置测试 网络地址转发模式 (NAT)还原配置虚拟网络配置默认配置测试手动配置测试 仅主机模式 网络模式 桥接模式: 主机与虚拟机对等, 虚拟机注册到主机所在的局域网, 会占用该网络的IP该局域网内的所有机…

简单认识镜像底层原理详解和基于Docker file创建镜像

文章目录 一、镜像底层原理1.联合文件系统(UnionFS)2.镜像加载原理3.为什么Docker里的centos的大小才200M? 二、Dockerfile1.简介2.Dockerfile操作常用命令 三、创建Docker镜像1.基于已有镜像创建2.基于本地模板创建3.基于Dockerfile创建4.Dockerfile多阶段构建镜像 一、镜像底…