白手起家学习数据科学 ——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

相关文章

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

Redis 中的热点键和数据倾斜示例详解

《Redis中的热点键和数据倾斜示例详解》热点键是指在Redis中被频繁访问的特定键,这些键由于其高访问频率,可能导致Redis服务器的性能问题,尤其是在高并发场景下,本文给大家介绍Redis中的热... 目录Redis 中的热点键和数据倾斜热点键(Hot Key)定义特点应对策略示例数据倾斜(Data S

Python实现将MySQL中所有表的数据都导出为CSV文件并压缩

《Python实现将MySQL中所有表的数据都导出为CSV文件并压缩》这篇文章主要为大家详细介绍了如何使用Python将MySQL数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到... python将mysql数据库中所有表的数据都导出为CSV文件到一个目录,并压缩为zip文件到另一个

SpringBoot整合jasypt实现重要数据加密

《SpringBoot整合jasypt实现重要数据加密》Jasypt是一个专注于简化Java加密操作的开源工具,:本文主要介绍详细介绍了如何使用jasypt实现重要数据加密,感兴趣的小伙伴可... 目录jasypt简介 jasypt的优点SpringBoot使用jasypt创建mapper接口配置文件加密

使用Python高效获取网络数据的操作指南

《使用Python高效获取网络数据的操作指南》网络爬虫是一种自动化程序,用于访问和提取网站上的数据,Python是进行网络爬虫开发的理想语言,拥有丰富的库和工具,使得编写和维护爬虫变得简单高效,本文将... 目录网络爬虫的基本概念常用库介绍安装库Requests和BeautifulSoup爬虫开发发送请求解

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.