机器学习系列之手把手教你实现一个 naiveBayes
https://www.ibm.com/developerworks/cn/analytics/library/machine-learning-hands-on3-naivebayes/index.html?ca=drs-
樸素貝葉斯簡介
在本系列的前面兩篇文章中,分別介紹了 SVM 模型和 FP-growth 模型。其中 SVM 模型主要用于分類,FP-growth 模型用于挖掘頻繁項集和關聯規則。本文將介紹 naiveBayes 模型,即樸素貝葉斯模型。樸素貝葉斯模型主要用來分類,但是與 SVM 模型不同的的是,樸素貝葉斯模型不需要針對目標變量建立模型,而是借助貝葉斯公式計算樣本屬于各個類別的概率,然后取概率值大的類別作為分類類別。之所以稱之為樸素,是因為樸素貝葉斯模型假設各屬性之間是條件獨立的,該假設極大得簡化了運算,使得樸素貝葉斯模型變得非常簡單。
樸素貝葉斯模型主要應用在文本分類方面。這里需要用到向量空間模型,即將文本轉換成詞向量。詞向量的每一項是該詞出現的頻數。在樸素貝葉斯中會將頻數進一步轉換成頻率。這樣就完成了文本到數值上的轉化,方便后期計算條件概率和先驗概率。
樸素貝葉斯模型也有它的優缺點,優點是模型簡單,計算快;缺點是依賴于屬性之間條件獨立這一假設,但是現實場景下很多情況并不滿足這一假設,使得樸素貝葉斯的準確率受到影響。這種情況需要考慮半樸素貝葉斯,即放松屬性之間條件獨立這一假設,一定程度上考慮屬性之間的依賴關系。由于篇幅有限,對半樸素貝葉斯感興趣的話可自行參照文末參考資源學習,本文重點介紹樸素貝葉斯的原理和實現。
樸素貝葉斯原理
樸素貝葉斯模型主要利用貝葉斯公式進行展開。貝葉斯公式如下:
圖 1. 貝葉斯公式
公式中 P(C|X)表示 X 屬于類別 C 的概率,P(X|C)表示類別 C 中 X 出現的概率,P(C)表示類別 C 出現的概率。其中 P(C)稱為先驗概率,P(X|C)是條件概率,P(C|X)稱為后驗概率,將后驗概率最大的類作為 X 的類別輸出。假設有 C0 和 C1 兩個類,由于 P(X)都是一樣的,所以不需要考慮 P(X),只需考慮如下:
由上述可知,需要計算 P(X|C)和 P(C)。樸素貝葉斯假設屬性之間條件獨立,可得:
P(X|C) =?P(X0|C) *?P(X1|C) *?P(X2|C) *?P(X3|C) *… *?P(Xn|C)
令 Dc 表示訓練集 D 中第 C 類樣本組成的集合,可得:
P(Xi|C) = |Dc,xi| / |Dc,x|,表示類別為 C 的樣本在第 i 個屬性上頻數總和除以類別為 C 的樣本集合中所有屬性頻數總和。為了避免 P(Xi|C)為 0 造成 P(X|C)為 0 而影響分類結果,在此引入拉普拉斯平滑,本文分別給分子和分母加上 1 和 2,即 P(Xi|C) = (|Dc,xi| + 1) / (|Dc,x| + 2)。
又有 P(C) = |Dc| / |D|, 表示類別為 C 的樣本集合大小除以數據集 D 的樣本集合大小。
至此,通過 P(X|C0) *?P(C0) 和?P(X|C1) *?P(C1)的大小比較,可得 X 所屬類別。但是小數連乘會造成所得值幾乎等于 0 的結果,從而無法比較大小。鑒于此,往往在實際運算中,會借助 log 函數,比較 log(P(X|C0) *?P(C0)) 和 log(P(X|C1) *?P(C1))的大小來判斷 X 所屬類別。從而得:
log(?P(X|C0) *?P(C0) ) = log(P(X|C0)) + log(P(C0)) = log(P(X0|C0)) + log(P(X1|C0)) + log(P(X2|C0)) + …+ log(P(Xn|C0)) + log(P(C0)),
同理可得 log(?P(X|C1) *?P(C1) ) = log(P(X|C1)) + log(P(C1)) = log(P(X0|C1)) + log(P(X1|C1)) + log(P(X2|C1)) + …+ log(P(Xn|C1)) + log(P(C1))。
用樸素貝葉斯進行文本分類
利用樸素貝葉斯模型進行文本分類,首先需要將文本表示成詞向量,再從詞向量中計算得到條件概率 P(X|C)和先驗概率 P(C),然后利用條件概率 P(X|C)與先驗概率 P(C)計算后驗概率 P(C0|X)、P(C1|X)。最終比較 P(C0|X)、P(C1|X)大小得到 X 屬于 C0 類還是 C1 類。下面用表 1 所示訓練數據和表 2 所示測試數據展開介紹。
表 1. 示例訓練數據集
| 1 | 'book', 'student', 'campus', 'study' |
| 0 | 'others', 'game', 'sky' |
| 1 | 'campus', ' book ' |
| 0 | 'others', 'yes' |
表 2. 示例測試數據集
| ? | 'book', 'campus', 'study' |
從文本到詞向量
首先需要將文本表示成詞向量,去掉重復的詞。將表 1 中示例數據集表示成詞向量如下:
[ 'book', 'student', 'campus', 'study', 'others', 'game', 'sky', 'yes' ]
可以看出,重復的'campus', 'book', 'others'都只出現了一次。
然后,需要將文本列表轉換成詞向量列表,文本中的詞在詞向量中出現為 1,未出現為 0, 如表 3,4 所示:
表 3. 訓練文本詞向量列表
| 1 | [1, 1, 1, 1, 0, 0, 0, 0] |
| 0 | [0, 0, 0, 0, 1, 1, 1, 0] |
| 1 | [1, 0, 1, 0, 0, 0, 0, 0] |
| 0 | [0, 0, 0, 0, 1, 0, 0, 1] |
表 4. 測試文本詞向量列表
| ? | [1, 0, 1, 1, 0, 0, 0, 0] |
從詞向量到條件概率和先驗概率
由上一章知,
條件概率 P(X|C) =?P(X0|C) *?P(X1|C) *?P(X2|C) *?P(X3|C) *… *?P(Xn|C),
為防止概率為 0 影響結果,加入拉普拉斯平滑后 P(Xi|C) = (|Dc,xi| + 1) / (|Dc,x| + 2),
先驗概率 P(C) = |Dc| / |D|。
為防止小數連乘造成結果幾乎為 0,引入 log 函數,由于測試文本只包含 X0, X2, X3, 得:
log(?P(X|C0) *?P(C0) ) = log(P(X0|C0)) + log(P(X2|C0)) + log(P(X3|C0)) + log(P(C0))
log(?P(X|C1) *?P(C1) ) = log(P(X0|C1)) + log(P(X2|C1)) + log(P(X3|C1)) + log(P(C1))
代入數據,得
P(X0|C0) =?P(X2|C0) =?P(X3|C0) = (0 + 1) / (5 + 2) = 1/7,
P(C0) =?P(C1) = 2 / 4,
P(X0|C1) =?P(X2|C1) = (2 + 1) / (6 + 2) = 3/8,
P(X3|C1) = (1 + 1) / (6 + 2) = 2/8,
故可得:
log(?P(X|C0) *?P(C0) ) = log(1/7) + log(1/7) + log(1/7) + log(2/4) = -2.84
log(?P(X|C1) *?P(C1) ) = log(3/8) + log(3/8) + log(2/8) + log(2/4) = -1.76
根據后驗概率分類
由上一章知,
因此后驗概率 P(C0|X)只需考慮 P(X|C0) *?P(C0) ,同理后驗概率 P(C1|X)只需考慮 P(X|C1) *?P(C1)。
已知:
如果 log(?P(X|C0) *?P(C0) ) > log(?P(X|C1) *?P(C1) ),則 P(C0|X) >?P(C1|X),可得 X 屬于 C0 類;
如果 log(?P(X|C0) *?P(C0) ) < log(?P(X|C1) *?P(C1) ),則 P(C0|X) <?P(C1|X),可得 X 屬于 C1 類。
又由于-1.76 > -2.84, 所以 log(?P(X|C1) *?P(C1) ) > log(?P(X|C0) *?P(C0) ), 即 P(C1|X) >?P(C0|X),可得測試文本{'book', 'campus', 'study'}屬于類別 1。
實現步驟:自己動手實現樸素貝葉斯
本節將介紹使用樸素貝葉斯進行文本分類的實現過程。自己動手實現樸素貝葉斯主要從三個方面展開,分別是從文本到詞向量,從詞向量到先驗概率和條件概率,以及推斷測試文本的類別。
清單 1. 從文本到詞向量
| 1 2 3 4 5 6 | def word2vector(words, article): ????article2Vector = zeros(len(words)) ????for word in article: ????????if word in words: ????????????article2Vector[words.index(word)] += 1 ????return article2Vector |
清單 1 完成了將文本表示成詞向量的過程。words 是統計出的所有文本中的詞列表,即所有文本中不重復的詞列表,如清單 2 所示,計算 words 的過程用到了集合的并操作。對于文本 article 中的每個詞,如果詞在 words 列表中,就將詞向量中對應下標的元素加一。
清單 2. 從詞向量到先驗概率
| 1 2 3 4 5 6 7 8 9 10 11 | def calcProb(articles, categories): ????p1 = sum(array(categories)) / len(categories) ????p0 = 1 - p1 ????words = set([]) ????for i in range(len(articles)): ????????words = words | set(articles[i]) ????words = list(words) ????p0words, p1words = calcWordsProbInCateg(words, articles, categories) ????return p0,p1,p0words,p1words,words |
清單 2 完成了從詞向量中計算先驗概率 p0 和 p1 的過程。p1 的計算過程為首先統計類別列表 categories 中所有類別為 1 的向量集合大小,然后對其除以所有文本總數。P0 由 1 減去 p1 即可得到, 這是因為 P0 + P1 = 1。
清單 3. 從詞向量到條件概率
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | def calcWordsProbInCateg(words, articles, categories): ????articlesMatrix = [] ????for article in articles: ????????article2Vector = word2vector(words, article) ????????articlesMatrix.append(article2Vector) ????sumWords0 = 2 ????sumWords1 = 2 ????p0words = ones(len(words)) ????p1words = ones(len(words)) ????for i in range(len(articles)): ????????if categories[i] == 0: ????????????p0words += articlesMatrix[i] ????????????sumWords0 += sum(articlesMatrix[i]) ????????else: ????????????p1words += articlesMatrix[i] ????????????sumWords1 += sum(articlesMatrix[i]) ????p0words = p0words / sumWords0 ????p1words = p1words / sumWords1 ????return p0words, p1words |
清單 3 完成了從詞向量中計算條件概率 p0words 和 p1words 的過程。p0words 表示類別 0 中所有詞出現的概率向量,p1words 表示類別 1 中所有詞出現的概率向量。代碼一開始先將文本列表 articles 轉換成文本詞概率矩陣 articelsMatrix, 然后對每篇文本,對該文本所屬的類別,統計每個詞的出現總次數和所有詞的出現總次數。最后對每個類別,用每個詞在該類別中的出現總次數除以所有詞的出現總次數,得到類別 0 中所有詞出現的概率向量和類別 1 中所有詞出現的概率向量。注意此處利用拉普拉斯平滑避免了概率為 0 的出現,方便后續概率計算。
清單 4. 推斷測試文本的類別
| 1 2 3 4 5 6 7 8 9 10 11 12 | def inferCategory(words, testArticle, p0, p1, p0words, p1words): ????category = 0 ????testArticle2Vector = word2vector(words, testArticle) ????p0temp = sum(log(p0words) * testArticle2Vector) ????p1temp = sum(log(p1words) * testArticle2Vector) ????pwords0 = p0temp + log(p0) ????pwords1 = p1temp + log(p1) ????if pwords0 < pwords1: ????????category = 1 ????return category |
清單 4 用 inferCategory 函數推斷測試文本 testArticle 所屬的類別。首先,將 testArticle 轉化成詞向量 testArticle2Vector,然后利用貝葉斯公式分別計算 testArticle 屬于類別 0 的概率和 testArticle 屬于類別 1 的概率,取概率值大的類別作為 testArticle 所屬的類別。注意此處利用了 log 函數避免了連乘造成的結果幾乎等于 0 的后果。
代碼下載 (code downloads)
本文所有樸素貝葉斯實現代碼可在文末下載。
本文數據集簡介
圖 2. 數據集樣例
訓練數據集有 6 條文本數據,分為教育類和非教育類,第 1,3,5 條文本數據['book', 'student', 'is', 'campus', 'classes', 'study']、['children', 'library', 'are', 'homework', 'we', 'learn', 'cafeteria']、['student', 'library', 'teach', 'lecture', 'time', 'math','art', 'biology', 'geography'],代表教育類的文本;第 2,4,6 條文本數據['others', 'game', 'sky', 'cat', 'park', 'dog']、['nothing', 'gone', 'from', 'good', 'cookie']、['bread', 'milk', 'water', 'you', 'we', 'yes'],代表非教育類的文本。教育類用類別 1 表示,非教育類用類別 0 表示。
應用示例: 應用實現的樸素貝葉斯解決實際問題
清單 5. 用樸素貝葉斯解決實際問題
| 1 2 3 4 5 6 7 8 9 | if __name__ == '__main__': ?articles, categories = loadDataSet() ?p0, p1, p0words, p1words, words = calcProb(articles, categories) ?testArticle1 = ['student', 'study', 'campus'] ?category1 = inferCategory(words, testArticle1, p0, p1, p0words, p1words) ?print("test article:", testArticle1, ",category is: ", category1) ?testArticle2 = ['other', 'no'] ?category2 = inferCategory(words, testArticle2, p0, p1, p0words, p1words) ????print("test article:", testArticle2, ",category is: ", category2) |
測試數據集有 2 條文本數據,分別為['student', 'study', 'campus']和['other', 'no']。清單 5 首先調用 loadDataSet 函數加載文本列表和類別列表,接著調用 calcProb 函數計算類別 0 概率、類別 1 概率、類別 0 中所有詞的概率向量、類別 1 中所有詞的概率向量,然后調用 inferCategory 函數計算測試文本 testArticle 所屬的類別。
運行結果如下:
test article: ['student', 'study', 'campus'] ,category is: 1
test article: ['other', 'no'] ,category is: 0
可以看出測試文本['student', 'study', 'campus']屬于類別 1,即教育類;測試文本['other', 'no']屬于類別 0,即非教育類。
總結
本文首先介紹了樸素貝葉斯的應用場景和優缺點,接著詳細介紹了樸素貝葉斯的原理,然后介紹了如何用樸素貝葉斯進行文本分類,并通過代碼樣例詳細介紹如何自己動手實現樸素貝葉斯。最后,用教育類數據展示了如何應用樸素貝葉斯模型解決實際問題。需要注意的是樸素貝葉斯模型認為屬性之間是條件獨立的,這也就是樸素這個詞的來源,表達了簡化的含義。但是實際場景中,屬性之間是條件獨立的這個假設不一定總是成立的。這就引申出了半樸素貝葉斯,即放松了屬性之間條件獨立這一假設。半樸素貝葉斯考慮了一部分屬性之間的相互依賴關系。由于篇幅有限,對于半樸素貝葉斯感興趣的話可以參考文末列出的第三個參考資源(周志華著《機器學習》)了解詳細原理。
參考資源
本文用到的參考文獻如下:
- 參考 Peter Harrington 著《機器學習實戰》,了解樸素貝葉斯模型基本原理。
- 參考李航著《統計學習方法》,了解拉普拉斯平滑原理。
- 參考周志華著《機器學習》,了解半樸素貝葉斯原理。
轉載于:https://www.cnblogs.com/davidwang456/articles/8926997.html
總結
以上是生活随笔為你收集整理的机器学习系列之手把手教你实现一个 naiveBayes的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习之手把手实现,第 2 部分 频
- 下一篇: 机器学习系列之手把手教你实现一个决策树