1. 程式人生 > >機器學習實戰-樸素貝葉斯演算法

機器學習實戰-樸素貝葉斯演算法

樸素貝葉斯概述

樸素貝葉斯也是一個強大的分類演算法。其基本原理:假設現在有1,2,3,3種類別,現有一個數據a,其屬於這個3種類別的概率分別為p1(a),p2(a),p3(a)。如果這3個概率中p1(a)最大,那麼就把資料a歸為1類。
這道理好簡單啊,就算我們猜謎語也會猜一個可能性最大的嘛~~~
果然很樸素啊,但是呢,這裡還是有一個問題的,這裡的3個概率是怎麼計算出來的呢?

條件概率

為了計算概率,就得翻出概率論的知識了。
假設現有資料w=w0+w1+...+wn,好多維啊。。類別有c={c1,c2}2種類別。
那麼屬於c1,c2的概率就可以表示為:
p(c1|w)=p(w|

c1)p(c1)p(w)
p(c2|w)=p(w|c2)p(c2)p(w)
如果:
p(c1|w)>p(c2|w), 那麼w屬於c1類。
p(c1|w)<p(c2|w), 那麼w屬於c2類。
推廣到多個類別:

p(ci|w)=p(w|ci)p(ci)p(w)
對於不同的類別,計算該公式,比較大小就ok了。這裡的計算,其實只需要計算分子,因為分母部分對於任何類別來說都是一樣的。分子大就歸到哪一類。
這裡以《機器學習實戰》這本書上的例子為例。關於論壇留言,是否是侮辱性的判斷。
計算p(ci)
這裡的p(ci)就是ci類文件數除以文件總數。
計算p(w|ci)
p
(w|ci)
的計算相對麻煩點,這裡就要用到樸素貝葉斯的假設了,這裡把w展開,可以寫成p(w0,w1,w2,...,wn|ci),這裡假設所有的詞相互獨立(顯然是不成立,很多詞的出現是有關聯的,所以這叫樸素貝葉斯,樸素的內涵在於此)。有了這個假設,上面的概率可以轉化為p(w0|ci)p(w1|ci)...p(wn|ci),這個公式看起來沒簡化多少,其實計算的時候會簡單很多。
分解開來,單個拎出來看,p(w0|ci)可以理解為w0這個詞在ci這種文件中出現的概率,那麼只要把ci文件中出現w0詞數除以所有的詞數即可。

Ok,順利得到p(w|ci)p(ci)。我們就可以比較p(ci|w)大小來歸類了。

code

from numpy import *
#生成測試資料
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]
    return postingList,classvec
#生成一個文字集合,包含所有出現的詞
def createvocalist(dataSet):
    vocaset=set([])
    for document in dataSet:
        vocaset=vocaset | set(document)
    return list(vocaset)
#把每個文件的詞對應文字集合,對映成向量,如:[1,0,1,0,0...]
def setofWord2vec(vocalist,inputSet):
    returnVec=[0]*len(vocalist)
    for word in inputSet:
        if word in vocalist:
            returnVec[vocalist.index(word)] =1
        else:
            print "the word : %s is not in ..." % word
    return returnVec

def trainNB0(trainMatrix,trainclass):
    numdocs=len(trainMatrix)
    numWords=len(trainMatrix[0])
    #trainclass只有 0,1資料,求和相當於計算A=1的數量,再除以總數就是pA
    pA=sum(trainclass)/float(numdocs)
    p1num=ones(numWords)
    p0num=ones(numWords)
    p1sum=2.0
    p0sum=2.0
    for i in range(numdocs):
        if trainclass[i] == 1:
            p1num+=trainMatrix[i]#計算單個詞出現的數量
            p1sum+=sum(trainMatrix[i])#計算所有詞出現的數量
        else:
            p0num+=trainMatrix[i]
            p0sum+=sum(trainMatrix[i])
    p1vec=log(p1num/p1sum)#這裡相當於前面分子左邊的部分,在c1類別下,wi出現的概率
    p0vec=log(p0num/p0sum)
    return p0vec,p1vec,pA

def classifyNB(vec2class,p0Vec,p1Vec,pClass):
    #這裡的求和有點奇怪,因為按照公式是所有詞出現的概率相乘,然而這裡卻是求和,是因為前面用log來計算了。
    p1=sum(vec2class*p0Vec)+log(pClass)
    p0=sum(vec2class*p1Vec)+log(1.0-pClass)
    if p1>p0:
        return 1
    else:
        return 0
#測試分類
def testingNb():
    listdoc,listclass=loadDataSet()
    allwordlist=createvocalist(listdoc)
    trainMat=[]
    for doc in listdoc:
        trainMat.append(setofWord2vec(allwordlist,doc))
    p0v,p1v,pA=trainNB0(trainMat,listclass)
    testdoc=['love','my','jack']
    testdocvec=setofWord2vec(allwordlist,testdoc)
    print testdoc,'classified as:',classifyNB(testdocvec,p0v,p1v,pA)

end

參考:
《機器學習實戰》