簡介
如果你有一個很大的數據集,有很多的變量,而且已知這是一個分類問題,你想快速的得到你的分類結果,那朴素貝葉斯是一個不錯的選擇,他比一般的分類算法都要快,他的理論基礎是概率中的貝葉斯定理。
本文會介紹朴素貝葉斯的理論基礎,以及一個基於python的實戰例子,so,坐穩了,准備開車
目錄
1.朴素貝葉斯是如何工作的?
2.朴素貝葉斯的理論基礎是什么?
3.朴素貝葉斯的優缺點是什么?
4.一個實戰例子
5.使用朴素貝葉斯模型的一些建議
朴素貝葉斯是如何工作的?
接下來用一個簡單的例子介紹,下面的訓練數據集反映了小學生出去玩(Play)和天氣(Weather)之間的關系
第一步:將數據集轉換為頻率表
第二步:創建概率表,比如P(sunny) =0.36
第三步:用朴素貝葉斯計算后驗概率,后驗概率大的為預測分類(關於先驗概率,后驗概率,看這篇文章)
問題:根據上面的數據集,如果天氣是sunny就出去玩,這樣說是否正確?
可以根據第三步中討論的后驗概率來確定以上說法是否正確。
P(Yes | Sunny) = P( Sunny | Yes) * P(Yes) / P (Sunny) (什么?為什么這樣計算,下面會介紹^_^)
P (Sunny |Yes) = 3/9 = 0.33, P(Sunny) = 5/14 = 0.36, P( Yes)= 9/14 = 0.64
最后: P (Yes | Sunny) = 0.33 * 0.64 / 0.36 = 0.60,因為0.6>0.5,所以以上說法正確
朴素貝葉斯的理論基礎是什么?
先看看條件獨立公式,如果X和Y相互獨立,則有:
P(X,Y) = P(X)P(Y)
接着看一下條件概率公式:
P(Y|X) = P(X,Y)/P(X)
由上面兩個公式可以推出貝葉斯公式:
P(Y|X) = P(X|Y)P(Y)/P(X)
由上面的統計學知識回到我們的數據分析。
假設某個體有n項特征(Feature),分別為F1、F2、…、Fn。現有m個類別(Category),分別為C1、C2、…、Cm。貝葉斯分類器就是計算出概率最大的那個分類,也就是求下面這個算式的最大值:
P(C|F1F2...Fn) = P(F1F2...Fn|C)P(C) / P(F1F2...Fn)
由於 P(F1F2…Fn) 對於所有的類別都是相同的,可以省略,問題就變成了求
P(F1F2...Fn|C)P(C)
的最大值。
朴素貝葉斯分類器則是更進一步,假設所有特征都彼此獨立,因此
P(F1F2...Fn|C)P(C) = P(F1|C)P(F2|C) ... P(Fn|C)P(C)
上式等號右邊的每一項,都可以從統計資料中得到,由此就可以計算出每個類別對應的概率,從而找出最大概率的那個類。
雖然”所有特征彼此獨立”這個假設,在現實中不太可能成立,但是它可以大大簡化計算,而且有研究表明對分類結果的准確性影響不大。
朴素貝葉斯的優缺點是什么?
優點:
- 簡單、運算量小、在擁有大量分類的數據集上仍然表現很好
- 當數據的各個屬性互相獨立的假設成立,朴素貝葉斯比邏輯回歸等模型表現更好,並且朴素貝葉斯需要更少的訓練數據
- 與數值變量相比,朴素貝葉斯在非數值變量的訓練集上表現更好,因為對於數值型變量,一般假設數據符合正太分布(這個假設是一個很強的假設,大多數數據集並不相符)
缺點:
- 如果一個變量的某個值在測試集中有,在訓練集中沒有,計算結果將是0概率,無法做出分類,為了解決這個問題,需要引入平滑處理,比較簡單的是拉普拉斯平滑
- 朴素貝葉斯假定每個變量之間是相互獨立的,但是現實中的數據往往都具有一定的相關性,很少有完全獨立的
一個實戰例子
該例子主要是為了識別某個文本是否具有侮辱性
import numpy as np def getDataSet(): """ 加載訓練數據, postingList是所有的訓練集, 每一個列表代表一條言論, 一共有8條言論 classVec代表每一條言論的類別, 0是正常, 1是有侮辱性 返回 言論和類別 :return: """ 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']] labels = [0,1,0,1,0,1] return postingList,labels def createVocabList(dataSet): """ 創建詞匯表, 就是把這個文檔中所有的單詞不重復的放在一個列表里面 :param dataSet: :return: """ vocabSet = set([]) for data in dataSet: vocabSet = vocabSet | set(data) return list(vocabSet) def vectorize(vocabSet,dataSet): """ 制作詞向量矩陣 將每一個文檔轉換為詞向量, 然后放入矩陣中 :param vocabSet: :param dataSet: :return: """ vocab = [0] * len(vocabSet) for data in dataSet: vocab[vocabSet.index(data)] = 1 return vocab def trainN(X_train,y_train): """ 制作貝葉斯分類器 :param X_train: :param y_train: :return: """ num = len(X_train) #有多少記錄 numvocab = len(X_train[0]) #詞向量的大小 p0Num = np.ones(numvocab) #統計非侮辱類的相關單詞頻數 加入了拉普拉斯平滑 p1Num = np.ones(numvocab) #統計侮辱類的相關單詞頻數 p0Sum = 2 p1Sum = 2 pA = sum(y_train) / num #先驗概率 for i in range(num): if y_train[i]==0: #統計屬於非侮辱類的條件概率所需的數據 # p0Sum += sum(X_train[i]) p0Sum += 1 p0Num += X_train[i] else: #統計屬於侮辱類的條件概率所需的數據 # p1Sum += sum(X_train[i]) p1Sum += 1 p1Num += X_train[i] # 為了防止下溢出,計算條件概率的對數 p0 = np.log(p0Num / p0Sum) #頻數除以總數 得到概率 p1 = np.log(p1Num / p1Sum) return p0,p1,pA def classify(testMat,p0,p1,pA): """ 進行分類 :param testMat: :param p0: :param p1: :param pA: :return: """ p0Score = sum(testMat * p0) + np.log(pA) p1Score = sum(testMat * p1) + np.log(1-pA) if p0Score > p1Score: return 0 else: return 1 if __name__=='__main__': dataSet,label = getDataSet() vocabSet = createVocabList(dataSet) trainMat = [] for elem in dataSet: trainMat.append(vectorize(vocabSet,elem)) # print(trainMat) p0,p1,pA = trainN(trainMat,label) test1= ['love', 'my', 'dalmation'] test2= ['stupid', 'garbage','love'] test1_vocab = np.array(vectorize(vocabSet,test1)) test2_vocab = np.array(vectorize(vocabSet,test2)) result1 = classify(test1_vocab,p0,p1,pA) result2 = classify(test2_vocab,p0,p1,pA) if result1==1: print(test1,"屬於:侮辱類") else: print(test1, "屬於:非侮辱類") print("------------------------------------------") if result2==1: print(test2,"屬於:侮辱類") else: print(test2, "屬於:非侮辱類")
結果:
['love', 'my', 'dalmation'] 屬於:非侮辱類 ------------------------------------------ ['stupid', 'garbage', 'love'] 屬於:侮辱類
使用朴素貝葉斯模型的一些建議
- 如果連續型變量不符合正態分布,需要使用一些方法轉換為正太分布
- 刪除相關屬性,如果相關屬性多次參與計算概率,會導致該屬性出現的概率變大
- 如果測試數據出現某個變量值在訓練集為0時,記得使用拉普拉斯平滑