白手起家学习数据科学 ——Naive Bayes之“背后的思想”(十)

2023-11-22 12:08

本文主要是介绍白手起家学习数据科学 ——Naive Bayes之“背后的思想”(十),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如果人们不能互相沟通,那么社会网络就不是一个好的网络。基于此,DataSciencester网站有个大众的特点,允许用户发送消息给其他的用户。大多数用户是有责任的公民,他们只发送受欢迎的“最近好么”(how is it going?)消息,其他一些用户发送极端的垃圾邮件,关于致富方案、无需开处方的药物等,你的用户开始抱怨,所以Messaging部门的副总要求你使用数据科学找到一个方法过滤这些垃圾邮件。

无声的垃圾邮件过滤系统

S是一个”消息是垃圾邮件”事件,V是一个”包含单词viagra的消息”的事件。贝叶斯原理告诉我们,在”包含单词viagra“条件下”消息是垃圾邮件”的概率:

P(S|V)=[P(V|S)P(S)]/[P(V|S)P(S)+P(V|¬S)P(¬S)]

分子是”消息是垃圾邮件”同时”包含单词viagra消息”的概率,然而分母是”包含单词viagra消息”的概率。因此你可以简单的把这个公式看成在”包含单词viagra邮件”集合里,垃圾邮件所占的比重。

如果我们有大量知道是垃圾邮件的消息,以及大量知道是非垃圾邮件的消息,那么我们能简单的评估 P(V|S) P(V|¬S) 。如果我们假设任何消息都是等价的可能是垃圾邮件也可能是非垃圾邮件(所以P(S)=P( ¬S)=0.5),那么:

P(S|V)=P(V|S)/[P(V|S)+P(V|¬S)]

例如,如果垃圾邮件50%有单词viagra,但是只有1%的非垃圾邮件有单词viagra,那么在包含单词viagra邮件的前提下,是垃圾邮件的概率是:

0.5/(0.5+0.01)=98

更加复杂的垃圾邮件过滤系统

现在设想一下我们有许多单词 w1,...,wn 组成的词汇表,为了把这个词汇表移动真实的概率理论中,我们记 Xi 为事件”包含单词 wi 的信息”;提出评估 P(Xi|S) 概率,表示已知是垃圾邮件,包含第i个单词的概率;相似的评估 P(Xi|¬S) 概率,表示已知是非垃圾消息,包含第i个单词的概率。

朴素贝叶斯(Naive Bayes)最关键的假设是:基于已知消息是垃圾邮件或者不是的前提下,每个单词跟另外的单词是独立的。直观上,这个假设的意思是知道某个垃圾消息包含单词viagra没有给你任何信息是否同样的消息包含单词rolex,数学上表示:

P(X1=x1,...,Xn=xn|S)=P(X1=x1|S)...P(Xn=xn|S)

这是一个极端的假设(这就是”naive”的由来)。设想一下我们的词汇表只包含单词viagrarolex,所有垃圾消息一半是”cheap viagra”,另外一半是”authentic rolex”。这这个案例中,朴素贝叶斯评估包含”viagra”和”rolex”两者的垃圾消息是:

P(X1=1X2=1|S)=P(X1=1|S)P(X2=1|S)=.5.5=.25

由于我们假定的知识”viagra”和”rolex”从来不一起出现,虽然这个假设不现实,但是这个模型常常执行的 很好并被使用在真实的垃圾过滤系统中。

同理可以推出Bayes理论用于”只有viagra”垃圾邮件过滤,我们能计算一个消息是垃圾邮件的概率:

P(S|X=x)=P(X=x|S)/[P(X=x|S)+P(X=x|¬S)]

朴素贝叶斯允许我们把计算出来的概率(单词表里每个单词)简单的一起相乘。

实际中,你通常想要避免多个概率相乘,为了避免一个叫做下溢(underflow)的问题,因为计算机不能处理一个接近于零的浮点型数据(意味着小数点后面有很多位)。回顾一下线性代数 log(ab)=loga+logb 以及exp(logx) = x,我们通常计算 p1...pn 如下式:

exp(log(p1)+...log(pn))

最后的挑战就是评估P(Xi|S)和P(Xi|¬S),即在已知垃圾消息(或非垃圾消息)下包含单词wi的概率。如果我们有相当一部分”训练”消息带着标签”spam”和”nonspam”,很显然简单评估P(Xi|S)看成”spam”消息集中单词wi占的比例。

但是这引起了一个大的问题,设想一下,在我们的训练集上词汇表中”data”单词只出现在非垃圾消息中,那么我们评估 P("data"|S)=0 ,结果是我们的朴素贝叶斯分类器总是把垃圾消息概率为0赋值给任何包含单词”data”的消息中,甚至像”data on cheap viagra and authentic rolex watches.”这样的消息,为了避免这个问题,我们通常使用某些过滤。

尤其,我们将选择pseudocount—k,评估在spam条件下第i个单词的概率:

P(Xi|S)=(k+numberofspamscontainingwi)/(2k+numberofspams)

P(Xi|¬S) 也类似。我们假设另外加k个额外的spams包含这个单词以及另外加k个额外的spams不包含这个单词。

例如,在spam条件下,如果”data”发生了0/98(98个spam,有0个包含单词”data”),并且如果k为1,我们评估 P("data"|S) 1/100=0.01 ,允许我们的分类器仍然把一些非零spam概率赋值给包含单词”data”的消息中。

实施(Implementation)

现在我们有了所有技术,我们需要建立我们的分类器。首先,让我们创建一个简单的函数,把所有消息切分成不同的单词。把每个消息转换成小写,然后利用 re.findall() 抽出单词,这些单词由字母、数字以及省略号组成,最后使用 set() 得到不同的单词:

def tokenize(message):message = message.lower() # convert to lowercaseall_words = re.findall("[a-z0-9']+", message) # extract the wordsreturn set(all_words) # remove duplicates

我们的第二个函数对带有标签的训练集进行计数,它会返回一个字典,其key为单词,value为一个带有2个元素的list [spam_count, non_spam_count],对应在spam和nonspam消息中key出现的次数:

def count_words(training_set):"""training set consists of pairs (message, is_spam)"""counts = defaultdict(lambda: [0, 0])for message, is_spam in training_set:for word in tokenize(message):counts[word][0 if is_spam else 1] += 1return counts

接下来的步骤是把这些计数转换成概率,这些概率利用我们之前描述的平滑操作,我们的函数会返回一个list,其每行是包含3个元素的tuple,这3个元素分别为单词;spam消息下的单词概率;nonspam消息下的单词概率:

def word_probabilities(counts, total_spams, total_non_spams, k=0.5):"""turn the word_counts into a list of tripletsw, p(w | spam) and p(w | ~spam)"""return [(w,(spam + k) / (total_spams + 2 * k),(non_spam + k) / (total_non_spams + 2 * k))for w, (spam, non_spam) in counts.iteritems()]

最后一步是使用这些单词概率(以及我们的朴素贝叶斯假设)为这些消息计算概率:

def spam_probability(word_probs, message):message_words = tokenize(message)log_prob_if_spam = log_prob_if_not_spam = 0.0# iterate through each word in our vocabularyfor word, prob_if_spam, prob_if_not_spam in word_probs:# if *word* appears in the message,# add the log probability of seeing itif word in message_words:log_prob_if_spam += math.log(prob_if_spam)log_prob_if_not_spam += math.log(prob_if_not_spam)# if *word* doesn't appear in the message# add the log probability of _not_ seeing it# which is log(1 - probability of seeing it)else:log_prob_if_spam += math.log(1.0 - prob_if_spam)log_prob_if_not_spam += math.log(1.0 - prob_if_not_spam)prob_if_spam = math.exp(log_prob_if_spam)prob_if_not_spam = math.exp(log_prob_if_not_spam)return prob_if_spam / (prob_if_spam + prob_if_not_spam)

我们把这些连接起来组成Naive Bayes Classifier

class NaiveBayesClassifier:def __init__(self, k=0.5):self.k = kself.word_probs = []def train(self, training_set):# count spam and non-spam messagesnum_spams = len([is_spamfor message, is_spam in training_setif is_spam])num_non_spams = len(training_set) - num_spams# run training data through our "pipeline"word_counts = count_words(training_set)self.word_probs = word_probabilities(word_counts,num_spams,num_non_spams,self.k)def classify(self, message):return spam_probability(self.word_probs, message)

下一章节我们将要测试模型。

这篇关于白手起家学习数据科学 ——Naive Bayes之“背后的思想”(十)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/410026

相关文章

批量导入txt数据到的redis过程

《批量导入txt数据到的redis过程》用户通过将Redis命令逐行写入txt文件,利用管道模式运行客户端,成功执行批量删除以Product*匹配的Key操作,提高了数据清理效率... 目录批量导入txt数据到Redisjs把redis命令按一条 一行写到txt中管道命令运行redis客户端成功了批量删除k

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

解决pandas无法读取csv文件数据的问题

《解决pandas无法读取csv文件数据的问题》本文讲述作者用Pandas读取CSV文件时因参数设置不当导致数据错位,通过调整delimiter和on_bad_lines参数最终解决问题,并强调正确参... 目录一、前言二、问题复现1. 问题2. 通过 on_bad_lines=‘warn’ 跳过异常数据3

C#监听txt文档获取新数据方式

《C#监听txt文档获取新数据方式》文章介绍通过监听txt文件获取最新数据,并实现开机自启动、禁用窗口关闭按钮、阻止Ctrl+C中断及防止程序退出等功能,代码整合于主函数中,供参考学习... 目录前言一、监听txt文档增加数据二、其他功能1. 设置开机自启动2. 禁止控制台窗口关闭按钮3. 阻止Ctrl +

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

在MySQL中实现冷热数据分离的方法及使用场景底层原理解析

《在MySQL中实现冷热数据分离的方法及使用场景底层原理解析》MySQL冷热数据分离通过分表/分区策略、数据归档和索引优化,将频繁访问的热数据与冷数据分开存储,提升查询效率并降低存储成本,适用于高并发... 目录实现冷热数据分离1. 分表策略2. 使用分区表3. 数据归档与迁移在mysql中实现冷热数据分

C#解析JSON数据全攻略指南

《C#解析JSON数据全攻略指南》这篇文章主要为大家详细介绍了使用C#解析JSON数据全攻略指南,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、为什么jsON是C#开发必修课?二、四步搞定网络JSON数据1. 获取数据 - HttpClient最佳实践2. 动态解析 - 快速

MyBatis-Plus通用中等、大量数据分批查询和处理方法

《MyBatis-Plus通用中等、大量数据分批查询和处理方法》文章介绍MyBatis-Plus分页查询处理,通过函数式接口与Lambda表达式实现通用逻辑,方法抽象但功能强大,建议扩展分批处理及流式... 目录函数式接口获取分页数据接口数据处理接口通用逻辑工具类使用方法简单查询自定义查询方法总结函数式接口

SQL中如何添加数据(常见方法及示例)

《SQL中如何添加数据(常见方法及示例)》SQL全称为StructuredQueryLanguage,是一种用于管理关系数据库的标准编程语言,下面给大家介绍SQL中如何添加数据,感兴趣的朋友一起看看吧... 目录在mysql中,有多种方法可以添加数据。以下是一些常见的方法及其示例。1. 使用INSERT I

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核