樸素貝葉斯模型(Naive Bayes Model,NB)理解


1. Bayes 定理

  • P(A,B)=P(A|B)P(B);              
  • P(A,B)=P(B|A)P(A);  
  • P(A|B)=P(B|A)P(A)/P(B);    貝葉斯定理變形

2. 概率圖模型


2.1 定義

概率圖模型是一類用圖的形式表示隨機變量之間條件依賴關係的概率模型,是概率論與圖論的結合。
圖中的節點表示隨機變量,邊表示隨機變量之間的概率依賴關係.缺少邊的節點表示滿足條件獨立假設。

2.2 隨機變量的條件獨立

如果有P(A,B|C)=P(A|C)P(B|C),  則稱在給定事件C的條件下,兩個事件A和B獨立,這裏假設P(C)>0;

如:設A=2x+z;  B=y+z;  C=z;

在C確定的條件下 A,B是獨立的。如假設z=0(常數),則A和B沒有任何關聯。

  等價形式P(A|B,C)=P(A|C) 

 推導: P(A,B|C)=P(A|C)P(B|C);       ...1
     P(A,B|C)=P(A|B,C)P(B|C);    ...2

  聯合1,2式可以=> P(A|C)=P(A|B,C)

2.3概率圖模型的有向圖表示

利用有向圖來表示變量之間的概率依賴關係,典型應用就是貝葉斯網絡.

上圖Naive Bayes 可以表示爲: p(y,x1,x2,x3)=p(y).p(x1|y)p(x2|y)p(x3|y)

3. Naive Bayes Model


3.1 Bayes 決策理論思想

樸素貝葉斯是貝葉斯決策理論的一部分, 所以講述樸素貝葉斯之前有必要快速瞭解一下貝葉斯決策理論。

  假設我們有一個數據集,如下圖所示:

 

我們用P(c1|x,y) 表示數據點(x,y)屬於類別c1的概率(圖中紅色圓點的概率),用P(c2|x,y)表示數據點(x,y)屬於類別c2的概率(圖中綠色的三角形概率)。那麼對於一個新的數據點(x,y),我們就可以用一下規則來判斷它的類別。

  • If p(c1|x, y) > p(c2|x, y), then the class is c1.
  • If p(c2|x, y) > p(c1|x, y), then the class is c2.

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

3.2 Naive Bayes 公式推導

假設某個體有n項特徵(Feature),分別爲F1、F2、...、Fn。現有m個類別(Category),分別爲C1、C2、...、Cm

貝葉斯分類器就是計算出概率最大的那  個 分類,也就是求下面這個算式的最大值:P(C|F1,F2,...,Fn);  

  可以理解爲求 在屬性F1,F2,....Fn條件下,屬於各個類別Ci的概率,然後求出最大的那個P(Ci|F1,F2,...Fn) ,這樣就得到F1,F2,...Fn 屬於哪一類(Ci)了。

  使用貝葉斯原理可以寫成

   

  因爲對於每一個類別的Ci的概率都存在P(F1,F2,......Fn)所以只需要關注P(C)P(F1,F2.....Fn|C)

  寫成聯合概率的形式P(C,F1,F2...Fn)=P(C)P(F1,F2.....Fn|C)

  重複使用貝葉斯原理=>

  

  現在“樸素”的“條件獨立”(2中有推導)假設開始發揮作用:假設每個特徵F_i對於其他特徵F_j,j\neq i是條件獨立的。這就意味着

          

  對於i\ne j,所以聯合分佈模型可以表達爲

  

4. 例子


4.1 性別分類

下面是一組人類身體特徵的統計資料。

身體特徵資料統計
性別 身高(英尺) 體重(磅) 腳掌(英寸)
6 180 12
5.92 190 11
5.58 170 12
5.92 165 10
5 100 6
5.5 150 8
5.42 130 7
5.75 150 9

 

  已知某人身高6英尺、體重130磅,腳掌8英寸,請問該人是男是女?

  即,P(C|F1,F2,F3)的最大概率。

  根據上面的Naive Bayes Model       P(C|F1,F2,F3)=P(身高|性別) x P(體重|性別) x P(腳掌|性別) x P(性別)

  這裏的困難在於,由於身高、體重、腳掌都是連續變量,不能採用離散變量的方法計算概率。而且由於樣本太少,所以也無法分成區間計算。怎麼辦?

  這時,可以假設男性和女性的身高、體重、腳掌都是正態分佈,通過樣本計算出均值和方差,也就是得到正態分佈的密度函數。有了密度函數,就可以把值代入,  算出某一點的密度函數的值。

  比如,男性的身高是均值5.855、方差0.035的正態分佈。所以,男性的身高爲6英尺的概率的相對值等於1.5789(大於1並沒有關係,因爲這裏是密度函數的   值,只用來反映各個值的相對可能性)。

    

如上,我們就可以推出

 有了P(height|male),P(weight|male),...我們就可以得到

  P(height=6|male) x P(weight=130|male) x P(footsize=8|male) x P(male) 
    = 6.1984 x e-9

  P(height=6|female) x P(weight=130|female) x P(footsize=8|female) x P(female)
    = 5.3778 x e-4

可以看到,女性的概率比男性要高出將近10000倍,所以判斷該人爲女性。

4.2 使用Naive Bayes Model 實現髒話評論

已知如下圖的6條評論,以及它們所屬的類別,其中0表示正常言論,1表示需要過濾的髒話,使用Naive Bayes Model 預測最後兩句評論的類別




  • 分析:
根據上面Naive Bayes的知識,要知道一個評論屬於哪種類型,可以使用bayes定理,改爲求每一個詞在這個類別的概率,以及這個類別出現的概率,公式如下:



  • 訓練過程:
訓練評論:[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], ['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']]
已分類[0, 1, 0, 1, 0, 1]

訓練評論構成的唯一字典:['maybe', 'him', 'help', 'problems', 'so', 'I', 'dog', 'is', 'cute', 'love', 'buying', 'flea', 'how', 'food', 'licks', 'posting', 'has', 'take', 'stupid', 'steak', 'park', 'please', 'to', 'worthless', 'garbage', 'my', 'dalmation', 'mr', 'quit', 'not', 'ate', 'stop']
訓練評論向量化(0表未出現,1表示出現):[[0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,1, 1, 0, 0, 0, 0, 0, 0, 1], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0,0, 1, 0, 0, 0]]

返回:p0V 類別0的詞頻(各單詞在此類別所有詞彙的比重)向量   p1V類別1的詞頻向量

  • 分類過程:
將最後兩條評論向量化,使用訓練出來的詞頻計算未知向量的p(W|C),比較並得到分類結果
實現代碼:
__author__ = 'essex.user'
from numpy import *
from math import *
from pylab import *
#load example data
def loadDataSet():
    postingList=[['my', 'dog', 'has', 'flea','problems', 'help', 'please'],
                 ['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

# create a list of all the unique words in all of our documents
def createVocabList(dataSet):
    vocabSet = set([])
    for document in dataSet:
        vocabSet = vocabSet|set(document)
    return  list(vocabSet)

#文檔的向量(inputSet)是否在詞彙表(vacabList)中,則將輸出向量的下標變爲1
#將文字轉化爲關於0,1的向量
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0]*len(vocabList)
    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

#樸素貝葉斯分類器訓練函數1
def trainNB0(trainMatrix,trainCategory):
    #print("trainMatrix:%s\ntrainCategory:%s"%(trainMatrix,trainCategory))
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    #print("numTrainDocs=%d\tnumWords=%d"%(numTrainDocs,numWords))
    pAbusive = sum(trainCategory)/float(numTrainDocs) #3/6
    p0Num = zeros(numWords); p1Num = zeros(numWords)  #長度爲32的0向量
    #print("pAbusive=%d\np0Num:%s\np1Num:%s"%(pAbusive,p0Num,p1Num))
    p0Denom = 0.0; p1Denom = 0.0 #所有文檔中,屬於類別0和1的詞彙個數
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:
            p1Num += trainMatrix[i]
            #print("p1Num:",p1Num)
            p1Denom += sum(trainMatrix[i])
            #print("p1Denom",p1Denom)
        else:
            p0Num += trainMatrix[i]
            #print("p0Num:",p0Num)
            p0Denom += sum(trainMatrix[i])
    p1Vect = p1Num/p1Denom #change to log()
    p0Vect = p0Num/p0Denom #change to log()
    #print("p1Vect:",p1Vect)
    return p0Vect,p1Vect,pAbusive

#樸素貝葉斯分類器訓練函數--改進版
def trainNB(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)        #文檔數
    numWords = len(trainMatrix[0])         #詞彙表的詞彙數
    pAbusive = sum(trainCategory)/float(numTrainDocs) #帶侮辱性質類別的文檔數
    p0Num = ones(numWords)  #是侮辱性質類別的向量
    p1Num = ones(numWords)  #長度爲32的0向量
    p0Denom = 2.0; p1Denom = 2.0 #所有文檔中,屬於類別0和1的詞彙個數
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:
            p1Num += trainMatrix[i] #類別1的詞頻
            p1Denom += sum(trainMatrix[i])
        else:
            p0Num += trainMatrix[i] #類別0的詞頻
            p0Denom += sum(trainMatrix[i])
    p1Vect = log(p1Num/p1Denom)
    p0Vect = log(p0Num/p0Denom)
    return p0Vect,p1Vect,pAbusive

#樸素貝葉斯分類函數
def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    p1 = sum(vec2Classify * p1Vec) + log(pClass1)
    p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
    if p1>p0:
        return 1
    else:
        return 0

#分類器測試
def testingNB():
    listOPosts,listClasses = loadDataSet()
    myVocabList = createVocabList(listOPosts)
    trainMat=[]
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V,p1V,pAb = trainNB(array(trainMat),array(listClasses))
    testEntry = ['love', 'my', 'dalmation']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print(testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
    testEntry = ['stupid', 'garbage']
    thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
    print(testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
testingNB()

運行結果:
['love', 'my', 'dalmation'] classified as:  0
['stupid', 'garbage'] classified as:  1






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