朴素贝叶斯——垃圾邮件过滤

news2025/1/25 4:39:15

文章目录

  • 利用朴素贝叶斯进行文档分类
    • 1、获取数据集
    • 2、切分文本
    • 3、构建词表和分类
    • 4、构建分类器
    • 5、测试算法
  • 利用朴素贝叶斯进行垃圾邮件过滤
    • 1、导入数据集
    • 2、垃圾邮件预测
  • 总结

利用朴素贝叶斯进行文档分类

1、获取数据集

下载数据集,获取到一些邮件文档。其中ham文件夹下都是正常邮件,spam下都是垃圾邮件。
在这里插入图片描述
数据集中将一些词组用空格分开,方便后面分割词组,统计词表。
在这里插入图片描述

2、切分文本

每一份邮件里面用空格键分割出很多的词组,需要将这些词组分割出来,放在一个词表里面。

def cut_sentences(content):   # 实现分句的函数,content参数是传入的文本字符串
    end_flag = ['?', '!', '.', '?', '!', '。', ' ']   # 结束符号,包含中文和英文的
    content_len = len(content)
    sentences = []   # 存储每一个句子的列表
    tmp_char = ''
    for idx, char in enumerate(content):
        tmp_char += char   # 拼接字符
        if (idx + 1) == content_len:   # 判断是否已经到了最后一位
            sentences.append(tmp_char.strip().replace('\ufeff', ''))
            break
        if char in end_flag:   # 判断此字符是否为结束符号
            # 再判断下一个字符是否为结束符号,如果不是结束符号,则切分句子
            next_idx = idx + 1
            if not content[next_idx] in end_flag:
                sentences.append(tmp_char.strip().replace('\ufeff', ''))
                tmp_char = ''
    sentences = list(set(sentences))
    return  [tok for tok in sentences if len(tok) > 1]

words = cut_sentences(open('TrainingSet/Ham/{}.txt'.format(2)).read())
print(words)

例如分割好一份邮件后,可以得到一个词表
在这里插入图片描述

3、构建词表和分类

下面方法中,posting_list 存放着每一个邮件的词表,class_vec 里面存放对应下标词表的类别,1代表友好文件,0代表不友好文件。最后返回一个词表的列表,和一个类别的列表。

# 获取词表和对应类别
def load_data_set():
    # 词表和对应类别
    posting_list = []
    class_vec = []
    for i in range(2, 10):
        # 获取友好邮件词表
        words = cut_sentences(open('TrainingSet/Ham/{}.txt'.format(i)).read())
        posting_list.append(words)
        class_vec.append(1)
        # 获取不友好邮件词表
        words = cut_sentences(open('TrainingSet/Spam/{}.txt'.format(i)).read())
        posting_list.append(words)
        class_vec.append(0)
    return posting_list, class_vec

在这里插入图片描述
create_vocab_list方法会将load_data_set返回的词表列表合并成一个大的词表,里面每一个词组输给Set函数后,set会返回一个不重复的大词表。

# 合并所有词表
def create_vocab_list(data_set):
    vocab_set = set() 
    for item in data_set:
        # | 求两个集合的并集
        vocab_set = vocab_set | set(item)
    return list(vocab_set)
print(create_vocab_list(posting_list))

通过上面create_vocab_list方法可以返回一个包含所有词汇的大词表,用set_of_words2vec方法,传入大词表与小词表,可以遍历出小词表中每个词汇在大词表中存在的位置,对应位置标志置为1。创建一个和词汇表等长的向量,并将其元素都设置为0,遍历文档中的所有单词,如果出现了词汇表中的单词,则将输出的文档向量中的对应值设为1。

def set_of_words2vec(vocab_list, input_set):
    # 创建一个和词汇表等长的向量,并将其元素都设置为0
    result = [0] * len(vocab_list)
    # 遍历文档中的所有单词,如果出现了词汇表中的单词,则将输出的文档向量中的对应值设为1
    for word in input_set:
        if word in vocab_list:
            result[vocab_list.index(word)] = 1
        else:
            pass
    return result

在这里插入图片描述

4、构建分类器

利用公式:
P ( c i ∣ w ) = P ( w ∣ c i ) P ( c i ) P ( w ) P(c_{i}|\mathbf{w } ) = \frac{P(\mathbf{w }|c_{i})P(c_{i})}{P(\mathbf{w } )} P(ciw)=P(w)P(wci)P(ci)
首先可以通过类别i(友好或者非友好)邮件数除以总的邮件数计算概率P(ci)。接着计算P(w|ci),这里就要用到贝叶斯假设。如果将w展开为一个个独立特征,那么就可以将上述概率写作P(w0,w1,w2...wn),这里假设所有词都互相独立,该假设也作为条件独立性假设,它意味着可以使用P(w0,ci)P(w1,ci)P(w2,ci)...P(wn,ci)计算概率。

		该函数的伪代码如下:
		计算每个类别中的文档数目
		对每篇训练文档:
		        对每个类别:
		                如果词条出现在文档中→ 增加该词条的计数值
		                增加所有词条的计数值
		        对每个类别:
		                对每个词条:
		                        将该词条的数目除以总词条数目得到条件概率
		返回每个类别的条件概率

计算P(wi|c1)P(wi|c1),需要初始化程序中的分子变量和分母变量。一旦每个词语(友好或者不友好)在某一文件中出现,则改词对应的个数(p0Num或者p1Num)就加1,而在所有文件中,该文件总词数也对应加1。


def train_naive_bayes(train_mat, train_category):
    train_doc_num = len(train_mat)
    words_num = len(train_mat[0])
    # 因为侮辱性的被标记为了1, 所以只要把他们相加就可以得到侮辱性的有多少
    # 侮辱性文件的出现概率,即train_category中所有的1的个数,
    # 代表的就是多少个侮辱性文件,与文件的总数相除就得到了侮辱性文件的出现概率
    pos_abusive = np.sum(train_category) / train_doc_num
    # 单词出现的次数
    p0num = np.ones(words_num)
    p1num = np.ones(words_num)
    print(p1num)
    p0num_all = 2.0
    p1num_all = 2.0

    for i in range(train_doc_num):
        # 遍历所有的文件,如果是侮辱性文件,就计算此侮辱性文件中出现的侮辱性单词的个数
        if train_category[i] == 1:
            p1num += train_mat[i]
            p1num_all += np.sum(train_mat[i])
        else:
            p0num += train_mat[i]
            p0num_all += np.sum(train_mat[i])
    p1vec = np.log(p1num / p1num_all)
    p0vec = np.log(p0num / p0num_all)
    return p0vec, p1vec, pos_abusive

vec2classify: 待测数据[0,1,1,1,1…],即要分类的向量,p0vec: 类别0,即正常文档的, p1vec: 类别1,即侮辱性文档的,p_class1类别1,侮辱性文件的出现概率。使用算法: 乘法: P(C|F1F2...Fn) = P(F1F2...Fn|C)P(C)/P(F1F2...Fn),加法:P(F1|C)*P(F2|C)....P(Fn|C)P(C) -> log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C)),使用 NumPy 数组来计算两个向量相乘的结果,这里的相乘是指对应元素相乘,即先将两个向量中的第一个元素相乘,然后将第2个元素相乘,以此类推。我的理解是: 这里的 vec2Classify * p1Vec 的意思就是将每个词与其对应的概率相关联起来,可以理解为 1.单词在词汇表中的条件下,文件是good 类别的概率 也可以理解为 2.在整个空间下,文件既在词汇表中又是good类别的概率。

def classify_naive_bayes(vec2classify, p0vec, p1vec, p_class1):
    p1 = np.sum(vec2classify * p1vec) + np.log(p_class1)
    p0 = np.sum(vec2classify * p0vec) + np.log(1 - p_class1)
    if p1 > p0:
        return 1
    else:
        return 0

5、测试算法

输入测试文件的对应词表,可以判断这个文件是友好的还是不友好的。例如我输入两个文件一部分词表,通过算法可以判断该邮件是友好还是非友好文件。其中词表['一番', '卑劣', '某人', '冷静', '以为', '真的', '不能', '有着', '这件', '清华', '心情 。', '一起 。', '解释',]是从友好文件中截取的,['邮箱', '地税', '查证', '树立', '较多现', '广州', '我司', '大小', '如贵司', '额度', '核心思想', '电脑', '真票 !', '每月', '洽商']是从非友好文件中截取的,最后算法预测的结果也是正确的。

def testing_naive_bayes():
    # 1. 加载数据集
    list_post, list_classes = load_data_set()
    # 2. 创建单词集合
    vocab_list = create_vocab_list(list_post)

    # 3. 计算单词是否出现并创建数据矩阵
    train_mat = []
    for post_in in list_post:
        train_mat.append(
            # 返回m*len(vocab_list)的矩阵, 记录的都是0,1信息
            set_of_words2vec(vocab_list, post_in)
        )
    # 4. 训练数据
    p0v, p1v, p_abusive = train_naive_bayes(np.array(train_mat), np.array(list_classes))
    # 5. 测试数据
    test_one = ['一番', '卑劣', '某人', '冷静', '以为', '真的', '不能', '有着', '这件', '清华', '心情 。', '一起 。', '解释',]
    print(test_one)
    test_one_doc = np.array(set_of_words2vec(vocab_list, test_one))
    print('这个邮件的类别是: {}'.format(classify_naive_bayes(test_one_doc, p0v, p1v, p_abusive)))
    test_two = ['邮箱', '地税', '查证', '树立', '较多现', '广州', '我司', '大小', '如贵司', '额度', '核心思想', '电脑', '真票 !', '每月', '洽商']
    print(test_two)
    test_two_doc = np.array(set_of_words2vec(vocab_list, test_two))
    print('这个邮件的类别是: {}'.format(classify_naive_bayes(test_two_doc, p0v, p1v, p_abusive)))

在这里插入图片描述

利用朴素贝叶斯进行垃圾邮件过滤

1、导入数据集

数据集中友好邮件和不友好邮件大概都是8500份。
在这里插入图片描述

2、垃圾邮件预测

垃圾邮件预测算法主要用到利用朴素贝叶斯进行文档分类中的贝叶斯分类器,通过分类器返回判断类型与实际类型比较,最终可以计算出错误比例。我这里友好文件和不友好文件都有1000份,对这些邮件处理返回概率之后,再从总共份文件中随机抽取100份进行预测,最后输出预测的结果。

def spam_test():
    """
    对贝叶斯垃圾邮件分类器进行自动化处理。
    :return: nothing
    """
    doc_list = []
    class_list = []
    full_text = []
    for i in range(1, 51):
        try:
            words = cut_sentences(open('TrainingSet/Ham/{}.txt'.format(i)).read())
        except:
            words = cut_sentences(open('TrainingSet/Ham/{}.txt'.format(i), encoding='Windows 1252').read())
        doc_list.append(words)
        full_text.extend(words)
        class_list.append(1)
        try:
            # 添加非垃圾邮件
            words = cut_sentences(open('TrainingSet/Ham/{}.txt'.format(i)).read())
        except:
            words = cut_sentences(open('TrainingSet/Ham/{}.txt'.format(i), encoding='Windows 1252').read())
        doc_list.append(words)
        full_text.extend(words)
        class_list.append(0)
    # 创建词汇表
    vocab_list = create_vocab_list(doc_list)
    
    import random
    test_set = [int(num) for num in random.sample(range(100), 50)]
    training_set = list(set(range(100)) - set(test_set))
    
    training_mat = []
    training_class = []
    for doc_index in training_set:
        training_mat.append(set_of_words2vec(vocab_list, doc_list[doc_index]))
        training_class.append(class_list[doc_index])
    p0v, p1v, p_spam = train_naive_bayes(
        np.array(training_mat),
        np.array(training_class)
    )

    # 开始测试
    error_count = 0
    for doc_index in test_set:
        word_vec = set_of_words2vec(vocab_list, doc_list[doc_index])
        if classify_naive_bayes(
            np.array(word_vec),
            p0v,
            p1v,
            p_spam
        ) != class_list[doc_index]:
            error_count += 1
    print('正确率为 {}'.format(
        1 - (error_count / len(test_set))
    ))

总结

算法对大量的数据集不太友好,最开始我找了上万条的邮件作为数据集,最后运行出来的结果特别差错误率能达到0.9。最后不得不减少数据集,分别用500条友好和不友好的文件,一共抽取100条测试正确率,最后结果正确率只有0.18。
在这里插入图片描述
继续减小数据集,最后分别用50条友好和不友好的文件,一共抽取20条测试正确率,正确率只有0.28。应该是我的数据集里面每一封邮件内容过多,中文词组之间没有太大联系造成的。
在这里插入图片描述

朴素贝叶斯算法优点:

  • 朴素贝叶斯模型有稳定的分类效率。
  • 对小规模的数据表现很好,能处理多分类任务,适合增量式训练,尤其是数据量超出内存时,可以一批批的去增量训练。
  • 对缺失数据不太敏感,算法也比较简单,常用于文本分类。

缺点:

  • 理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。
  • 需要知道先验概率,且先验概率很多时候取决于假设,假设的模型可以有很多种,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。
  • 对输入数据的表达形式很敏感。

代码地址:
链接:https://pan.baidu.com/s/1iXUTGRxISzWisOk_Wt6xXA?pwd=zrqx
提取码:zrqx

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

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

相关文章

Intersoft WebUI Studio for asp.net/asp.mvc

企业 Web 开发的终极工具集。WebUI 建立在坚实的框架之上,为 ASP.NET 提供创新和先进的 40 多个优质 UI 组件,让您轻松及时地构建强大的业务 Web 应用程序。 不仅仅是全面的 UI 工具集。 在提供业界最佳网络体验的愿景的支持下,WebUI 提供了前…

AQS源码解析 8.共享模式_Semaphore信号量

AQS源码解析—共享模式_Semaphore信号量 简介 synchronized 可以起到锁的作用,但某个时间段内,只能有一个线程允许执行。 Semaphore(信号量)用来限制能同时访问共享资源的线程上限,非重入锁。 Semaphore 是什么&am…

377. 组合总和 Ⅳ【完全背包】求排列数:外层for背包,内层for物品;求组合数:外层for物品,内层for背包;

377. 组合总和 Ⅳ 给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 示例 1: 输入:nums [1,2,3], target 4 输出&#x…

如何利用快解析远程访问家庭智能网关

随着家庭宽带用户的暴增,涌现出了许多连接家居设备和控制中心的产品,如家庭智能网关。家庭智能网关是家居智能化的心脏,通过它实现系统的信息采集、信息输入、信息输出、集中控制、远程控制、联动控制等功能。 ​ 智能家庭网关具备智能家居控…

springcloud24:分布式事务 Seata处理分布式事务总结篇

分布式事务: 分布式事务的问题: 1:1 一个servlet 对应一个 数据库1:N 一个servlet对应多个数据库N:N 多个servlet对应多个数据库 全局事务一致性问题(全局数据一致性的保证) Seata是分布式事务的解决方案 分…

Python标准库之os

1. OS标准库简介 顾名思义,OS表示Operating System,即操作系统。OS标准库是一个操作系统接口模块,提供一些方便使用操作系统相关功能的函数,具体安装位置可通过导入os模块查看os.__file__属性得到。当需要在Python代码中调用OS相…

WPF-页面-DataGrid数据处理-多线程-Winform嵌入

页面 if(NavigationService.CanGoBack true) NavigationService.GoBack(); NavigationService.Navigate(new Uri("Page.xaml",UriKind.Relative));打印对话框PrintDialog如果要一下启动两个窗口,可以重写App.cs中的OnStartUP方法设置窗口所属关系&#…

【我的渲染技术进阶之旅】你知道数字图像处理的标准图上的女孩子是谁吗?背后的故事你了解吗?为啥这张名为Lenna的图会成为数字图像处理的标准图呢?

文章目录一、先来看一张神图:Lenna图二、图片中的妹子是谁?三、为何要使用Lenna图像?四、谁制作了Lenna图像?五、人红是非多六、福利时间七、岁月神偷文末有福利 一、先来看一张神图:Lenna图 想必所有搞过图像处理的人…

LQ0265 汉诺塔【水题】

题目来源:蓝桥杯2012初赛 Java A组C题 题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。 大梵天创造世界的时候做了三…

Map和Set常见操作汇总

作者:~小明学编程 文章专栏:Java数据结构 格言:目之所及皆为回忆,心之所想皆为过往 目录 Map 介绍 什么是Map? Map.Entry,> 常用方法 代码 Map中的注意点总结 Set 常见方法汇总 Set中的注意点总结 Map …

Ngxin--源码分析 缓冲区链表

1.基本数据结构 在处理 TCP/HTTP 请求时会经常创建多个缓冲区来存放数据, Nginx缓冲区块简单地组织一个单向链表struct ngx_chain_s {ngx_buf_t *buf;ngx_chain_t *next; };buf: 缓冲区指针 next 下一个链表节点 注意: ngx_chain_t是…

自定义数据类型:结构体、枚举、联合

个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C/C】 目录结构体结构体类型的声明结构的自引用结构体变量的定义和初始化结构体内存对齐练习1练习2(结构体嵌套问题&#x…

JSP表达式(EL)

一、介绍: EL(Expression Language)可用来代替JSP中的各类脚本,提高编程的灵活度,简化代码的编写。 二、EL的限制: 不能声明变量,需要使用JSTL或者JavaBean Action设置变量。 三、EL的标准格…

使用D435i+Avia跑Fast-LIVO

前言 最近Fast-LIVO开源了,之前看它的论文的时候发现效果很优秀,于是用实验室现有的设备尝试一下。这里主要记录一下使用不带外触发功能的D435i Avia跑Fast-LIVO的过程,为了适配代码,主要修改了雷达的驱动、相机的launch文件、以…

【Flink】各种窗口的使用(处理时间窗口、事件时间窗口、窗口聚合窗口)

文章目录一 Flink 中的 Window1 Window(1)Window概述(2) Window类型a 滚动窗口(Tumbling Windows)b 滑动窗口(Sliding Windows)c 会话窗口(Session Windows)2…

ATJ2157内存篇【炬芯音频芯片】---sct语法

ATJ2157 sct语法公共知识篇BNF 简介Sct脚本Sct的作用Sct的语法规则1. 加载域描述(Loadd region descriptions)2. 执行域描述3. 输入节的描述ATJ2157平台使用的sctRO的等效写法ScatterAssert()函数LoadLength()函数LoadBase()函数ImageLimit()函数ATJ2157平台什么数据编译出来是…

CentOS 7.6上安装SqlServer2017

一、 安装 SQL Server 1、 安装 SQL Server 所需的python2 sudo alternatives --config python # If not configured, install python2 and openssl10 using the following commands: sudo yum install python2 sudo yum install compat-openssl10 # Configure python2 a…

Python自动化小技巧12——根据论文题目自动导出参考文献格式

案例背景 在写论文的时候,弄参考文献格式也很麻烦,不可能手打人名题目期刊名称年月日卷号页码这些,我们一般都是使用系统自动导出的格式复制粘贴就行。中国知网可以直接导出论文的格式,但是知网基本只有中文的论文,英…

pdf编辑器工具哪个好?好用的pdf编辑器一款就够!

pdf这类办公软件大家都很熟悉,不过pdf通常情况只能看不能编辑,这着实也很让人苦恼!特别是现在国内大多都已居家办公,本来就颇多不便,如果没有一款好用的pdf编辑器工具,那么势必导致工作效率更为低下。 那么…

第十二章 哈希表与字符串哈希

第十二章 哈希表与字符串哈希一、哈希表1、什么是哈希表2、算法逻辑(1)哈希函数(2)冲突解决3、算法模板二、字符串哈希1、算法逻辑2、算法用途3、算法模板一、哈希表 1、什么是哈希表 在之前的文章中,我们学习过离散…