機器學習實戰教程(四):樸素貝葉斯基礎篇之言論過濾器

原文連接: Jack-Cui,cuijiahua.com/blog/2017/1…html

1、前言

樸素貝葉斯算法是有監督的學習算法,解決的是分類問題,如客戶是否流失、是否值得投資、信用等級評定等多分類問題。該算法的優勢在於簡單易懂、學習效率高、在某些領域的分類問題中可以與決策樹、神經網絡相媲美。但因爲該算法以自變量之間的獨立(條件特徵獨立)性和連續變量的正態性假設爲前提,就會致使算法精度在某種程度上受影響。python

本篇文章將從樸素貝葉斯推斷原理開始講起,經過實例進行輔助講解。最後,使用Python3編程實現一個簡單的言論過濾器。git

2、樸素貝葉斯理論

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

一、貝葉斯決策理論

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

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

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

也就是說,咱們會選擇高几率對應的類別。這就是貝葉斯決策理論的核心思想,即選擇具備最高几率的決策。已經瞭解了貝葉斯決策理論的核心思想,那麼接下來,就是學習如何計算p1和p2機率。數組

二、條件機率

在學習計算p1 和p2機率以前,咱們須要瞭解什麼是條件機率(Condittional probability),就是指在事件B發生的狀況下,事件A發生的機率,用P(A|B)來表示。bash

根據文氏圖,能夠很清楚地看到在事件B發生的狀況下,事件A發生的機率就是P(A∩B)除以P(B)。網絡

所以,app

同理可得,

因此,

這就是條件機率的計算公式。

三、全機率公式

除了條件機率之外,在計算p1和p2的時候,還要用到全機率公式,所以,這裏繼續推導全機率公式。

假定樣本空間S,是兩個事件A與A'的和。

上圖中,紅色部分是事件A,綠色部分是事件A',它們共同構成了樣本空間S。

在這種狀況下,事件B能夠劃分紅兩個部分。

在上一節的推導當中,咱們已知

因此,

這就是全機率公式。它的含義是,若是A和A'構成樣本空間的一個劃分,那麼事件B的機率,就等於A和A'的機率分別乘以B對這兩個事件的條件機率之和。

將這個公式代入上一節的條件機率公式,就獲得了條件機率的另外一種寫法:

四、貝葉斯推斷

對條件機率公式進行變形,能夠獲得以下形式:

咱們把P(A)稱爲"先驗機率"(Prior probability),即在B事件發生以前,咱們對A事件機率的一個判斷。

P(A|B)稱爲"後驗機率"(Posterior probability),即在B事件發生以後,咱們對A事件機率的從新評估。

P(B|A)/P(B)稱爲"可能性函數"(Likelyhood),這是一個調整因子,使得預估機率更接近真實機率。

因此,條件機率能夠理解成下面的式子:

後驗機率&emsp;=&emsp;先驗機率 x 調整因子
複製代碼

這就是貝葉斯推斷的含義。咱們先預估一個"先驗機率",而後加入實驗結果,看這個實驗究竟是加強仍是削弱了"先驗機率",由此獲得更接近事實的"後驗機率"

在這裏,若是"可能性函數"P(B|A)/P(B)>1,意味着"先驗機率"被加強,事件A的發生的可能性變大;若是"可能性函數"=1,意味着B事件無助於判斷事件A的可能性;若是"可能性函數"<1,意味着"先驗機率"被削弱,事件A的可能性變小。

爲了加深對貝葉斯推斷的理解,咱們舉一個例子。

兩個如出一轍的碗,一號碗有30顆水果糖和10顆巧克力糖,二號碗有水果糖和巧克力糖各20顆。如今隨機選擇一個碗,從中摸出一顆糖,發現是水果糖。請問這顆水果糖來自一號碗的機率有多大?

咱們假定,H1表示一號碗,H2表示二號碗。因爲這兩個碗是同樣的,因此P(H1)=P(H2),也就是說,在取出水果糖以前,這兩個碗被選中的機率相同。所以,P(H1)=0.5,咱們把這個機率就叫作"先驗機率",即沒有作實驗以前,來自一號碗的機率是0.5。

再假定,E表示水果糖,因此問題就變成了在已知E的狀況下,來自一號碗的機率有多大,即求P(H1|E)。咱們把這個機率叫作"後驗機率",即在E事件發生以後,對P(H1)的修正。

根據條件機率公式,獲得

已知,P(H1)等於0.5,P(E|H1)爲一號碗中取出水果糖的機率,等於30÷(30+10)=0.75,那麼求出P(E)就能夠獲得答案。根據全機率公式,

因此,

將數字代入原方程,獲得

這代表,來自一號碗的機率是0.6。也就是說,取出水果糖以後,H1事件的可能性獲得了加強。

同時再思考一個問題,在使用該算法的時候,若是不須要知道具體的類別機率,即上面P(H1|E)=0.6,只須要知道所屬類別,即來自一號碗,咱們有必要計算P(E)這個全機率嗎?要知道咱們只須要比較 P(H1|E)和P(H2|E)的大小,找到那個最大的機率就能夠。既然如此,二者的分母都是相同的,那咱們只須要比較分子便可。即比較P(E|H1)P(H1)和P(E|H2)P(H2)的大小,因此爲了減小計算量,全機率公式在實際編程中能夠不使用

五、樸素貝葉斯推斷

理解了貝葉斯推斷,那麼讓咱們繼續看看樸素貝葉斯。貝葉斯和樸素貝葉斯的概念是不一樣的,區別就在於「樸素」二字,樸素貝葉斯對條件個機率分佈作了條件獨立性的假設。 好比下面的公式,假設有n個特徵:

因爲每一個特徵都是獨立的,咱們能夠進一步拆分公式 :

)

這樣咱們就能夠進行計算了。若是有些迷糊,讓咱們從一個例子開始講起,你會看到貝葉斯分類器很好懂,一點都不難。

某個醫院早上來了六個門診的病人,他們的狀況以下表所示:

如今又來了第七個病人,是一個打噴嚏的建築工人。請問他患上感冒的機率有多大?

根據貝葉斯定理:

可得:

根據樸素貝葉斯條件獨立性的假設可知,"打噴嚏"和"建築工人"這兩個特徵是獨立的,所以,上面的等式就變成了

這裏能夠計算:

所以,這個打噴嚏的建築工人,有66%的機率是得了感冒。同理,能夠計算這個病人患上過敏或腦震盪的機率。比較這幾個機率,就能夠知道他最可能得什麼病。

這就是貝葉斯分類器的基本方法:在統計資料的基礎上,依據某些特徵,計算各個類別的機率,從而實現分類。

一樣,在編程的時候,若是不須要求出所屬類別的具體機率,P(打噴嚏) = 0.5和P(建築工人) = 0.33的機率是能夠不用求的。

3、動手實戰

說了這麼多,沒點實踐編程怎麼行?

以在線社區留言爲例。爲了避免影響社區的發展,咱們要屏蔽侮辱性的言論,因此要構建一個快速過濾器,若是某條留言使用了負面或者侮辱性的語言,那麼就將該留言標誌爲內容不當。過濾這類內容是一個很常見的需求。對此問題創建兩個類型:侮辱類和非侮辱類,使用1和0分別表示。

咱們把文本當作單詞向量或者詞條向量,也就是說將句子轉換爲向量。考慮出現全部文檔中的單詞,再決定將哪些單詞歸入詞彙表或者說所要的詞聚集合,而後必需要將每一篇文檔轉換爲詞彙表上的向量。簡單起見,咱們先假設已經將本文切分完畢,存放到列表中,並對詞彙向量進行分類標註。編寫代碼以下:

# -*- coding: UTF-8 -*-
 
""" 函數說明:建立實驗樣本 Parameters: 無 Returns: postingList - 實驗樣本切分的詞條 classVec - 類別標籤向量 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
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表明侮辱性詞彙,0表明不是
    return postingList,classVec
 
if __name__ == '__main__':
    postingLIst, classVec = loadDataSet()
    for each in postingLIst:
        print(each)
    print(classVec)
複製代碼

從運行結果能夠看出,咱們已經將postingList是存放詞條列表中,classVec是存放每一個詞條的所屬類別,1表明侮辱類 ,0表明非侮辱類。

繼續編寫代碼,前面咱們已經說過咱們要先建立一個詞彙表,並將切分好的詞條轉換爲詞條向量。

# -*- coding: UTF-8 -*-
 
""" 函數說明:建立實驗樣本 Parameters: 無 Returns: postingList - 實驗樣本切分的詞條 classVec - 類別標籤向量 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
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表明侮辱性詞彙,0表明不是
    return postingList,classVec
 
""" 函數說明:根據vocabList詞彙表,將inputSet向量化,向量的每一個元素爲1或0 Parameters: vocabList - createVocabList返回的列表 inputSet - 切分的詞條列表 Returns: returnVec - 文檔向量,詞集模型 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0] * len(vocabList)                                    #建立一個其中所含元素都爲0的向量
    for word in inputSet:                                                #遍歷每一個詞條
        if word in vocabList:                                            #若是詞條存在於詞彙表中,則置1
            returnVec[vocabList.index(word)] = 1
        else: print("the word: %s is not in my Vocabulary!" % word)
    return returnVec                                                    #返回文檔向量
 
""" 函數說明:將切分的實驗樣本詞條整理成不重複的詞條列表,也就是詞彙表 Parameters: dataSet - 整理的樣本數據集 Returns: vocabSet - 返回不重複的詞條列表,也就是詞彙表 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
def createVocabList(dataSet):
    vocabSet = set([])                      #建立一個空的不重複列表
    for document in dataSet:               
        vocabSet = vocabSet | set(document) #取並集
    return list(vocabSet)
 
if __name__ == '__main__':
    postingList, classVec = loadDataSet()
    print('postingList:\n',postingList)
    myVocabList = createVocabList(postingList)
    print('myVocabList:\n',myVocabList)
    trainMat = []
    for postinDoc in postingList:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    print('trainMat:\n', trainMat)
複製代碼

從運行結果能夠看出,postingList是原始的詞條列表,myVocabList是詞彙表。myVocabList是全部單詞出現的集合,沒有重複的元素。詞彙表是用來幹什麼的?沒錯,它是用來將詞條向量化的,一個單詞在詞彙表中出現過一次,那麼就在相應位置記做1,若是沒有出現就在相應位置記做0。trainMat是全部的詞條向量組成的列表。它裏面存放的是根據myVocabList向量化的詞條向量。

咱們已經獲得了詞條向量。接下來,咱們就能夠經過詞條向量訓練樸素貝葉斯分類器。

# -*- coding: UTF-8 -*-
import numpy as np
 
""" 函數說明:建立實驗樣本 Parameters: 無 Returns: postingList - 實驗樣本切分的詞條 classVec - 類別標籤向量 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
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表明侮辱性詞彙,0表明不是
    return postingList,classVec
 
""" 函數說明:根據vocabList詞彙表,將inputSet向量化,向量的每一個元素爲1或0 Parameters: vocabList - createVocabList返回的列表 inputSet - 切分的詞條列表 Returns: returnVec - 文檔向量,詞集模型 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0] * len(vocabList)                                    #建立一個其中所含元素都爲0的向量
    for word in inputSet:                                                #遍歷每一個詞條
        if word in vocabList:                                            #若是詞條存在於詞彙表中,則置1
            returnVec[vocabList.index(word)] = 1
        else: print("the word: %s is not in my Vocabulary!" % word)
    return returnVec                                                    #返回文檔向量
 
""" 函數說明:將切分的實驗樣本詞條整理成不重複的詞條列表,也就是詞彙表 Parameters: dataSet - 整理的樣本數據集 Returns: vocabSet - 返回不重複的詞條列表,也就是詞彙表 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
def createVocabList(dataSet):
    vocabSet = set([])                      #建立一個空的不重複列表
    for document in dataSet:
        vocabSet = vocabSet | set(document) #取並集
    return list(vocabSet)
 
""" 函數說明:樸素貝葉斯分類器訓練函數 Parameters: trainMatrix - 訓練文檔矩陣,即setOfWords2Vec返回的returnVec構成的矩陣 trainCategory - 訓練類別標籤向量,即loadDataSet返回的classVec Returns: p0Vect - 非侮辱類的條件機率數組 p1Vect - 侮辱類的條件機率數組 pAbusive - 文檔屬於侮辱類的機率 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-12 """
def trainNB0(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)                            #計算訓練的文檔數目
    numWords = len(trainMatrix[0])                            #計算每篇文檔的詞條數
    pAbusive = sum(trainCategory)/float(numTrainDocs)        #文檔屬於侮辱類的機率
    p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)    #建立numpy.zeros數組,詞條出現數初始化爲0
    p0Denom = 0.0; p1Denom = 0.0                            #分母初始化爲0
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:                            #統計屬於侮辱類的條件機率所需的數據,即P(w0|1),P(w1|1),P(w2|1)···
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])
        else:                                                #統計屬於非侮辱類的條件機率所需的數據,即P(w0|0),P(w1|0),P(w2|0)···
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    p1Vect = p1Num/p1Denom                                      
    p0Vect = p0Num/p0Denom         
    return p0Vect,p1Vect,pAbusive                            #返回屬於侮辱類的條件機率數組,屬於非侮辱類的條件機率數組,文檔屬於侮辱類的機率
 
if __name__ == '__main__':
    postingList, classVec = loadDataSet()
    myVocabList = createVocabList(postingList)
    print('myVocabList:\n', myVocabList)
    trainMat = []
    for postinDoc in postingList:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    p0V, p1V, pAb = trainNB0(trainMat, classVec)
    print('p0V:\n', p0V)
    print('p1V:\n', p1V)
    print('classVec:\n', classVec)
    print('pAb:\n', pAb)
複製代碼

運行結果以下,p0V存放的是每一個單詞屬於類別0,也就是非侮辱類詞彙的機率。好比p0V的倒數第6個機率,就是stupid這個單詞屬於非侮辱類的機率爲0。同理,p1V的倒數第6個機率,就是stupid這個單詞屬於侮辱類的機率爲0.15789474,也就是約等於15.79%的機率。咱們知道stupid的中文意思是蠢貨,難聽點的叫法就是傻逼。顯而易見,這個單詞屬於侮辱類。pAb是全部侮辱類的樣本佔全部樣本的機率,從classVec中能夠看出,一用有3個侮辱類,3個非侮辱類。因此侮辱類的機率是0.5。所以p0V存放的就是P(非侮辱類 | him) = 0.0833,P(非侮辱類 | is) = 0.0417,一直到P(非侮辱類 | dog) = 0.0417,這些單詞的條件機率。同理,p1V存放的就是各個單詞屬於侮辱類的條件機率。pAb就是先驗機率。

已經訓練好分類器,接下來,使用分類器進行分類。

# -*- coding: UTF-8 -*-
import numpy as np
from functools import reduce
 
""" 函數說明:建立實驗樣本 Parameters: 無 Returns: postingList - 實驗樣本切分的詞條 classVec - 類別標籤向量 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
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表明侮辱性詞彙,0表明不是
    return postingList,classVec                                                                #返回實驗樣本切分的詞條和類別標籤向量
 
""" 函數說明:將切分的實驗樣本詞條整理成不重複的詞條列表,也就是詞彙表 Parameters: dataSet - 整理的樣本數據集 Returns: vocabSet - 返回不重複的詞條列表,也就是詞彙表 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
def createVocabList(dataSet):
    vocabSet = set([])                      #建立一個空的不重複列表
    for document in dataSet:                
        vocabSet = vocabSet | set(document) #取並集
    return list(vocabSet)
 
""" 函數說明:根據vocabList詞彙表,將inputSet向量化,向量的每一個元素爲1或0 Parameters: vocabList - createVocabList返回的列表 inputSet - 切分的詞條列表 Returns: returnVec - 文檔向量,詞集模型 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-11 """
def setOfWords2Vec(vocabList, inputSet):
    returnVec = [0] * len(vocabList)                                    #建立一個其中所含元素都爲0的向量
    for word in inputSet:                                                #遍歷每一個詞條
        if word in vocabList:                                            #若是詞條存在於詞彙表中,則置1
            returnVec[vocabList.index(word)] = 1
        else: print("the word: %s is not in my Vocabulary!" % word)
    return returnVec                                                    #返回文檔向量
 
 
""" 函數說明:樸素貝葉斯分類器訓練函數 Parameters: trainMatrix - 訓練文檔矩陣,即setOfWords2Vec返回的returnVec構成的矩陣 trainCategory - 訓練類別標籤向量,即loadDataSet返回的classVec Returns: p0Vect - 非侮辱類的條件機率數組 p1Vect - 侮辱類的條件機率數組 pAbusive - 文檔屬於侮辱類的機率 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-12 """
def trainNB0(trainMatrix,trainCategory):
    numTrainDocs = len(trainMatrix)                            #計算訓練的文檔數目
    numWords = len(trainMatrix[0])                            #計算每篇文檔的詞條數
    pAbusive = sum(trainCategory)/float(numTrainDocs)        #文檔屬於侮辱類的機率
    p0Num = np.zeros(numWords); p1Num = np.zeros(numWords)    #建立numpy.zeros數組,
    p0Denom = 0.0; p1Denom = 0.0                            #分母初始化爲0.0
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:                            #統計屬於侮辱類的條件機率所需的數據,即P(w0|1),P(w1|1),P(w2|1)···
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])
        else:                                                #統計屬於非侮辱類的條件機率所需的數據,即P(w0|0),P(w1|0),P(w2|0)···
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    p1Vect = p1Num/p1Denom                                    #相除 
    p0Vect = p0Num/p0Denom          
    return p0Vect,p1Vect,pAbusive                            #返回屬於侮辱類的條件機率數組,屬於非侮辱類的條件機率數組,文檔屬於侮辱類的機率
 
""" 函數說明:樸素貝葉斯分類器分類函數 Parameters: vec2Classify - 待分類的詞條數組 p0Vec - 侮辱類的條件機率數組 p1Vec -非侮辱類的條件機率數組 pClass1 - 文檔屬於侮辱類的機率 Returns: 0 - 屬於非侮辱類 1 - 屬於侮辱類 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-12 """
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    p1 = reduce(lambda x,y:x*y, vec2Classify * p1Vec) * pClass1                #對應元素相乘
    p0 = reduce(lambda x,y:x*y, vec2Classify * p0Vec) * (1.0 - pClass1)
    print('p0:',p0)
    print('p1:',p1)
    if p1 > p0:
        return 1
    else: 
        return 0
 
""" 函數說明:測試樸素貝葉斯分類器 Parameters: 無 Returns: 無 Author: Jack Cui Blog: http://blog.csdn.net/c406495762 Modify: 2017-08-12 """
def testingNB():
    listOPosts,listClasses = loadDataSet()                                    #建立實驗樣本
    myVocabList = createVocabList(listOPosts)                                #建立詞彙表
    trainMat=[]
    for postinDoc in listOPosts:
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))                #將實驗樣本向量化
    p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))        #訓練樸素貝葉斯分類器
    testEntry = ['love', 'my', 'dalmation']                                    #測試樣本1
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))                #測試樣本向量化
    if classifyNB(thisDoc,p0V,p1V,pAb):
        print(testEntry,'屬於侮辱類')                                        #執行分類並打印分類結果
    else:
        print(testEntry,'屬於非侮辱類')                                        #執行分類並打印分類結果
    testEntry = ['stupid', 'garbage']                                        #測試樣本2
 
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))                #測試樣本向量化
    if classifyNB(thisDoc,p0V,p1V,pAb):
        print(testEntry,'屬於侮辱類')                                        #執行分類並打印分類結果
    else:
        print(testEntry,'屬於非侮辱類')                                        #執行分類並打印分類結果
 
if __name__ == '__main__':
    testingNB()
複製代碼

咱們測試了兩個詞條,在使用分類器前,也須要對詞條向量化,而後使用classifyNB()函數,用樸素貝葉斯公式,計算詞條向量屬於侮辱類和非侮辱類的機率。運行結果以下:

你會發現,這樣寫的算法沒法進行分類,p0和p1的計算結果都是0,顯然結果錯誤。這是爲何呢?下一篇文章繼續講解~

4、總結

樸素貝葉斯推斷的一些優勢

  • 生成式模型,經過計算機率來進行分類,能夠用來處理多分類問題。
  • 對小規模的數據表現很好,適合多分類任務,適合增量式訓練,算法也比較簡單。

樸素貝葉斯推斷的一些缺點

  • 對輸入數據的表達形式很敏感。
  • 因爲樸素貝葉斯的「樸素」特色,因此會帶來一些準確率上的損失。
  • 須要計算先驗機率,分類決策存在錯誤率。

其它

  • 本文中的編程實例,存在必定的問題,須要進行改進,下篇文章會講解改進方法;
  • 同時,本文中的編程實例,沒有進行前期的文本切分,下一篇文章會講解英文單詞和中文單詞的切分方法;
  • 下篇文章將使用sklearn進行中文實例練習;
  • 樸素貝葉斯的準確率,實際上是比較依賴於訓練語料的,機器學習算法就和純潔的小孩同樣,取決於其成長(訓練)條件,"吃的是草擠的是奶",但"不是全部的牛奶,都叫特侖蘇"。
  • 參考文獻:www.ruanyifeng.com/blog/2013/1…
  • 若有問題,請留言。若有錯誤,還望指正,謝謝!

PS: 若是以爲本篇本章對您有所幫助,歡迎關注、評論、贊!

本文出現的全部代碼和數據集,都可在個人github上下載,歡迎Follow、Star:github.com/Jack-Cheris…


相關文章和視頻推薦

圓方圓學院聚集 Python + AI 名師,打造精品的 Python + AI 技術課程。 在各大平臺都長期有優質免費公開課,歡迎報名收看。 公開課地址: ke.qq.com/course/3627…

加入python學習討論羣 78486745 ,獲取資料,和廣大羣友一塊兒學習。

圓方圓python技術討論羣
圓方圓python技術討論羣
相關文章
相關標籤/搜索