利用貝葉斯公式通過python過濾垃圾郵件

樸素貝葉斯公式

樸素貝葉斯公式

也可以簡寫為:


轉(zhuǎn)載請注明出處:Michael孟良

其中:

P(A)叫做A事件的先驗(yàn)概率,即一般情況下,認(rèn)為A發(fā)生的概率。

P(B|A)叫做似然度,是A假設(shè)條件成立的情況下發(fā)生B的概率。

P(A|B)叫做后驗(yàn)概率,在B發(fā)生的情況下發(fā)生A的概率,也就是要求的概率。P(B)叫做標(biāo)準(zhǔn)化常量,即在一般情況下,認(rèn)為B發(fā)生的概率。

理解樸素貝葉斯

假設(shè)現(xiàn)在有一堆郵件,正常郵件的比例是80%,垃圾郵件的比例是20%,這堆郵件中,5%的郵件中出現(xiàn)Viagra單詞,如果有一封郵件,這封郵件中包含Viagra單詞,求這封郵件是垃圾郵件的概率。



顯然不能使用5%*20%=1%得到這封郵件是垃圾郵件的概率,因?yàn)槔]件中有可能出現(xiàn)Viagra也有可能不會出現(xiàn)Viagra單詞。那么根據(jù)貝葉斯公式可得包含Viagra單詞的郵件是垃圾郵件的概率為:


P(spam)是已知20%,P(Viagra)也是已知 5%,那么如果求出P(Viagra|spam)的概率,結(jié)果就可以知道。我們可以根據(jù)郵件的數(shù)據(jù)集統(tǒng)計得到單詞頻率表:

其中P(spam|Viagra)表示在垃圾郵件中出現(xiàn)Viagra單詞的概率,通過統(tǒng)計得出為4/20??梢缘贸鋈绻环忄]件中有Viagra單詞,這封郵件是垃圾郵件的概率為:



通過同樣的計算可以得到,含有Viagra單詞但不是垃圾郵件的概率為0.2。那么可以認(rèn)為這封郵件是垃圾郵件的概率比較大。這里的Viagra可以理解為郵件中的一個特征。那么當(dāng)一封郵件有額外更多的特征時,貝葉斯如何擴(kuò)展?
假設(shè)所有歷史郵件中只出現(xiàn)了4個單詞,也就是4個特征,根據(jù)歷史郵件統(tǒng)計的單詞頻率表如下:



假設(shè)現(xiàn)在給定一封郵件中有Viagra和Unsubscribe(取消訂閱)兩個單詞,求這封郵件是垃圾郵件的概率、不是垃圾郵件的概率?
利用貝葉斯公式,我們可以得到:

是垃圾郵件的概率:



最后約等于98.07%
不是垃圾郵件的概率:

最后約等于17.4%

拉普拉斯估計

根據(jù)以上例子,假設(shè)有一封郵件這4個單詞都出現(xiàn)了,求這封郵件是垃圾郵件的概率:



由于P(W3)的概率為0/20,會導(dǎo)致整個結(jié)果是垃圾郵件的概率為0,那么就否定了其他單詞出現(xiàn)的權(quán)重。

拉普拉斯估計本質(zhì)上是給頻率表中的每個單詞的計數(shù)加上一個較小的數(shù),這樣就保證每一類中每個特征發(fā)生的概率非零。通常,拉普拉斯估計中加上的數(shù)值為1,這樣就保證了每一個特征至少在數(shù)據(jù)中出現(xiàn)一次。

以上例子如果四個單詞都出現(xiàn)情況下計算是否是垃圾郵件,出現(xiàn)P(W3)的概率為0/20,可以增加4封垃圾郵件,使4封郵件中每個郵件中只有一個單詞出現(xiàn),這樣就避免了垃圾郵件中有的單詞出現(xiàn)概率為0的情況。同樣在不是垃圾郵件中也增加4封,避免在正常郵件中出現(xiàn)有的單詞出現(xiàn)概率為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
    # 文本特征提?。?    #     將文本數(shù)據(jù)轉(zhuǎn)化成特征向量的過程
    #     比較常用的文本特征表示法為詞袋法
    #
    # 詞袋法:
    #     不考慮詞語出現(xiàn)的順序,每個出現(xiàn)過的詞匯單獨(dú)作為一列特征
    #     這些不重復(fù)的特征詞匯集合為詞表
    #     每一個文本都可以在很長的詞表上統(tǒng)計出一個很多列的特征向量
    # CountVectorizer是將文本向量轉(zhuǎn)換成稀疏表示數(shù)值向量(字符頻率向量)  vectorizer 將文檔詞塊化,只考慮詞匯在文本中出現(xiàn)的頻率
    # 詞袋
    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 拉普拉斯估計給每個單詞個數(shù)加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條數(shù)據(jù), 取5550條數(shù)據(jù)作為訓(xùn)練,后十條作為測試數(shù)據(jù)。每一行的第一個詞是這份郵件的類型,就是之前已經(jīng)人為判斷過,ham表示它為正常郵件, spam為垃圾郵件。
這里labels就是收集人為判斷的結(jié)果

    # 詞袋
    vectorizer = CountVectorizer()
    # 每行的詞向量,fea_train是一個矩陣
    fea_train = vectorizer.fit_transform(corpus)

vectorizer 拿到所有郵件的所有單詞,fea_train 是所有郵件每個詞在每份郵件出現(xiàn)的次數(shù),相當(dāng)一個矩陣。

# create the Multinomial Naive Bayesian Classifier
# alpha = 1 拉普拉斯估計給每個單詞個數(shù)加1
clf = MultinomialNB(alpha=1)
clf.fit(fea_train, labels)

這里 alpha = 1 ,就是前面講到的拉普拉斯估計,給每個單詞個數(shù)加1,防止它出現(xiàn)0的情況。
fea_train是訓(xùn)練出來的矩陣,labels是人為判斷的結(jié)果,把他們fit到clf里面。

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

fea_test是后面十條的數(shù)據(jù),把它放到我們之前訓(xùn)練好的貝葉斯模型clf,然后預(yù)測出這十條數(shù)據(jù)。

打印出來的結(jié)果

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容