数据结构与算法之美学习笔记:46 | 概率统计:如何利用朴素贝叶斯算法过滤垃圾短信?

目录

  • 前言
  • 算法解析
  • 总结引申

前言

在这里插入图片描述
本节课程思维导图:
在这里插入图片描述
上一节我们讲到,如何用位图、布隆过滤器,来过滤重复的数据。今天,我们再讲一个跟过滤相关的问题,如何过滤垃圾短信?

垃圾短信和骚扰电话,我想每个人都收到过吧?买房、贷款、投资理财、开发票,各种垃圾短信和骚扰电话,不胜其扰。如果你是一名手机应用开发工程师,让你实现一个简单的垃圾短信过滤功能以及骚扰电话拦截功能,该用什么样的数据结构和算法实现呢?

算法解析

实际上,解决这个问题并不会涉及很高深的算法。今天,我就带你一块看下,如何利用简单的数据结构和算法,解决这种看似非常复杂的问题。

  1. 基于黑名单的过滤器

我们可以维护一个骚扰电话号码和垃圾短信发送号码的黑名单。这个黑名单的收集,有很多途径,比如,我们可以从一些公开的网站上下载,也可以通过类似“360 骚扰电话拦截”的功能,通过用户自主标记骚扰电话来收集。对于被多个用户标记,并且标记个数超过一定阈值的号码,我们就可以定义为骚扰电话,并将它加入到我们的黑名单中。

如果黑名单中的电话号码不多的话,我们可以使用散列表、二叉树等动态数据结构来存储,对内存的消耗并不会很大。如果我们把每个号码看作一个字符串,并且假设平均长度是 16 个字节,那存储 50 万个电话号码,大约需要 10MB 的内存空间。即便是对于手机这样的内存有限的设备来说,这点内存的消耗也是可以接受的。

但是,如果黑名单中的电话号码很多呢?比如有 500 万个。这个时候,如果再用散列表存储,就需要大约 100MB 的存储空间。为了实现一个拦截功能,耗费用户如此多的手机内存,这显然有点儿不合理。

上一节我们讲了,布隆过滤器最大的特点就是比较省存储空间,所以,用它来解决这个问题再合适不过了。如果我们要存储 500 万个手机号码,我们把位图大小设置为 10 倍数据大小,也就是 5000 万,那也只需要使用 5000 万个二进制位(5000 万 bits),换算成字节,也就是不到 7MB 的存储空间。比起散列表的解决方案,内存的消耗减少了很多。

实际上,我们还有一种时间换空间的方法,可以将内存的消耗优化到极致。

我们可以把黑名单存储在服务器端上,把过滤和拦截的核心工作,交给服务器端来做。手机端只负责将要检查的号码发送给服务器端,服务器端通过查黑名单,判断这个号码是否应该被拦截,并将结果返回给手机端。

用这个解决思路完全不需要占用手机内存。不过,有利就有弊。我们知道,网络通信是比较慢的,所以,网络延迟就会导致处理速度降低。而且,这个方案还有个硬性要求,那就是只有在联网的情况下,才能正常工作。

基于黑名单的过滤器我就讲完了,不过,你可能还会说,布隆过滤器会有判错的概率呀!如果它把一个重要的电话或者短信,当成垃圾短信或者骚扰电话拦截了,对于用户来说,这是无法接受的。你说得没错,这是一个很大的问题。不过,我们现在先放一放,等三种过滤器都讲完之后,我再来解答。

  1. 基于规则的过滤器

刚刚讲了一种基于黑名单的垃圾短信过滤方法,但是,如果某个垃圾短信发送者的号码并不在黑名单中,那这种方法就没办法拦截了。所以,基于黑名单的过滤方式,还不够完善,我们再继续看一种基于规则的过滤方式。

对于垃圾短信来说,我们还可以通过短信的内容,来判断某条短信是否是垃圾短信。我们预先设定一些规则,如果某条短信符合这些规则,我们就可以判定它是垃圾短信。实际上,规则可以有很多,比如下面这几个:

  • 短信中包含特殊单词(或词语),比如一些非法、淫秽、反动词语等;
  • 短信发送号码是群发号码,非我们正常的手机号码,比如 +60389585;
  • 短信中包含回拨的联系方式,比如手机号码、微信、QQ、网页链接等,因为群发短信的号码一般都是无法回拨的;
  • 短信格式花哨、内容很长,比如包含各种表情、图片、网页链接等;
  • 符合已知垃圾短信的模板。垃圾短信一般都是重复群发,对于已经判定为垃圾短信的短信,我们可以抽象成模板,将获取到的短信与模板匹配,一旦匹配,我们就可以判定为垃圾短信。

当然,如果短信只是满足其中一条规则,如果就判定为垃圾短信,那会存在比较大的误判的情况。我们可以综合多条规则进行判断。比如,满足 2 条以上才会被判定为垃圾短信;或者每条规则对应一个不同的得分,满足哪条规则,我们就累加对应的分数,某条短信的总得分超过某个阈值,才会被判定为垃圾短信。

不过,我只是给出了一些制定规则的思路,具体落实到执行层面,其实还有很大的距离,还有很多细节需要处理。比如,第一条规则中,我们该如何定义特殊单词;第二条规则中,我们该如何定义什么样的号码是群发号码等等。限于篇幅,我就不一一详细展开来讲了。我这里只讲一下,如何定义特殊单词?

如果我们只是自己拍脑袋想,哪些单词属于特殊单词,那势必有比较大的主观性,也很容易漏掉某些单词。实际上,我们可以基于概率统计的方法,借助计算机强大的计算能力,找出哪些单词最常出现在垃圾短信中,将这些最常出现的单词,作为特殊单词,用来过滤短信。

不过这种方法的前提是,我们有大量的样本数据,也就是说,要有大量的短信(比如 1000 万条短信),并且我们还要求,每条短信都做好了标记,它是垃圾短信还是非垃圾短信。

我们对这 1000 万条短信,进行分词处理(借助中文或者英文分词算法),去掉“的、和、是”等没有意义的停用词(Stop words),得到 n 个不同的单词。针对每个单词,我们统计有多少个垃圾短信出现了这个单词,有多少个非垃圾短信会出现这个单词,进而求出每个单词出现在垃圾短信中的概率,以及出现在非垃圾短信中的概率。如果某个单词出现在垃圾短信中的概率,远大于出现在非垃圾短信中的概率,那我们就把这个单词作为特殊单词,用来过滤垃圾短信。

在这里插入图片描述

  1. 基于概率统计的过滤器

基于规则的过滤器,看起来很直观,也很好理解,但是它也有一定的局限性。一方面,这些规则受人的思维方式局限,规则未免太过简单;另一方面,垃圾短信发送者可能会针对规则,精心设计短信,绕过这些规则的拦截。对此,我们再来看一种更加高级的过滤方式,基于概率统计的过滤方式。

这种基于概率统计的过滤方式,基础理论是基于朴素贝叶斯算法。为了让你更好地理解下面的内容,我们先通过一个非常简单的例子来看下,什么是朴素贝叶斯算法?

假设事件 A 是“小明不去上学”,事件 B 是“下雨了”。我们现在统计了一下过去 10 天的下雨情况和小明上学的情况,作为样本数据。

在这里插入图片描述
我们来分析一下,这组样本有什么规律。在这 10 天中,有 4 天下雨,所以下雨的概率 P(B)=4/10。10 天中有 3 天,小明没有去上学,所以小明不去上学的概率 P(A)=3/10。在 4 个下雨天中,小明有 2 天没去上学,所以下雨天不去上学的概率 P(A|B)=2/4。在小明没有去上学的 3 天中,有 2 天下雨了,所以小明因为下雨而不上学的概率是 P(B|A)=2/3。实际上,这 4 个概率值之间,有一定的关系,这个关系就是朴素贝叶斯算法,我们用公式表示出来,就是下面这个样子。

在这里插入图片描述
朴素贝叶斯算法是不是非常简单?我们用一个公式就可以将它概括。弄懂了朴素贝叶斯算法,我们再回到垃圾短信过滤这个问题上,看看如何利用朴素贝叶斯算法,来做垃圾短信的过滤。

基于概率统计的过滤器,是基于短信内容来判定是否是垃圾短信。而计算机没办法像人一样理解短信的含义。所以,我们需要把短信抽象成一组计算机可以理解并且方便计算的特征项,用这一组特征项代替短信本身,来做垃圾短信过滤。

我们可以通过分词算法,把一个短信分割成 n 个单词。这 n 个单词就是一组特征项,全权代表这个短信。因此,判定一个短信是否是垃圾短信这样一个问题,就变成了,判定同时包含这几个单词的短信是否是垃圾短信。

不过,这里我们并不像基于规则的过滤器那样,非黑即白,一个短信要么被判定为垃圾短信、要么被判定为非垃圾短息。我们使用概率,来表征一个短信是垃圾短信的可信程度。如果我们用公式将这个概率表示出来,就是下面这个样子:

在这里插入图片描述
尽管我们有大量的短信样本,但是我们没法通过样本数据统计得到这个概率。为什么不可以呢?你可能会说,我只需要统计同时包含 W1​,W2​,W3​,…,Wn​ 这 n 个单词的短信有多少个(我们假设有 x 个),然后看这里面属于垃圾短信的有几个(我们假设有 y 个),那包含 W1​,W2​,W3​,…,Wn​ 这 n 个单词的短信是垃圾短信的概率就是 y/x。

理想很丰满,但现实往往很骨感。你忽视了非常重要的一点,那就是样本的数量再大,毕竟也是有限的,样本中不会有太多同时包含 W1​,W2​,W3​,…,Wn​ 的短信的,甚至很多时候,样本中根本不存在这样的短信。没有样本,也就无法计算概率。所以这样的推理方式虽然正确,但是实践中并不好用。

这个时候,朴素贝叶斯公式就可以派上用场了。我们通过朴素贝叶斯公式,将这个概率的求解,分解为其他三个概率的求解。你可以看我画的图。那转化之后的三个概率是否可以通过样本统计得到呢?

在这里插入图片描述

P(W1​,W2​,W3​,…,Wn​ 同时出现在一条短信中 | 短信是垃圾短信)这个概率照样无法通过样本来统计得到。但是我们可以基于下面这条著名的概率规则来计算。

独立事件发生的概率计算公式:P(A*B) = P(A)P(B)
如果事件 A 和事件 B 是独立事件,两者的发生没有相关性,事件 A 发生的概率 P(A) 等于 p1,事件 B 发生的概率 P(B) 等于 p2,那两个同时发生的概率 P(A
B) 就等于 P(A)*P(B)。

基于这条独立事件发生概率的计算公式,我们可以把 P(W1,W2,W3,…,Wn 同时出现在一条短信中 | 短信是垃圾短信)分解为下面这个公式:
在这里插入图片描述
其中,P(Wi​ 出现在短信中 | 短信是垃圾短信)表示垃圾短信中包含 Wi​ 这个单词的概率有多大。这个概率值通过统计样本很容易就能获得。我们假设垃圾短信有 y 个,其中包含 Wi​ 的有 x 个,那这个概率值就等于 x/y。

P(W1​,W2​,W3​,…,Wn​ 同时出现在一条短信中 | 短信是垃圾短信)这个概率值,我们就计算出来了,我们再来看下剩下两个。

P(短信是垃圾短信)表示短信是垃圾短信的概率,这个很容易得到。我们把样本中垃圾短信的个数除以总样本短信个数,就是短信是垃圾短信的概率。

不过,P(W1​,W2​,W3​,…,Wn​ 同时出现在一条短信中)这个概率还是不好通过样本统计得到,原因我们前面说过了,样本空间有限。不过,我们没必要非得计算这一部分的概率值。为什么这么说呢?

实际上,我们可以分别计算同时包含 W1​,W2​,W3​,…,Wn​ 这 n 个单词的短信,是垃圾短信和非垃圾短信的概率。假设它们分别是 p1 和 p2。我们并不需要单纯地基于 p1 值的大小来判断是否是垃圾短信,而是通过对比 p1 和 p2 值的大小,来判断一条短信是否是垃圾短信。更细化一点讲,那就是,如果 p1 是 p2 的很多倍(比如 10 倍),我们才确信这条短信是垃圾短信。

在这里插入图片描述
基于这两个概率的倍数来判断是否是垃圾短信的方法,我们就可以不用计算 P(W1​,W2​,W3​,…,Wn​ 同时出现在一条短信中)这一部分的值了,因为计算 p1 与 p2 的时候,都会包含这个概率值的计算,所以在求解 p1 和 p2 倍数(p1/p2)的时候,我们也就不需要这个值。

总结引申

今天,我们讲了基于黑名单、规则、概率统计三种垃圾短信的过滤方法,实际上,今天讲的这三种方法,还可以应用到很多类似的过滤、拦截的领域,比如垃圾邮件的过滤等等。

在讲黑名单过滤的时候,我讲到布隆过滤器可能会存在误判情况,可能会导致用户投诉。实际上,我们可以结合三种不同的过滤方式的结果,对同一个短信处理,如果三者都表明这个短信是垃圾短信,我们才把它当作垃圾短信拦截过滤,这样就会更精准。

当然,在实际的工程中,我们还需要结合具体的场景,以及大量的实验,不断去调整策略,权衡垃圾短信判定的准确率(是否会把不是垃圾的短信错判为垃圾短信)和召回率(是否能把所有的垃圾短信都找到),来实现我们的需求。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

牛客(JZ36 二叉搜索树与双向链表)

题目链接 思路1:使用中序遍历, 创建一个cur记录当前结点,prev记录上一个结点,这样cur->left prev,prev->right cur, 这样就链接 成功了。 难点:需要使用引用来控制prev。 /* struct T…

软件测试|深入理解Python中的re.search()和re.findall()区别

前言 在Python中,正则表达式是一种强大的工具,用于在文本中查找、匹配和处理模式。re 模块提供了许多函数来处理正则表达式,其中 re.search()和 re.findall() 是常用的两个函数,用于在字符串中查找匹配的模式。本文将深入介绍这两…

【同济子豪兄斯坦福CS224W中文精讲】NetworkX代码学习笔记

文章目录 安装配置创建图可视化图图数据挖掘参考资料 安装配置 matplotlib中文字体设置 import networkx as nx import matplotlib.pyplot as plt # 魔法指令,设置后在jupyter notebook中绘制的图形会显示在输出单元格中,而不是弹出一个新窗口 %matplo…

数字智慧驱动:数据可视化如何助力大企业效率飙升?

在当今信息大爆炸的时代,大型企业面临着前所未有的数据挑战。数据量庞大、多样化的信息汇聚,无疑成为企业高效运营的挑战之一。幸运的是,数据可视化作为一种强大的工具,正成为大型企业提高效率、优化决策的得力助手。 数据可视化首…

LAMMPS 文献:9 种熔化温度模拟方法的总结与比较:两相法、单相法以及缺陷法

记录一下检索到一篇通过LAMMPS模拟熔化温度的总结文章:单相方法、过热–过冷方法、Z 方法、修正 Z 方法、孔洞方法、修正孔洞方法、两相方法、夹层方法以及修正两相法。 感谢论文的原作者! 文章题目: A comprehensive investigation on the…

专业课148,总分410+电子科技大学858信号与系统考研经验电子信息与通信

今年专业课148分,总分410顺利被电子科技大学录取,回望这一年复习还有很多不足,总结一下自己的复习经历,希望对大家复习有所帮助。 数学:(多动手,多计算,多总结,打好基础…

spring-boot集成mybait-plus+shareding实现分表分库,dynamic动态数据多数据源

spring-boot集成mybait-plusshareding实现分表分库,多数据源 1. Spring-boot集成shareding Mybatis-plus依赖引用yaml 配置示例 2. 引用 dynamic实现分表动态数据源依赖引用yaml配置数据源注入配置示例 说明: 以下内容为两部分: …

WebDav协议相关软件@简单配置局域网内的http和WebDav服务器和传输系统

文章目录 相关软件windows自带第三方软件 chfs(CuteHttpFileServer)下载软件GUI方案 补充命令行方案命令行程序定位简单创建服务站点使用配置文件配置细节 使用软连接或符号链接等手段将向共享站点的根目录添加文件开机自启服务包装nssm包装使用powershell包装 服务启动chfs服务…

安装nvidia driver出现 the cc vision check falied

这里提示说的需要gcc12,但是我只有gcc11,所以就报错了,说一说我自己的解决方法: 安装gcc12和g12,再切换版本为gcc12 安装gcc12: sudo apt install gcc-12安装g12: sudo apt -y install g-12切换版本:参考博客

MSF流量加密

1、背景介绍 在MSF中生成shell,并上线运行时。都是通过http https tcp等协议传输。虽然MSF本身会对流量进行加密,但MSF太出名以致于其加密特征容易被IPS,WAF等可以检测带有攻击的特征的设备拦截或记录。 2、生成 SSL 证书 openssl req -x50…

《ORANGE’S:一个操作系统的实现》读书笔记(二十九)文件系统(四)

上一篇文章完善了硬盘驱动程序,并且完成了一个文件系统。这篇文章开始记录对文件的操作,首先记录如何创建一个文件。 目录 创建文件 Linux 下的文件操作 文件描述符(file descriptor) open() 创建文件所涉及的其它函数 str…

Redis:原理速成+项目实战——Redis企业级项目实战终结篇(HyperLogLog实现UV统计)

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习 🌌上期文章:Redis:原理速成项目实战——Redis实战14(BitMap实现用户签到功能) 📚订阅专栏&am…

vue中使用js-doc

安装依赖 安装vue-template-compiler npm install ​vue-template-compiler​ 安装minami npm install minami 安装js-doc npm install js-doc 根目录下创建 .jsdoc.conf.json 内容: {"tags": {"allowUnknownTags": true,// 指定所用词…

linux环境下安装postgresql

PostgreSQL: Linux downloads (Red Hat family)postgresql官网 PostgreSQL: Linux downloads (Red Hat family) 环境: centos7 postgresql14 选择版本 执行启动命令 配置远程连接文件 vi /var/lib/pqsql/14/data/postgresql.conf 这里将listen_addresses值由lo…

阿里云服务器+宝塔 (尝试部署一个最简单的静态页面)

1. 免费白嫖一个阿里服务器 进入网址:服务器购买地址 选择预装宝塔面板 购买完成后前往控制台 查看当前实例 设置或修改密码 设置用户名和密码 2. 远程连接到服务器 2.1. 使用Workbench连接 输入用户名和密码连接成功页面如下: 2.2. 使…

redis高级篇之单线程和多线程

目录 1、redis的发展史 2、redis为什么选择单线程? 3、主线程和Io线程是怎么协作完成请求处理的? 4、IO多路复用 5、开启redis多线程 1、redis的发展史 Redis4.0之前是用的单线程,4.0以后逐渐支持多线程 Redis4.0之前一直采用单线程的主…

高级分布式系统-第6讲 分布式系统的容错性--可靠的组通信

可靠的组通信 组内通信最好是每个进程之间都建立点到点的通信, 但实际中这样的组织结构不是有效的, 因为会浪费很大的通信带宽。 在平等组中, 多播是主要的组织结构。 但多播是具有同步性质的容错结构, 并不适用拜占庭模型。 多…

Redis命令 - Strings命令组常用命令

1、Set命令 SET key value [EX seconds] [PX milliseconds] [NX|XX]1.1 参数说明: EX seconds: 设置key的过期时间,单位时秒PX milliseconds: 设置key的过期时间,单位时毫秒NX: 只有key不存在的时候,才会设置key的值XX: 只有key…

GitHub注册新账号的操作流程(详细)

目录 第一步 进入官网,点击右上角的"Sign up" 第二步 输入email地址 第三步 设置密码 第四步 输入昵称 第五步 根据个人喜好决定要不要接收GitHub的邮件推送。然后回答他们的验证问题 第六步 输入验证码 我在注册github账号时遇到过一些阻碍&#x…

Web前端 ---- 【Vue3】ref和reactive实现响应式的区别和联系

目录 前言 setup ref 基本数据类型 对象形式 reactive ref和reactive的区别与联系 前言 本文介绍函数ref和函数reactive实现响应式 setup 在介绍ref和reactive之前,先介绍setup,vue3新引入的配置项。在该配置项中,在vue2中的data、methods、comput…