《機器學習實戰》學習筆記:樸素貝葉斯分類演算法
貝葉斯決策理論
選擇高概率對應的類別是貝葉斯決策理論的核心思想,即選擇具有最高概率的決策。
樸素貝葉斯
樸素貝葉斯法是基於貝葉斯定理與特徵條件獨立假設的分類方法 。最為廣泛的兩種分類模型是決策樹模型(Decision Tree Model)和樸素貝葉斯模型(Naive Bayesian Model,NBM),本文主要討論樸素貝葉斯模型。我們稱之為“樸素”,是因為整個形式化過程只做最原始、最簡單的假設。
和決策樹模型相比,樸素貝葉斯分類器(Naive Bayes Classifier,或 NBC)發源於古典數學理論,有著堅實的數學基礎,以及穩定的分類效率。同時,NBC模型所需估計的引數很少,對缺失資料不太敏感,演算法也比較簡單。理論上,NBC模型與其他分類方法相比具有最小的誤差率。但是實際上並非總是如此,這是因為NBC模型假設屬性之間相互獨立,這個假設在實際應用中往往是不成立的,這給NBC模型的正確分類帶來了一定影響。
它也是基於貝葉斯定律的,如下圖,一般的貝葉斯估計就是基於條件概率。
事件c發生的概率為P(c),即先驗概率;事件x發生的概率為P(x);在事件c發生的條件下事件x發生的概率為P(x|c);在事件x發生的條件下事件c發生的概率為P(c|x),其中P(x|c)P(c)= P(cx),即事件c、x同時發生的概率。
那麼根據貝葉斯定律:在事件x發生的條件下事件c發生的概率為P(c|x),即後驗概率,等於在事件x發生的條件下事件c、x同時發生的概率。
而樸素貝葉斯演算法則針對多元分類問題,假設在事件x1、x2…xn均發生條件下事件c的概率,這裡假設x1、x2…xn相互獨立,那麼P(x|c)的概率就可以計算為
主要步驟如下:
1、建立資料集和標籤表
2、準備資料:從文字中構建詞向量(無重複的詞向量,通過set集合,和list來實現)
3、根據第二步構建詞向量,將原始資料集向量化,向量的每個元素為1或0
4、樸素貝葉斯分類器訓練函式
5、樸素貝葉斯分類器分類函式
# -*- coding: UTF-8 -*- import numpy as np from functools import reduce """ 函式說明:建立實驗樣本 Parameters: 無 Returns: postingList - 實驗樣本切分的詞條 classVec - 類別標籤向量 Modify: 2018-10-12 """ 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 - 返回不重複的詞條列表,也就是詞彙表 Modify: 2018-10-12 """ 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 - 文件向量,詞集模型 Modify: 2018-10-12 """ 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 - 文件屬於侮辱類的概率 Modify: 2018-10-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 - 屬於侮辱類 Modify: 2018-10-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: 無 Modify: 2018-10-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,'wuru') #執行分類並列印分類結果 else: print(testEntry,'not belong insult') #執行分類並列印分類結果 testEntry = ['stupid', 'garbage'] #測試樣本2 thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry)) #測試樣本向量化 if classifyNB(thisDoc,p0V,p1V,pAb): print(testEntry,'is belong insult') #執行分類並列印分類結果 else: print(testEntry,'not belong insult') #執行分類並列印分類結果 if __name__ == '__main__': testingNB()
執行結果:
應用場景
- 垃圾郵件分類
- 大量廣告中學習分類器
- 文字分類、垃圾文字過濾、情感預測、多分類預測、推薦系統
總結:
優點:
- 需估計的引數很少
- 缺失資料不太敏感
- 演算法邏輯簡單,易於實現(演算法思路很簡單,只要使用貝葉斯公式轉化醫學即可!
- 在資料較少的情況下仍然有效,可以處理多類別問題
-
分類過程中時空開銷小(假設特徵相互獨立,只會涉及到二維儲存)
缺點:
- NBC模型假設屬性之間相互獨立,這個假設在實際應用中往往是不成立的
-
需要一個比較容易解釋,而且不同維度之間相關性較小的模型的時候
-
可以高效處理高維資料,雖然結果可能不盡如人意
-
對於輸入資料的準備方式較為敏感