機器學習實戰(zhàn) 樸素貝葉斯分類器

基于概率論的分類方法: 樸素貝葉斯

我的微信公眾號: s406205391; 歡迎大家一起學習,一起進步!W⒉尽女阀!

????????k-近鄰算法和決策樹會給出“該數(shù)據(jù)屬于哪一類”的明確回答宅荤。不過,分類器有時會產(chǎn)生錯誤結果浸策,這是可以要求分類器給出一個最優(yōu)的類別的猜測結果冯键,同事給出這個猜測的概率估計值。

????????樸素貝葉斯就是一個概率分類器庸汗。我們稱之為“樸素”惫确,是因為整個形式化的過程只做最原始、最簡單的假設。樸素貝葉斯的優(yōu)點:在數(shù)據(jù)較少的情況下仍然有效改化,可以處理多類別問題昧诱。缺點:對于輸入數(shù)據(jù)的準備方式較為敏感。適用數(shù)據(jù)類型:標稱型數(shù)據(jù).貝葉斯決策理論的核心思想就是所袁,選擇高概率對應的類別盏档。這里會應用到一種有效計算條件概率的方法,稱為貝葉斯準則燥爷。

P(c|x)=\frac{p(x|c)P(c)}{P(x)}

數(shù)據(jù)準備:構建詞向量

????????在應用貝葉斯分類算法之前蜈亩,構建輸入向量是很重要的一項。

????????機器學習的一個重要應用就是文檔的自動分類前翎。在文檔分類中稚配,整個文檔(如一封電子郵件)是實例,而電子郵件中的某些原色則構成特征港华。雖然電子郵件是一種會不斷增加的文本道川,但我們同樣也可以對新聞報道、用戶留言立宜、政府公文等其他任意類型的文本進行分類冒萄。我們可以觀察文檔中出現(xiàn)的詞,并把每個詞的出現(xiàn)或者不出現(xiàn)作為一個特征橙数,這樣得到的特征數(shù)目就會跟詞匯表中的詞數(shù)目一樣多尊流。

樸素貝葉斯的一般過程:

  1. 收集數(shù)據(jù):可以使用任何方法。

  2. 準備數(shù)據(jù):需要數(shù)值型或者布爾型數(shù)據(jù)

  3. 分析數(shù)據(jù):有大量特征時灯帮,繪制特征作用不大崖技,此時使用直方圖效果更好

  4. 訓練算法:計算不同的獨立特征的條件概率

  5. 測試算法:計算錯誤率

  6. 使用算法:一個常見的樸素貝葉斯應用是文檔分類排嫌≈莨簦可以在任意的分類場景中使用樸素貝葉斯分類器,不一定非要是文本值朋。

????????樸素貝葉斯有一個很重要的假設腻贰,每個特征同等重要吁恍。

???????? 現(xiàn)在我們通過如下函數(shù)去構建詞向量。load_data_set()函數(shù)創(chuàng)建了一些實驗樣本银受,其中posting_list表示不同的文本践盼,class_vec表示該文本的分類,0表示正常宾巍,1表示侮辱性文本咕幻。我們在處理真實文本時,首先也會把文本拆分成一個個單詞組成的列表顶霞。create_vocab_list()函數(shù)會將詞向量中的所有詞肄程,整合為不含重復詞的列表锣吼。set_of _words_2_vec()函數(shù)會統(tǒng)計不含重復詞的詞向量在我們待統(tǒng)計的詞向量中出現(xiàn)的次數(shù)。即最后我們會得到一個長度等于不含重復詞的詞向量的一個數(shù)值向量蓝厌,其中的數(shù)值表示該詞出現(xiàn)的次數(shù)玄叠。

def load_data_set():
    """構建模擬的詞列表和標簽"""

    posting_list = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'pleas'],
                    ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                    ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                    ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                    ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                    ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    class_vec = [0, 1, 0, 1, 0, 1]  # 1表示屬于侮辱性詞匯
    return posting_list, class_vec


def create_vocab_list(data_set):
    """將詞矩陣中的所有詞整合為不含重復詞的列表"""

    vocab_set = reduce(lambda x, y: set(x) | set(y), data_set)
    return list(vocab_set)


def set_of_words_2_vec(vocab_list, input_set):
    """ 統(tǒng)計vocab_list中的詞在input_set中出現(xiàn)的次數(shù)。
    
    :param vocab_list: 需要統(tǒng)計的詞的列表
    :param input_set: 生成的不帶重復詞的詞向量
    :return: 返回一個數(shù)字矩陣拓提,0表示該詞在vocab_list中未出現(xiàn)读恃,3表示該次在vocab_list中出現(xiàn)了三次
    """
    
    return_vec = [0] * len(vocab_list)
    for word in input_set:
        if word in vocab_list:
            return_vec[vocab_list.index(word)] += 1
    return return_vec

訓練算法:從詞向量計算概率

????????我們可以根據(jù)貝葉斯準則來計算文本屬于侮辱性文本的概率。

p(c_i|w)=\frac{p(w|c_i)p(c_i)}{p(w)} w表示所有詞的一個向量代态。

????????p(ci)表示文檔屬于侮辱性文檔的概率寺惫,我們可以通過侮辱性文檔的數(shù)量,除以文檔總數(shù)蹦疑,很方便的求的西雀。p(w|ci)表示每一個詞在侮辱性文檔中出現(xiàn)的概率,根據(jù)樸素貝葉斯假設歉摧,我們可以將w展開為一個個獨立的特征,那么我們就可以將上述概率寫作p(w0|ci)p(w1|ci)p(w2|ci)...p(wn|ci)來計算上述概率艇肴。

基本過程如下:

計算每個類別中的文檔數(shù)目

對每篇訓練文檔:

????????對每個類別:

????????????????如果詞條出現(xiàn)雜文檔中,那么增加該詞條的計數(shù)值

????????????????增加所有詞條的計數(shù)值

對每個類別:

????????對每個詞條:

?????????????????將該詞條的數(shù)目除以總詞條數(shù)目得到條件概率

返回每個類別的條件概率

????????我們在利用貝葉斯分類器對文檔進行分類時叁温,要計算多個概率的乘積再悼,如果其中一個概率為0,那么最后的乘積也為0券盅。為降低這種影響帮哈,我們將所有詞的出現(xiàn)數(shù)初始化為1,并將分母初始化為2锰镀。另外一個問題是下溢,當很多很小的概率相乘時咖刃,程序會下溢泳炉,得不到正確答案。因此這里把概率轉換成自然對數(shù)嚎杨。

def train_nb(train_matrix, train_category):
    """ 計算訓練矩陣中花鹅,每一個詞屬于不同分類的概率
    
    :param train_matrix:  待計算的詞矩陣 
    :param train_category:  每一個文檔的分類標簽
    :return:  返回每個文檔中每個詞屬于不同分類文檔的概率
    """

    # 計算訓練數(shù)據(jù)集中,侮辱性文本的概率
    num_train_docs = len(train_matrix)
    num_words = len(train_matrix[0])
    p_abusive = sum(train_category) / num_train_docs
    
    # 計算每個詞屬于不同分類文本的概率
    p0_num = np.ones(num_words)
    p1_num = np.ones(num_words)
    p0_denom = 2
    p1_denom = 2  # 分母為2枫浙,初始分子為0刨肃,為了防止概率過小導致概率為0
    for i in range(num_train_docs):
        if train_category[i] == 1:
            p1_num += train_matrix[i]
            p1_denom += sum(train_matrix[i])
        else:
            p0_num += train_matrix[i]
            p0_denom += sum(train_matrix[i])
    p1_vect = log(p1_num / p1_denom)
    p0_vect = log(p0_num / p0_denom)
    return p0_vect, p1_vect, p_abusive

構建樸素貝葉斯分類器

????????在準備好上述函數(shù)后,就可以進行貝葉斯分類了箩帚。

def classify_nb(vec_2_classify, p0_vec, p1_vec, p_class):
    p1 = sum(vec_2_classify * p1_vec) + np.log(p_class)
    p0 = sum(vec_2_classify * p0_vec) + np.log(1 - p_class)
    if p1 > p0:
        return 1
    else:
        return 0

示例:使用樸素貝葉斯過濾垃圾郵件

????????在email(提取碼:lael)文件夾中真友,有兩個子文件,分別表示垃圾郵件和正常郵件紧帕。我們首先將所有文件都整合成詞向量矩陣盔然,然后再隨機取40封郵件作為訓練數(shù)據(jù)集桅打,10封郵件作為測試數(shù)據(jù)集。

#!/usr/bin/env python3
# coding: utf-8
# Author:Shen Yi
# Date :2020/2/16 1:05

"""機器學習實戰(zhàn) 樸素貝葉斯"""

from functools import reduce
from glob import glob
import numpy as np
import re


def load_data_set():
    """構建模擬的詞列表和標簽"""

    posting_list = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'pleas'],
                    ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                    ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                    ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                    ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                    ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    class_vec = [0, 1, 0, 1, 0, 1]
    return posting_list, class_vec


def create_vocab_list(data_set):
    """將詞矩陣中的所有詞整合為不含重復詞的列表"""

    vocab_set = reduce(lambda x, y: set(x) | set(y), data_set)
    return list(vocab_set)


def set_of_words_2_vec(vocab_list, input_set):
    """ 統(tǒng)計vocab_list中的詞在input_set中出現(xiàn)的次數(shù)愈案。

    :param vocab_list: 需要統(tǒng)計的詞的列表
    :param input_set: 生成的不帶重復詞的詞向量
    :return: 返回一個數(shù)字矩陣挺尾,0表示該詞在vocab_list中未出現(xiàn),3表示該次在vocab_list中出現(xiàn)了三次
    """
    return_vec = [0] * len(vocab_list)
    for word in input_set:
        if word in vocab_list:
            return_vec[vocab_list.index(word)] += 1
    return return_vec


def train_nb(train_matrix, train_category):
    """ 計算訓練矩陣中站绪,每一個詞屬于不同分類的概率

    :param train_matrix:  待計算的詞矩陣
    :param train_category:  每一個文檔的分類標簽
    :return:  返回每個文檔中每個詞屬于不同分類文檔的概率
    """

    num_train_docs = len(train_matrix)
    num_words = len(train_matrix[0])
    p_abusive = sum(train_category) / num_train_docs
    p0_num = np.ones(num_words)
    p1_num = np.ones(num_words)
    p0_denom = 2
    p1_denom = 2
    for i in range(num_train_docs):
        if train_category[i] == 1:
            p1_num += train_matrix[i]
            p1_denom += sum(train_matrix[i])
        else:
            p0_num += train_matrix[i]
            p0_denom += sum(train_matrix[i])
    p1_vect = np.log(p1_num / p1_denom)
    p0_vect = np.log(p0_num / p0_denom)
    return p0_vect, p1_vect, p_abusive


def classify_nb(vec_2_classify, p0_vec, p1_vec, p_class):
    p1 = sum(vec_2_classify * p1_vec) + np.log(p_class)
    p0 = sum(vec_2_classify * p0_vec) + np.log(1 - p_class)
    if p1 > p0:
        return 1
    else:
        return 0


def demo_filter_email():
    """示例:樸素貝葉斯過濾垃圾郵件"""
    
    # 生成詞向量矩陣
    doc_list = []
    class_list = []
    full_text = []
    emails = glob('data\\Ch04\\email\\*\\*.txt')
    for email in emails:
        word_list = re.split(r'\W+', open(email).read())
        word_list = [word.lower() for word in word_list if len(word) > 2]
        doc_list.append(word_list)
        full_text.extend(word_list)
        if 'spam' in email:
            class_list.append(1)
        else:
            class_list.append(0)
    
    # 得到不重復的詞向量
    vocab_list = create_vocab_list(doc_list)

    # 隨機選取10封作為測試數(shù)據(jù)集
    training_set = list(range(50))
    test_set = []
    for i in range(10):
        rand_index = int(np.random.uniform(0, len(training_set)))
        test_set.append(training_set[rand_index])
        del(training_set[rand_index])

    # 對訓練數(shù)據(jù)集進行訓練
    train_mat = []
    train_classes = []
    for doc_index in training_set:
        train_mat.append(set_of_words_2_vec(vocab_list, doc_list[doc_index]))
        train_classes.append(class_list[doc_index])
    p0_vect, p1_vect, p_spam = train_nb(np.array(train_mat), np.array(train_classes))

    # 利用測試數(shù)據(jù)集遭铺,計算錯誤率
    error_count = 0
    for doc_index in test_set:
        word_vector = set_of_words_2_vec(vocab_list, doc_list[doc_index])
        if classify_nb(np.array(word_vector), p0_vect, p1_vect, p_spam) != class_list[doc_index]:
            error_count += 1
    print(f'the error rate is: {error_count / len(test_set)}')


if __name__ == '__main__':
    
    demo_filter_email()

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恢准,隨后出現(xiàn)的幾起案子魂挂,更是在濱河造成了極大的恐慌,老刑警劉巖顷歌,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锰蓬,死亡現(xiàn)場離奇詭異,居然都是意外死亡眯漩,警方通過查閱死者的電腦和手機芹扭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赦抖,“玉大人舱卡,你說我怎么就攤上這事《佑” “怎么了轮锥?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長要尔。 經(jīng)常有香客問我舍杜,道長,這世上最難降的妖魔是什么赵辕? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任既绩,我火速辦了婚禮,結果婚禮上还惠,老公的妹妹穿的比我還像新娘饲握。我一直安慰自己,他們只是感情好蚕键,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布救欧。 她就那樣靜靜地躺著,像睡著了一般锣光。 火紅的嫁衣襯著肌膚如雪笆怠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天嫉晶,我揣著相機與錄音骑疆,去河邊找鬼田篇。 笑死,一個胖子當著我的面吹牛箍铭,可吹牛的內(nèi)容都是我干的泊柬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼诈火,長吁一口氣:“原來是場噩夢啊……” “哼兽赁!你這毒婦竟也來了?” 一聲冷哼從身側響起冷守,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤刀崖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拍摇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亮钦,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年充活,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜂莉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡混卵,死狀恐怖映穗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幕随,我是刑警寧澤蚁滋,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站赘淮,受9級特大地震影響辕录,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梢卸,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一踏拜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧低剔,春花似錦、人聲如沸肮塞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枕赵。三九已至猜欺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拷窜,已是汗流浹背开皿。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工涧黄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赋荆。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓笋妥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窄潭。 傳聞我的和親對象是個殘疾皇子春宣,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容