利用贝叶斯公式通过python过滤垃圾邮件

朴素贝叶斯公式

朴素贝叶斯公式

也可以简写为:


转载请注明出处:Michael孟良

其中:

P(A)叫做A事件的先验概率,即一般情况下,认为A发生的概率。

P(B|A)叫做似然度,是A假设条件成立的情况下发生B的概率。

P(A|B)叫做后验概率,在B发生的情况下发生A的概率,也就是要求的概率。P(B)叫做标准化常量,即在一般情况下,认为B发生的概率。

理解朴素贝叶斯

假设现在有一堆邮件,正常邮件的比例是80%,垃圾邮件的比例是20%,这堆邮件中,5%的邮件中出现Viagra单词,如果有一封邮件,这封邮件中包含Viagra单词,求这封邮件是垃圾邮件的概率。



显然不能使用5%*20%=1%得到这封邮件是垃圾邮件的概率,因为垃圾邮件中有可能出现Viagra也有可能不会出现Viagra单词。那么根据贝叶斯公式可得包含Viagra单词的邮件是垃圾邮件的概率为:


P(spam)是已知20%,P(Viagra)也是已知 5%,那么如果求出P(Viagra|spam)的概率,结果就可以知道。我们可以根据邮件的数据集统计得到单词频率表:

其中P(spam|Viagra)表示在垃圾邮件中出现Viagra单词的概率,通过统计得出为4/20。可以得出如果一封邮件中有Viagra单词,这封邮件是垃圾邮件的概率为:



通过同样的计算可以得到,含有Viagra单词但不是垃圾邮件的概率为0.2。那么可以认为这封邮件是垃圾邮件的概率比较大。这里的Viagra可以理解为邮件中的一个特征。那么当一封邮件有额外更多的特征时,贝叶斯如何扩展?
假设所有历史邮件中只出现了4个单词,也就是4个特征,根据历史邮件统计的单词频率表如下:



假设现在给定一封邮件中有Viagra和Unsubscribe(取消订阅)两个单词,求这封邮件是垃圾邮件的概率、不是垃圾邮件的概率?
利用贝叶斯公式,我们可以得到:

是垃圾邮件的概率:



最后约等于98.07%
不是垃圾邮件的概率:

最后约等于17.4%

拉普拉斯估计

根据以上例子,假设有一封邮件这4个单词都出现了,求这封邮件是垃圾邮件的概率:



由于P(W3)的概率为0/20,会导致整个结果是垃圾邮件的概率为0,那么就否定了其他单词出现的权重。

拉普拉斯估计本质上是给频率表中的每个单词的计数加上一个较小的数,这样就保证每一类中每个特征发生的概率非零。通常,拉普拉斯估计中加上的数值为1,这样就保证了每一个特征至少在数据中出现一次。

以上例子如果四个单词都出现情况下计算是否是垃圾邮件,出现P(W3)的概率为0/20,可以增加4封垃圾邮件,使4封邮件中每个邮件中只有一个单词出现,这样就避免了垃圾邮件中有的单词出现概率为0的情况。同样在不是垃圾邮件中也增加4封,避免在正常邮件中出现有的单词出现概率为0的情况。

Python 贝叶斯案例

# coding:utf-8

import os
import sys
import codecs


# #####################################################
# Multinomial Naive Bayes Classifier
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer

print('*************************\nNaive Bayes\n*************************')

if __name__ == '__main__':
    # read the file
    corpus = []
    labels = []
    corpus_test = []
    labels_test = []
    f = codecs.open("./sms_spam.txt", "rb")
    count = 0
    while True:
        # readline() read every line,including "\n"
        line = f.readline().decode("utf-8")
        # read the first line and ignore it
        if count == 0:
            count = count + 1
            continue
        if line:
            count = count + 1
            line = line.split(",")
            label = line[0]
            sentence = line[1]
            corpus.append(sentence)
            if "ham" == label:
                labels.append(0)
            elif "spam" == label:
                labels.append(1)
            if count > 5550:
                corpus_test.append(sentence)
                if "ham" == label:
                    labels_test.append(0)
                elif "spam" == label:
                    labels_test.append(1)
        else:
            break
    # 文本特征提取:
    #     将文本数据转化成特征向量的过程
    #     比较常用的文本特征表示法为词袋法
    #
    # 词袋法:
    #     不考虑词语出现的顺序,每个出现过的词汇单独作为一列特征
    #     这些不重复的特征词汇集合为词表
    #     每一个文本都可以在很长的词表上统计出一个很多列的特征向量
    # CountVectorizer是将文本向量转换成稀疏表示数值向量(字符频率向量)  vectorizer 将文档词块化,只考虑词汇在文本中出现的频率
    # 词袋
    vectorizer = CountVectorizer()
    # 每行的词向量,fea_train是一个矩阵
    fea_train = vectorizer.fit_transform(corpus)

    print("vectorizer.get_feature_names is ", vectorizer.get_feature_names())
    print("fea_train is ", fea_train.toarray())

    # vocabulary=vectorizer.vocabulary_ 只计算上面vectorizer中单词的tf(term frequency 词频)
    vectorizer2 = CountVectorizer(vocabulary=vectorizer.vocabulary_)
    fea_test = vectorizer2.fit_transform(corpus_test)
    print("vectorizer2.get_feature_names()",vectorizer2.get_feature_names())
    print("fea_test.toarray()",fea_test.toarray())

    # create the Multinomial Naive Bayesian Classifier
    # alpha = 1 拉普拉斯估计给每个单词个数加1
    clf = MultinomialNB(alpha=1)
    clf.fit(fea_train, labels)

    pred = clf.predict(fea_test);
    for p in pred:
        if p == 0:
            print("正常邮件")
        else:
            print("垃圾邮件")

sms_spam.txt:

type,text
ham,you are having a good week. Just checking in 00 00 00 0089 0089
ham,K..give back my thanks.
ham,Am also doing in cbe only. But have to pay.
spam,"complimentary 4 STAR Ibiza Holiday or £10,000 cash needs your URGENT collection. 09066364349 NOW from Landline not to lose out! Box434SK38WP150PPM18+"
...

逻辑思路:

sms_spam.txt有5560条数据, 取5550条数据作为训练,后十条作为测试数据。每一行的第一个词是这份邮件的类型,就是之前已经人为判断过,ham表示它为正常邮件, spam为垃圾邮件。
这里labels就是收集人为判断的结果

    # 词袋
    vectorizer = CountVectorizer()
    # 每行的词向量,fea_train是一个矩阵
    fea_train = vectorizer.fit_transform(corpus)

vectorizer 拿到所有邮件的所有单词,fea_train 是所有邮件每个词在每份邮件出现的次数,相当一个矩阵。

# create the Multinomial Naive Bayesian Classifier
# alpha = 1 拉普拉斯估计给每个单词个数加1
clf = MultinomialNB(alpha=1)
clf.fit(fea_train, labels)

这里 alpha = 1 ,就是前面讲到的拉普拉斯估计,给每个单词个数加1,防止它出现0的情况。
fea_train是训练出来的矩阵,labels是人为判断的结果,把他们fit到clf里面。

pred = clf.predict(fea_test);
for p in pred:
    if p == 0:
        print("正常邮件")
    else:
        print("垃圾邮件")

fea_test是后面十条的数据,把它放到我们之前训练好的贝叶斯模型clf,然后预测出这十条数据。

打印出来的结果

代码:https://github.com/MichaelYipInGitHub/PythonTest/tree/master/com/test/bayes

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容