基於機率論的分類方法:樸素貝葉斯

基於機率論的分類方法:樸素貝葉斯

1. 概述

貝葉斯分類是一類分類算法的總稱,這類算法均以貝葉斯定理爲基礎,故統稱爲貝葉斯分類。本章首先介紹貝葉斯分類算法的基礎——貝葉斯定理。最後,咱們經過實例來討論貝葉斯分類的中最簡單的一種: 樸素貝葉斯分類。html

2. 貝葉斯理論 & 條件機率

2.1 貝葉斯理論

咱們如今有一個數據集,它由兩類數據組成,數據分佈以下圖所示:python

咱們如今用 p1(x,y) 表示數據點 (x,y) 屬於類別 1(圖中用圓點表示的類別)的機率,用 p2(x,y) 表示數據點 (x,y) 屬於類別 2(圖中三角形表示的類別)的機率,那麼對於一個新數據點 (x,y),能夠用下面的規則來判斷它的類別:算法

若是 p1(x,y) > p2(x,y) ,那麼類別爲1
若是 p2(x,y) > p1(x,y) ,那麼類別爲2

也就是說,咱們會選擇高几率對應的類別。這就是貝葉斯決策理論的核心思想,即選擇具備最高几率的決策。apache

2.1.2 條件機率

若是你對 p(x,y|c1) 符號很熟悉,那麼能夠跳過本小節。bash

有一個裝了 7 塊石頭的罐子,其中 3 塊是白色的,4 塊是黑色的。若是從罐子中隨機取出一塊石頭,那麼是白色石頭的可能性是多少?因爲取石頭有 7 種可能,其中 3 種爲白色,因此取出白色石頭的機率爲 3/7 。那麼取到黑色石頭的機率又是多少呢?很顯然,是 4/7 。咱們使用 P(white) 來表示取到白色石頭的機率,其機率值能夠經過白色石頭數目除以總的石頭數目來獲得。less

若是這 7 塊石頭以下圖所示,放在兩個桶中,那麼上述機率應該如何計算?機器學習

計算 P(white) 或者 P(black) ,若是事先咱們知道石頭所在桶的信息是會改變結果的。這就是所謂的條件機率(conditional probablity)。假定計算的是從 B 桶取到白色石頭的機率,這個機率能夠記做 P(white|bucketB) ,咱們稱之爲「在已知石頭出自 B 桶的條件下,取出白色石頭的機率」。很容易獲得,P(white|bucketA) 值爲 2/4 ,P(white|bucketB) 的值爲 1/3 。函數

條件機率的計算公式以下post

P(white|bucketB) = P(white and bucketB) / P(bucketB)學習

首先,咱們用 B 桶中白色石頭的個數除以兩個桶中總的石頭數,獲得 P(white and bucketB) = 1/7 .其次,因爲 B 桶中有 3 塊石頭,而總石頭數爲 7 ,因而 P(bucketB) 就等於 3/7 。因而又 P(white|bucketB) = P(white and bucketB) / P(bucketB) = (1/7) / (3/7) = 1/3 。

另一種有效計算條件機率的方法稱爲貝葉斯準則。貝葉斯準則告訴咱們如何交換條件機率中的條件與結果,即若是已知 P(x|c),要求 P(c|x),那麼可使用下面的計算方法:

使用條件機率來分類

上面咱們提到貝葉斯決策理論要求計算兩個機率 p1(x, y) 和 p2(x, y):

若是 p1(x, y) > p2(x, y), 那麼屬於類別 1;
若是 p2(x, y) > p1(X, y), 那麼屬於類別 2.

這並非貝葉斯決策理論的全部內容。使用 p1() 和 p2() 只是爲了儘量簡化描述,而真正須要計算和比較的是 p(c1|x, y) 和 p(c2|x, y) .這些符號所表明的具體意義是: 給定某個由 x、y 表示的數據點,那麼該數據點來自類別 c1 的機率是多少?數據點來自類別 c2 的機率又是多少?注意這些機率與機率 p(x, y|c1) 並不同,不過可使用貝葉斯準則來交換機率中條件與結果。具體地,應用貝葉斯準則獲得:

使用上面這些定義,能夠定義貝葉斯分類準則爲:

若是 P(c1|x, y) > P(c2|x, y), 那麼屬於類別 c1;
若是 P(c2|x, y) > P(c1|x, y), 那麼屬於類別 c2.

在文檔分類中,整個文檔(如一封電子郵件)是實例,而電子郵件中的某些元素則構成特徵。咱們能夠觀察文檔中出現的詞,並把每一個詞做爲一個特徵,而每一個詞的出現或者不出現做爲該特徵的值,這樣獲得的特徵數目就會跟詞彙表中的詞的數目同樣多。

咱們假設特徵之間 相互獨立 。所謂 獨立(independence) 指的是統計意義上的獨立,即一個特徵或者單詞出現的可能性與它和其餘單詞相鄰沒有關係,好比說,「咱們」中的「我」和「們」出現的機率與這兩個字相鄰沒有任何關係。這個假設正是樸素貝葉斯分類器中 樸素(naive) 一詞的含義。樸素貝葉斯分類器中的另外一個假設是,每一個特徵同等重要。

Note: 樸素貝葉斯分類器一般有兩種實現方式: 一種基於伯努利模型實現,一種基於多項式模型實現。這裏採用前一種實現方式。該實現方式中並不考慮詞在文檔中出現的次數,只考慮出不出現,所以在這個意義上至關於假設詞是等權重的。

2.2 樸素貝葉斯 場景

機器學習的一個重要應用就是文檔的自動分類。

在文檔分類中,整個文檔(如一封電子郵件)是實例,而電子郵件中的某些元素則構成特徵。咱們能夠觀察文檔中出現的詞,並把每一個詞做爲一個特徵,而每一個詞的出現或者不出現做爲該特徵的值,這樣獲得的特徵數目就會跟詞彙表中的詞的數目同樣多。

樸素貝葉斯是上面介紹的貝葉斯分類器的一個擴展,是用於文檔分類的經常使用算法。下面咱們會進行一些樸素貝葉斯分類的實踐項目。

2.3 樸素貝葉斯 原理

樸素貝葉斯 工做原理

提取全部文檔中的詞條並進行去重
獲取文檔的全部類別
計算每一個類別中的文檔數目
對每篇訓練文檔:

對每一個類別:
    若是詞條出如今文檔中-->增長該詞條的計數值(for循環或者矩陣相加)
    增長全部詞條的計數值(此類別下詞條總數)

對每一個類別:

對每一個詞條:
    將該詞條的數目除以總詞條數目獲得的條件機率(P(詞條|類別))

返回該文檔屬於每一個類別的條件機率(P(類別|文檔的全部詞條))

2.4 樸素貝葉斯 開發流程

收集數據: 可使用任何方法。

準備數據: 須要數值型或者布爾型數據。

分析數據: 有大量特徵時,繪製特徵做用不大,此時使用直方圖效果更好。

訓練算法: 計算不一樣的獨立特徵的條件機率。

測試算法: 計算錯誤率。

使用算法: 一個常見的樸素貝葉斯應用是文檔分類。能夠在任意的分類場景中使用樸素貝葉斯分類器,不必定非要是文本。

2.5 樸素貝葉斯 算法特色

優勢: 在數據較少的狀況下仍然有效,能夠處理多類別問題。
缺點: 對於輸入數據的準備方式較爲敏感。
適用數據類型: 標稱型數據

2.6 樸素貝葉斯 項目案例

2.6.1 項目案例1

屏蔽社區留言板的侮辱性言論

2.6.1.1 項目概述

構建一個快速過濾器來屏蔽在線社區留言板上的侮辱性言論。若是某條留言使用了負面或者侮辱性的語言,那麼就將該留言標識爲內容不當。對此問題創建兩個類別: 侮辱類和非侮辱類,使用 1 和 0 分別表示。

2.6.1.2 開發流程

收集數據: 可使用任何方法

準備數據: 從文本中構建詞向量

分析數據: 檢查詞條確保解析的正確性

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

測試算法: 根據現實狀況修改分類器

使用算法: 對社區留言板言論進行分類

收集數據: 可使用任何方法

2.6.1.3 構造詞表

def loadDataSet():
    """
    建立數據集
    :return: 單詞列表postingList, 所屬類別classVec
    """
    postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], #[0,0,1,1,1......]
                   ['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']]
    classVec = [0, 1, 0, 1, 0, 1]  # 1 is abusive, 0 not
    return postingList, classVec

2.6.1.4 準備數據: 從文本中構建詞向量

def createVocabList(dataSet):
    """
    獲取全部單詞的集合
    :param dataSet: 數據集
    :return: 全部單詞的集合(即不含重複元素的單詞列表)
    """
    vocabSet = set([])  # create empty set
    for document in dataSet:
        # 操做符 | 用於求兩個集合的並集
        vocabSet = vocabSet | set(document)  # union of the two sets
    return list(vocabSet)


def setOfWords2Vec(vocabList, inputSet):
    """
    遍歷查看該單詞是否出現,出現該單詞則將該單詞置1
    :param vocabList: 全部單詞集合列表
    :param inputSet: 輸入數據集
    :return: 匹配列表[0,1,0,1...],其中 1與0 表示詞彙表中的單詞是否出如今輸入的數據集中
    """
    # 建立一個和詞彙表等長的向量,並將其元素都設置爲0
    returnVec = [0] * len(vocabList)# [0,0......]
    # 遍歷文檔中的全部單詞,若是出現了詞彙表中的單詞,則將輸出的文檔向量中的對應值設爲1
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)] = 1
        else:
            print "the word: %s is not in my Vocabulary!" % word
    return returnVec

2.6.1.5 分析數據: 檢查詞條確保解析的正確性

檢查函數執行狀況,檢查詞表,不出現重複單詞,須要的話,能夠對其進行排序。

>>> listOPosts, listClasses = bayes.loadDataSet()
>>> myVocabList = bayes.createVocabList(listOPosts)
>>> myVocabList
['cute', 'love', 'help', 'garbage', 'quit', 'I', 'problems', 'is', 'park',
'stop', 'flea', 'dalmation', 'licks', 'food', 'not', 'him', 'buying', 'posting', 'has', 'worthless', 'ate', 'to', 'maybe', 'please', 'dog', 'how',
'stupid', 'so', 'take', 'mr', 'steak', 'my']

檢查函數有效性。例如:myVocabList 中索引爲 2 的元素是什麼單詞?應該是是 help 。該單詞在第一篇文檔中出現了,如今檢查一下看看它是否出如今第四篇文檔中。

>>> bayes.setOfWords2Vec(myVocabList, listOPosts[0])
[0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1]

>>> bayes.setOfWords2Vec(myVocabList, listOPosts[3])
[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]

2.6.1.6 訓練算法: 從詞向量計算機率

如今已經知道了一個詞是否出如今一篇文檔中,也知道該文檔所屬的類別。接下來咱們重寫貝葉斯準則,將以前的 x, y 替換爲 w. 粗體的 w 表示這是一個向量,即它由多個值組成。在這個例子中,數值個數與詞彙表中的詞個數相同。

咱們使用上述公式,對每一個類計算該值,而後比較這兩個機率值的大小。

首先能夠經過類別 i (侮辱性留言或者非侮辱性留言)中的文檔數除以總的文檔數來計算機率 p(ci) 。接下來計算 p(w | ci) ,這裏就要用到樸素貝葉斯假設。若是將 w 展開爲一個個獨立特徵,那麼就能夠將上述機率寫做 p(w0, w1, w2...wn | ci) 。這裏假設全部詞都互相獨立,該假設也稱做條件獨立性假設(例如 A 和 B 兩我的拋骰子,機率是互不影響的,也就是相互獨立的,A 拋 2點的同時 B 拋 3 點的機率就是 1/6 * 1/6),它意味着可使用 p(w0 | ci)p(w1 | ci)p(w2 | ci)...p(wn | ci) 來計算上述機率,這樣就極大地簡化了計算的過程。

2.6.1.7 樸素貝葉斯分類器訓練函數

def _trainNB0(trainMatrix, trainCategory):
    """
    訓練數據原版
    :param trainMatrix: 文件單詞矩陣 [[1,0,1,1,1....],[],[]...]
    :param trainCategory: 文件對應的類別[0,1,1,0....],列表長度等於單詞矩陣數,其中的1表明對應的文件是侮辱性文件,0表明不是侮辱性矩陣
    :return:
    """
    # 文件數
    numTrainDocs = len(trainMatrix)
    # 單詞數
    numWords = len(trainMatrix[0])
    # 侮辱性文件的出現機率,即trainCategory中全部的1的個數,
    # 表明的就是多少個侮辱性文件,與文件的總數相除就獲得了侮辱性文件的出現機率
    pAbusive = sum(trainCategory) / float(numTrainDocs)
    # 構造單詞出現次數列表
    p0Num = zeros(numWords) # [0,0,0,.....]
    p1Num = zeros(numWords) # [0,0,0,.....]

    # 整個數據集單詞出現總數
    p0Denom = 0.0
    p1Denom = 0.0
    for i in range(numTrainDocs):
        # 是不是侮辱性文件
        if trainCategory[i] == 1:
            # 若是是侮辱性文件,對侮辱性文件的向量進行加和
            p1Num += trainMatrix[i] #[0,1,1,....] + [0,1,1,....]->[0,2,2,...]
            # 對向量中的全部元素進行求和,也就是計算全部侮辱性文件中出現的單詞總數
            p1Denom += sum(trainMatrix[i])
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    # 類別1,即侮辱性文檔的[P(F1|C1),P(F2|C1),P(F3|C1),P(F4|C1),P(F5|C1)....]列表
    # 即 在1類別下,每一個單詞出現的機率
    p1Vect = p1Num / p1Denom# [1,2,3,5]/90->[1/90,...]
    # 類別0,即正常文檔的[P(F1|C0),P(F2|C0),P(F3|C0),P(F4|C0),P(F5|C0)....]列表
    # 即 在0類別下,每一個單詞出現的機率
    p0Vect = p0Num / p0Denom
    return p0Vect, p1Vect, pAbusive

2.6.1.8 測試算法: 根據現實狀況修改分類器

http://www.cnblogs.com/apache...

相關文章
相關標籤/搜索