朴素贝叶斯算法

简介: 我们来约定一下: S: 邮件为垃圾邮件的概率 V: 邮件含有’viagra’词的概率 贝叶斯会告诉我们已知这个邮件含有viagra词,判断为垃圾邮件的概率: 假设垃圾邮件和非垃圾邮件的概率都是0.5,即: 则通过上面的公式得到: 假设50%的垃圾邮件中有‘vargra’,只有1%的非垃圾邮件中含有这个单词,问这个邮件是垃圾邮件的概率: 可见,含有这个单词一般都是垃圾邮件。

我们来约定一下:

S: 邮件为垃圾邮件的概率

V: 邮件含有’viagra’词的概率

贝叶斯会告诉我们已知这个邮件含有viagra词,判断为垃圾邮件的概率:

假设垃圾邮件和非垃圾邮件的概率都是0.5,即:

则通过上面的公式得到:

假设50%的垃圾邮件中有‘vargra’,只有1%的非垃圾邮件中含有这个单词,问这个邮件是垃圾邮件的概率:

可见,含有这个单词一般都是垃圾邮件。

更加精致的邮件分类器

想象一下我们有一堆字母,,我们使用Xi表示一封信中含有此词的概率。同样,表示垃圾邮件中含有单词的概率,,非垃圾邮件中含有单词的概率。贝叶斯估计最大的假设就是单词存在之间没有关系,也就是单词都是独立的,从数学的角度出发,也就是,这是一个非常大胆的假设,虽然这是一种假设,但这种算法却体现了很好的分类性能。接下来使用贝叶斯理论,则,这时我们需要计算大量的概率乘积,不过我们可以用log函数来简化,。 
但有时候会存在除0的状况,我们会使用一个因子k,得到

实现

说完了理论,是不是感觉很空洞,那我们来实现一下吧。首先定义一个方法来得到不同的单词作为集合。

def tokenize(message):
    message = message.lower()
    all_words = re.findall('[a-z0-9]+',message)
    return set(all_words)

我们第二个方法是统计训练集中单词的个数。返回一个字典,key为单词,value为二元组(垃圾邮件的统计,非垃圾邮件的统计),来查看某单词在垃圾和非垃圾邮件中的个数。

def count_words(training_set):
    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] += 1
    return counts

我们下面一步就是计算概率了,返回三元组,包含了每个单词,在垃圾邮件中的概率和非垃圾邮件中的概率。

def word_probabilities(counts, total_spams, total_non_spams,k=0.5):
    return [(w,(spam+k)/(2*k+total_spams),(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
    for word,prob_if_spam,prob_if_not_spam in word_probs:
        if word in message_words:
            log_prob_if_spam += math.log(prob_if_spam)
            log_prob_if_not_spam += math.log(prob_if_not_spam)
        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)

最后,我们写成一个类:

class NaiveBayesClassifier:
    def __init__(self, k=0.5):
        self.k = k
        self.word_probs = []
    def train(self,training_set):
        num_spams = len([is_spam for message,is_spam in training_set if is_spam])
        num_non_spams = len(training_set) - num_spams
        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)

我们来测试一下我们的分类性能。

在这个网址上提供了垃圾邮件数据集,我们测试了2002年的版本,对了,这里三个2002年的压缩文件都要下载下来,并放在一个文件夹下面,如这样的: 

下面我们就来测试一下:

import glob

path = 'spam\*\*'

data = []

for fn in glob.glob(path):
    is_spam = 'ham' not in fn
    #print is_spam

    with open(fn,'r') as file:
        for line in file:
            if![](http://i.imgur.com/8e6mWGM.png) line.startswith('Subject:'):
                subject = re.sub(r'^Subject: ','',line).strip()
                data.append((subject,is_spam))

这段代码的含义就是将文件夹下面的数据集放在一个data中。

random.seed(0)
train_data,test_data = split_data(data,0.75)
classifier = NaiveBayesClassifier()
classifier.train(train_data)

分割成测试集和训练集。

classified = [(subject,is_spam,classifier.classify(subject)) for subject,is_spam in test_data]
counts = Counter((is_spam,spam_probability>0.5) for _,is_spam ,spam_probability in classified)

首先分类测试集中的数据,然后检查准确率。在我的机器上,运行结果如下: 

精度为709/(709+28)=0.96,召回率为709/(709+40)=0/95,看起来还是蛮高的。我们有兴趣看看哪些容易被误分类。

classified.sort(key=lambda row:row[2]) #从小到大排序

spammiest_hams = filter(lambda row:not row[1],classified)[-5:]
hammiset_spams = filter(lambda row:row[1], classified)[:5]

最容易被判断为垃圾邮件的非垃圾邮件和垃圾邮件最不容易被判断的邮件。当然了,我们还最想看看垃圾邮件中的单词。

def p_spam_given_word(word_prob):
word, prob_if_spam, prob_if_not_spam = word_prob
return prob_if_spam / (prob_if_spam + prob_if_not_spam)

words = sorted(classifier.word_probs, key=p_spam_given_word)
spammiest_words = words[-5:]
hammiest_words = words[:5]

我们打印出来单词,如图:

这些关于含有钱,工作等单词的邮件很可能为垃圾邮件,而其他关于razor,等单词却不是,让我们感到很吃惊。

目录
相关文章
|
6月前
|
机器学习/深度学习 人工智能 自然语言处理
算法金 | AI 基石,无处不在的朴素贝叶斯算法
```markdown 探索贝叶斯定理:从默默无闻到AI基石。18世纪数学家贝叶斯的理论,初期未受重视,后成为20世纪机器学习、医学诊断和金融分析等领域关键。贝叶斯定理是智能背后的逻辑,朴素贝叶斯分类器在文本分类等应用中表现出色。贝叶斯网络则用于表示变量间条件依赖,常见于医学诊断和故障检测。贝叶斯推理通过更新信念以适应新证据,广泛应用于统计和AI。尽管有计算复杂性等局限,贝叶斯算法在小数据集和高不确定性场景中仍极具价值。了解并掌握这一算法,助你笑傲智能江湖! ```
60 2
算法金 | AI 基石,无处不在的朴素贝叶斯算法
|
4月前
|
数据采集 前端开发 算法
基于朴素贝叶斯算法的新闻类型预测,django框架开发,前端bootstrap,有爬虫有数据库
本文介绍了一个基于Django框架和朴素贝叶斯算法开发的新闻类型预测系统,该系统具备用户登录注册、后台管理、数据展示、新闻分类分布分析、新闻数量排名和新闻标题预测等功能,旨在提高新闻处理效率和个性化推荐服务。
|
4月前
|
机器学习/深度学习 算法 Python
python与朴素贝叶斯算法(附示例和代码)
朴素贝叶斯算法以其高效性和优良的分类性能,成为文本处理领域一项受欢迎的方法。提供的代码示例证明了其在Python语言中的易用性和实用性。尽管算法假设了特征之间的独立性,但在实际应用中,它仍然能够提供强大的分类能力。通过调整参数和优化模型,你可以进一步提升朴素贝叶斯分类器的性能。
130 0
|
4月前
|
监控 数据可视化 算法
基于朴素贝叶斯算法的微博舆情监控系统,flask后端,可视化丰富
本文介绍了一个基于朴素贝叶斯算法和Python技术栈的微博舆情监控系统,该系统使用Flask作为后端框架,通过数据爬取、清洗、情感分析和可视化等手段,为用户提供丰富的舆情分析和监测功能。
|
6月前
|
算法 Serverless
使用朴素贝叶斯算法过滤垃圾邮件
使用朴素贝叶斯算法过滤垃圾邮件
53 2
|
6月前
|
算法 Python
朴素贝叶斯算法
朴素贝叶斯算法
32 2
|
6月前
|
机器学习/深度学习 算法 大数据
【机器学习】朴素贝叶斯算法及其应用探索
在机器学习的广阔领域中,朴素贝叶斯分类器以其实现简单、计算高效和解释性强等特点,成为了一颗璀璨的明星。尽管名字中带有“朴素”二字,它在文本分类、垃圾邮件过滤、情感分析等多个领域展现出了不凡的效果。本文将深入浅出地介绍朴素贝叶斯的基本原理、数学推导、优缺点以及实际应用案例,旨在为读者构建一个全面而深刻的理解框架。
193 1
|
7月前
|
机器学习/深度学习 算法
【机器学习】比较朴素贝叶斯算法与逻辑回归算法
【5月更文挑战第10天】【机器学习】比较朴素贝叶斯算法与逻辑回归算法
|
6月前
|
算法
朴素贝叶斯算法
朴素贝叶斯算法
55 0
|
7月前
|
算法 Python
使用Python实现朴素贝叶斯算法
使用Python实现朴素贝叶斯算法
107 0