機器學習實戰--基於概率論的分類方法:樸素貝葉斯

  • 樸素貝葉斯概述
    樸素貝葉斯算法就是利用我們在概率論中學習的條件概率公式來處理一些分類問題。

    樸素貝葉斯
    優點:在數據較少的情況下仍然有效,可以處理多類別問題
    缺點:對於輸入數據的準備方式較爲敏感
    適用數據類型:標稱型數據
  • 樸素貝葉斯算法原理
    概率論中有一個大名鼎鼎的概率公式,貝葉斯公式:

    這裏寫圖片描述

    推導過程如下:
    這裏寫圖片描述

    舉一個例子來闡述貝葉斯公式,據統計百分之八十的女孩會留長髮,百分之四十的男孩也留長髮,通過觀察發現大街上的人留長髮的比例是0.6,而且男女比例爲6:4,某個雨夜交加的夜晚,一個人被搶了,警察詢問罪犯性別時,這個人不知道罪犯是男是女,只知道罪犯留着一頭飄逸的長髮,請問警察怎麼判斷罪犯的性別?
    這裏寫圖片描述

    這裏寫圖片描述

    根據貝葉斯公式我們大致可以判斷,罪犯爲女性。有一個疑問,爲什麼男人和女人的概率相加爲0.93而不是1呢,剩下的那0.7是什麼人,雙性人?
    問題出在了我們的觀察上,由於女人天性喜歡逛街,所以總會在大街上出沒,我們在大街上觀察的時候當然看到的美女就更多一些,沒有做到完全隨機,所以0.6的概率和理論值有誤差,我只能這麼解釋了。。。

  • 示例:使用樸素貝葉斯進行文本分類
# -*- coding: utf-8 -*-
# Project:Python
# File:Bayes
# Author:mm.liu
# Date:2016-04-29:09:24
# TODO: 利用貝葉斯算法進行分類 p(ci/w)=p(w/ci)p(ci)/p(w)

from numpy import *


class Bayes:
    # 獲取訓練樣本
    # posting_list是一些留言分詞後的文檔集合
    # class_vec是以上留言的標註分類結果,0-正常言論 1-侮辱性言論
    def load_data_set(self):
        posting_list = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                        ['maybe', 'not', 'take', 'hime', 'to', 'dog', 'park', 'stupid'],
                        ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'hime'],
                        ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                        ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'hime'],
                        ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
        class_vec = [0, 1, 0, 1, 0, 1]
        return posting_list, class_vec

    # 建立詞典(詞庫)
    # data_set是存儲一批文本語料的集合
    # vocab_set是建立好的詞庫集合
    def create_vocab_list(self, data_set):
        vocab_set = set([])
        for document in data_set:
            # 取文檔詞集合和原有詞庫的並集,即添加文檔中出現的新詞
            vocab_set = vocab_set | set(document)
        return list(vocab_set)

    # 將文檔轉換爲詞向量,維度是詞庫的容量
    # vocab_list詞庫集合
    # input_set輸入的一篇文檔詞集合
    def set_words2vec(self, vocab_list, input_set):
        # 初始創建一個維度是詞庫容量,元素都爲0的向量
        return_vec = [0] * len(vocab_list)
        for word in input_set:
            if word in vocab_list:
                # 將在詞庫中存在的詞的位置設爲1
                return_vec[vocab_list.index(word)] = 1
            else:
                print "單詞[%s]未收錄到詞典!" % word
        return return_vec

    # 對樣本進行訓練,獲得p(w/ci)和p(ci)等
    # 假設w1,w2...wn是相互獨立的,所以p(w/ci)=p(w1,w2...wn/ci)=p(w1/ci)p(w2/ci)...p(wn/ci)
    def train(self, train_matrix, train_category):
        train_docs_num = len(train_matrix)
        words_num = len(train_matrix[0])
        # 計算侮辱類1的文檔總數,從而計算p(c1)的概率,p(c0)=1-p(c1),注意sum是將所有元素求和,應和len函數區分
        p_abusive = sum(train_category) / float(train_docs_num)
        # 創建長度爲words_num,元素爲0的矩陣
        p0_num = zeros(words_num)
        p1_num = zeros(words_num)
        p0_denom = 0.0
        p1_denom = 0.0
        for i in range(train_docs_num):
            if train_category[i] == 1:
                # 向量中每個元素存儲的是某個單詞在c1中出現的次數
                p1_num += train_matrix[i]
                # 計算c1中所有單詞總數,同一個詞重複計算
                p1_denom += sum(train_matrix[i])
            else:
                p0_num += train_matrix[i]
                p0_denom += sum(train_matrix[i])
        # 計算每個單詞在c1中出現的概率,向量中的一個元素保存一個單詞的條件概率p(wi/c1)
        p1_vect = p1_num / p1_denom
        p0_vect = p0_num / p0_denom
        # p1_vect是[p(w1/c1),p(w2/c1)...p(wn/c1)],p0_vect是[p(w1/c0),p(w2/c0)...p(wn/c0)],p_abusive是p(c1)
        return p0_vect, p1_vect, p_abusive

    # 訓練函數改進
    # 1.如果某個p(wi/c)的值爲0,會導致整個p(w1/ci)p(w2/ci)...p(wn/ci)的乘積爲0,
    #   所以p_num初始化爲1,p_denom初始化爲2來避免這種情況
    # 2.如果最後求得的概率向量中元素的值太小會造成內存下溢,
    #   所以對概率取對數來避免這種情況,log(p(wi/c))和p(wi/c)擁有相同的單調性
    def train_better(self, train_matrix, train_category):
        train_docs_num = len(train_matrix)
        words_num = len(train_matrix[0])
        # 計算侮辱類1的文檔總數,從而計算p(c1)的概率,p(c0)=1-p(c1),注意sum是將所有元素求和,應和len函數區分
        p_abusive = sum(train_category) / float(train_docs_num)
        # 創建長度爲words_num,元素爲0的矩陣
        p0_num = ones(words_num)
        p1_num = ones(words_num)
        p0_denom = 2.0
        p1_denom = 2.0
        for i in range(train_docs_num):
            if train_category[i] == 1:
                # 向量中每個元素存儲的是某個單詞在c1中出現的次數
                p1_num += train_matrix[i]
                # 計算c1中所有單詞總數,同一個詞重複計算
                p1_denom += sum(train_matrix[i])
            else:
                p0_num += train_matrix[i]
                p0_denom += sum(train_matrix[i])
        # 計算每個單詞在c1中出現的概率,向量中的一個元素保存一個單詞的條件概率p(wi/c1)
        p1_vect = log(p1_num / p1_denom)
        p0_vect = log(p0_num / p0_denom)
        # p1_vect是[p(w1/c1),p(w2/c1)...p(wn/c1)],
        # p0_vect是[p(w1/c0),p(w2/c0)...p(wn/c0)],p_abusive是p(c1)
        return p0_vect, p1_vect, p_abusive

    # 貝葉斯分類函數,假設每個詞出現的概率相同,即p(wi)=p(wj)。由於僅比較大小,所以分母p(w)不用計算
    # 數學中有公式ln(a*b) = ln(a)+ln(b)由於在訓練過程中我們隊概率都取了對數,
    # 所以有ln(p(w1/ci)p(w2/ci...p(wn/ci))= ln(p(w1/ci))+ln(p(w2/ci))...+ln(p(wn/ci))
    # 同理,ln(p(w/ci)p(ci)) = ln(p(w/ci))+ln(p(ci))
    def classify(self, vec2_classify, p0_vec, p1_vec, p_class1):
        p1 = sum(vec2_classify * p1_vec) + log(p_class1)
        p0 = sum(vec2_classify * p0_vec) + log(1.0 - p_class1)
        if p1 > p0:
            return 1
        else:
            return 0

    def test_classify(self):
        posting_list, class_vec = self.load_data_set()
        vocab_list = self.create_vocab_list(posting_list)
        train_mat = []
        for post_in_doc in posting_list:
            train_mat.append(self.set_words2vec(vocab_list,post_in_doc))
        p0_vec,p1_vec,p_abusive = self.train_better(array(train_mat),array(class_vec))
        test_entity = ['stupid', 'garbage']
        this_doc = array(self.set_words2vec(vocab_list,test_entity))
        print test_entity,'的分類爲:',self.classify(this_doc,p0_vec,p1_vec,p_abusive)

bayes = Bayes()
bayes.test_classify()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章