樸素貝葉斯演算法及Python的簡單實現
貝葉斯演算法起源於古典數學理論,是一種分類演算法的總稱。它以貝葉斯定理為基礎,假設某待分類的樣本滿足某種概率分佈,並且可以根據已觀察到的樣本資料對該樣本進行概率計算,以得出最優的分類決策。通過計算已觀察到的樣本資料估計某待分類樣本的先驗概率,利用貝葉斯公式計算出其後驗概率,即該樣本屬於某一類的概率,選擇具有最大後驗概率的類作為該樣本所屬的類。
先驗概率是根據以往經驗和分析得到的概率。可以用P(h)來表示假設h的先驗概率,用P(D)表示將要觀察的訓練資料D的先驗概率,用P(D|h)表示假設h成立的情況下觀察到資料D的概率,關心的是P(h|D),即給定訓練資料D時h成立的概率,稱之為後驗概率。
貝葉斯公式:P(h|D)=P(D|h)P(h)/P(D),從公式可以看出P(h|D)隨著P(h)和P(D|h)的增長而增長,也可以看出P(h|D)隨著P(D)的增加而減少。考慮候選假設集合H並在其中尋找給定資料D時可能性最大的假設h。這樣的具有最大可能性的假設被稱為極大後驗(MAP)假設。確定MAP假設的方法是用貝葉斯公式計算每個候選假設的後驗概率,可能會多個屬性,且屬性之間可能存在複雜的依賴關係,這就使得P(D|h)的計算十分困難,為了簡化條件概率的求解難度,提出了一種條件獨立假設,即假設訓練資料D中,各屬性之間相互獨立。在貝葉斯演算法基礎上添上條件獨立假設,我們就稱之為樸素貝葉斯演算法。
樸素貝葉斯簡介
資料集
本部落格所用的資料集,用的是鳶尾花(Iris),如有需要可通過下方地址下載
http://archive.ics.uci.edu/ml/index.php
Python程式碼的簡單實現如下:
#coding:utf-8
# 極大似然估計 樸素貝葉斯演算法
import pandas as pd
import numpy as np
class NaiveBayes(object):
def getTrainSet(self):
dataSet = pd.read_csv('Iris.csv')
dataSetNP = np.array(dataSet) #將資料由dataframe型別轉換為陣列型別
trainData = dataSetNP[:120,:dataSetNP.shape[1]-1] #訓練資料
labels = dataSetNP[:120,dataSetNP.shape[1]-1] #訓練資料所對應的所屬型別C
testData = dataSetNP[120:,:dataSetNP.shape[1]-1] #測試資料
testlabels =dataSetNP[120:,dataSetNP.shape[1]-1] #測試資料所對應的類別C
return trainData, labels, testData, testlabels
def classify(self, trainData, labels, features):
#求labels中每個label的先驗概率
labels = list(labels) #轉換為list型別
P_y = {} #存入label的概率
for label in labels:
P_y[label] = labels.count(label)/float(len(labels)) # p = count(y) / count(Y)
#求label與feature同時發生的概率
P_xy = {}
for y in P_y.keys():
y_index = [i for i, label in enumerate(labels) if label == y] # labels中出現y值的所有數值的下標索引
for j in range(len(features)): # features[0] 在trainData[:,0]中出現的值的所有下標索引
x_index = [i for i, feature in enumerate(trainData[:,j]) if feature == features[j]]
xy_count = len(set(x_index) & set(y_index)) # set(x_index)&set(y_index)列出兩個表相同的元素
pkey = str(features[j]) + '*' + str(y)
P_xy[pkey] = xy_count / float(len(labels))
#求條件概率
P = {}
for y in P_y.keys():
for x in features:
pkey = str(x) + '|' + str(y)
P[pkey] = P_xy[str(x)+'*'+str(y)] / float(P_y[y]) #P[X1/Y] = P[X1Y]/P[Y]
#求testData每條樣例所屬類別
F = {} #testData每條樣例屬於各個類別的概率
for y in P_y:
F[y] = P_y[y]
for x in features:
F[y] = F[y]*P[str(x)+'|'+str(y)] #P[y|X] = P[X|y]*P[y]/P[X],分母相等,比較分子即可,
# 所以有F=P[X/y]*P[y]=P[x1/Y]*P[x2/Y]*P[x3|y]*P[x4|y]*P[y]
features_label = max(F, key=F.get) #概率最大值對應的類別
return features_label
def test(self,trainData, labels, testData, testlabels):
correct = 0
for i in range(len(testData)):
# Outlook Temperature Humidity Wind
features = testData[i]
# 該特徵應屬於哪一類
result = nb.classify(trainData, labels, features)
print features, '屬於', result
if nb.classify(trainData, labels, testData[i]) == testlabels[i]:
correct += 1
print correct / float(len(testlabels))
if __name__ == '__main__':
nb = NaiveBayes()
# 訓練資料,測試資料
trainData, labels, testData, testlabels = nb.getTrainSet()
nb.test(trainData, labels, testData, testlabels)
執行結果如下: