機器學習筆記之樸素貝葉斯分類演算法

birdlove1987發表於2017-01-22
樸素貝葉斯分類演算法:
優點:在資料較少的情況下仍然有效,可以處理多分類問題。
缺點:對於輸入資料的準備方式較為敏感。
適用資料型別:標稱型資料(離散型資料)

演算法原理:
對於某一個條件,這個條件下哪個類的個數最多,這個情況就可能是這個類的。其實就是max{P(y1|X),P(y2|X)...P(yn|X)},X是條件(屬性),y是類。
ps:是不是感覺有點像k-近鄰演算法的概率表達形式,另外肯定有人會問樸素貝葉斯中的'樸素是什麼意思',樸素要表達的意思就是其假設了各個特徵之間是獨立的。特徵獨立的好處是可以大大降低需要訓練的特徵樣本數。

演算法流程:
收集資料:即建立訓練測試資料集。
準備資料:資料型別最好是轉化成數值型或者布林型別資料
分析資料:有大量資料特徵是,由於是概率表示的原因繪製特徵作用不大,用直方圖表示效果更好
訓練演算法:計算不同的獨立特徵的條件概率
測試演算法:即求出誤差率
使用演算法:樸素貝葉斯比較常用的分類場景是文件分類

說道貝葉斯公式,我們要先了解條件概率公司:

               

這個公式的意思就是在y事件成立是x事件發生的概率是多少。
下面我們就可以看看貝葉斯公式:



是不是感覺這個公式很簡潔,但是在機器學習這個領域這個公式的用處那就太大了!
其實這個公式很容易理解,就是當你想求當y事件成立x事件發生的概率時,可以轉換為求當x事件成立時y事件發生的概率,雖然你現在可能感覺不出這樣的轉換有什麼便利,但是在實際問題中這樣的轉換可以大大的降低求解的難度

當這個y事件使用很多個子事件組成的時候,這個概率求起來還是很複雜的,但是如果這些子事件都是相互獨立的呢?那就簡單多了,這也就引出了樸素貝葉斯公式:



問題就這樣被各個擊破了。

下面讓我們來看一個小例子:

最近直播網站非常火爆,這些網站中的彈幕功能也形成了一種彈幕文化,但是總會有一些噴子在裡面隨意說一些讓人憤怒的話,我們能不能讓機器自己去遮蔽他們呢。這就用上了樸素貝葉斯分類演算法。

首先我們先抓取幾條彈幕,並對它們進行簡單的處理,如詞彙切分,去標點符號等,由於我是用的pycharm IDE對中文支援不好,我把這些漢字變成了拼音編碼(如果有拼錯的請原諒我把,我小學語文是數學老師教的。。),因為這些是我們的訓練資料,所以我們還要人為的判斷它們是積極的彈幕還是消極的彈幕:0代表積極的彈幕,1代表消極的彈幕

def createDataSet():
    myData=[['zhubo', 'de', 'jishu', 'wo', 'renwei', 'hen', 'lihai'],
            # 主播 的 技術 我 認為 很 厲害
           ['zhubo', 'shi', 'yi', 'ge', 'sb', 'laji', 'caib', 'hahaha'],
            # 主播 是 一 個 sb 垃圾 菜b 哈哈哈
           ['caozuo', 'shuiping', 'tai', 'laiji', 'zhege', 'fenduan', 'wo', 'suibianniu'],
            #操作 水平 太 垃圾 這種 分段 我 隨便虐
           ['xinteng', 'zhubo', 'bieli', 'pinzi', 'jiayou'],
            #心疼 主播 別理 噴子 加油
           ['zhubo', 'wande', 'bucuo', 'nengbuneng', 'bang', 'wo', 'da', 'yiju', 'paiweisai'],
            #主播 玩的 不錯 能不能 幫 我 打 一局 排位賽
           ['zhezhong', 'shuiping', 'haiyoulian', 'zhibo', 'sb', 'laji']]
            #這種 水平 還有臉 直播 sb 垃圾
    lables = [0,1,1,0,0,1]
    return myData,lables

然後我們將由這幾條彈幕建立一個詞彙表,python裡的set剛好是不重複容器。

def createVocabList(dataSet):
    vocabSet = set([])  
    for document in dataSet:
        vocabSet = vocabSet | set(document) 
    return list(vocabSet)

這樣我們就建立了一個不重複的詞彙表

['caozuo', 'ge', 'zhezhong', 'tai', 'zhege', 'paiweisai', 'jishu', 'pinzi', 'hen',
 'caib', 'yi', 'jiayou', 'laiji', 'wo', 'de', 'da', 'bang', 'zhibo', 'renwei', 'sb', 'bucuo',  'haiyoulian', 'laji', 'fenduan', 'wande', 'suibianniu', 'lihai', 'xinteng', 'zhubo', 'bieli',  'nengbuneng', 'yiju', 'hahaha', 'shi', 'shuiping']

然後我們需要一個函式,來判斷每一條彈幕是否在這個詞彙表中出現:

def showTimeInTheLine(data, dataMap):
    result = [0]*len(data)
    for pinyin in dataMap :
        if pinyin  in data :
           result [data .index(pinyin)] = 1
        else: print "this pinyin: %s is not in my dataMap" % pinyin 
    return result

我們使用第一條彈幕進行一下測試,結果:

[0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]
和我們的資料進行對比,結果是正確的

因為我們這是一個二分類問題,就是消極彈幕還是積極彈幕,所以我們要算出每一個結果的概率,以及我們的詞彙表在消極彈幕結果下的概率和在積極彈幕結果下的概率:

def train(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)     #資料有幾條
    numWords = len(trainMatrix[0])      #每條資料的大小
    pAbusive = sum(trainCategory)/float(numTrainDocs)   #積極類的概率
    p0Num = zeros(numWords); p1Num = zeros(numWords)
    p0Denom = 0.0; p1Denom = 0.0
    for i in range(numTrainDocs):    
        if trainCategory[i] == 1:    #消極類統計
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])
        else:                         #積極類統計
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    p1Vect = p1Num/p1Denom           #在消極類中詞彙表中每個詞的概率
    p0Vect = p0Num/p0Denom           #在積極類中詞彙表中每個詞的概率
    return p0Vect,p1Vect,pAbusive



經過計算可以看出,積極類的概率是0.5 即P(x)
然後程式算出了詞彙表在積極類中每個詞的概率:
[ 0.        ,          0.        ,          0.        ,         0.        ,          0.        ,
  0.04761905,  0.04761905,  0.04761905, 0.04761905,   0.        ,
  0.        ,          0.04761905,  0.        ,         0.0952381 ,    0.04761905,
  0.04761905,  0.04761905,  0.        ,         0.04761905,   0.        ,
  0.04761905,  0.        ,          0.        ,         0.        ,           0.04761905,
  0.        ,          0.04761905,  0.04761905, 0.14285714,   0.04761905,
  0.04761905,  0.04761905,  0.        ,         0.        ,           0.               ]

程式也算出了詞彙表在積極類中每個詞的概率:
[ 0.04545455,  0.04545455,  0.04545455,  0.04545455,  0.04545455,
  0.        ,          0.        ,          0.        ,         0.        ,          0.04545455,
  0.04545455,  0.        ,          0.04545455, 0.04545455,  0.        ,
  0.        ,          0.        ,          0.04545455, 0.        ,        0.09090909,
  0.        ,          0.04545455,  0.09090909, 0.04545455,  0.        ,
  0.04545455,  0.        ,          0.        ,         0.04545455,  0.        ,
  0.        ,          0.        ,          0.04545455, 0.04545455,  0.09090909]

這樣我們便訓練好了一個可以用來分類的分類概率組:

下面我們輸入兩組自己發的彈幕來測試一下我們的樸素貝葉斯分類器:

def testing():
    myData,lebels = createDataSet()
    myList = createVocabList(myData )
    trainMat=[]
    for posting in myData :
        trainMat.append(showTimeInTheLine(myList  , posting  ))
    p0,p1,plable = train(array(trainMat),array(listClasses))
    testEntry01 = ['jiayou', 'bucuo', 'lihai']
                 #加油  不錯  厲害
    thisDM = array(showTimeInTheLine (myList, testEntry01))
    print testEntry,u'這條彈幕屬於: ',classify(thisDM,p0V,p1V,pAb)
    testEntry02 = ['sb', 'laji']
                 #sb  垃圾
    thisDM = array(showTimeInTheLine (myList, testEntry02))
    print testEntry,u'這條彈幕屬於: ' ,classify(thisDM ,p0V,p1V,pAb)

最後我們程式判斷的結果是:



這就是樸素貝葉斯分類的故事啦~


相關文章