續着上一篇說到的Iris數據集多分類問題,基於softmax的邏輯迴歸分類需要通過數據訓練一輪輪地降低損失函數,以獲得最佳的參數w和b。
而對於樸素貝葉斯算法來說,其核心源於貝葉斯公式,這個偉大的業餘(?)數學家貝葉斯的著名公式:
其表現的是先驗概率P(a)和後驗概率P(a|b)之間的概率。
我們可以用一個形象的例子來說,比如相親:在不知道其他情況下,我們知道一個普通小夥子被姑娘看上的概率是0.4。根據後續的交流,我們發現這個小夥子爲人誠實,和藹可親,那麼根據常識,被看上的概率應該提高了;如果這個小夥子收入年入百萬,英俊瀟灑,身高185…那麼原來這個0.4的概率就會被不斷地修正,不斷地升高接近1.0。
我們剛剛這個例子中,一開始那個0.4的概率就是先驗概率,後面不斷地補充和小夥子相關的其他特徵,不斷修正得到的概率就是後驗概率。
利用貝葉斯公式,我們可以定性的發現先驗概率、後驗概率與這些其他相關特徵發生概率之間的關係。
回到樸素貝葉斯算法中,我們做多分類,也可以採用這種思想。一開始我們可以以這個類別在這個數據集中出現的比例爲先驗概率,在此之後,我們根據其他特徵發生的概率、在這個實體是這個類別條件下發生此特徵的概率來計算後驗概率,之後比較後驗概率(修正後的概率)的大小,選擇後驗概率最大的作爲一個實例的預測值。
對於離散型特徵,我們可以用每個特徵出現的次數來作爲概率:
由於可以認爲是一個常數,所以最終我們需要比較
這裏代表第i個特徵值爲v,y=c代表爲第c類
對於連續型特徵,我們可以任務特徵服從一維正態分佈,用其概率密度函數來表示概率:
同理最終我們要求:
我們可以發現,樸素貝葉斯不需要數據一輪輪的訓練來下降損失函數,只需要利用數據計算公式進行計算和比較即可。所以樸素貝葉斯比起softmax邏輯分類來說,“訓練”是輕鬆很多了。(我要是softmax算法我可能要罵娘了hhh)
下面上代碼:
import pandas as pd
from sklearn import datasets
import numpy as np
# 利用sklearn的datasets下載iris數據集
x_data = datasets.load_iris().data
y_data = datasets.load_iris().target
#打亂順序,分爲訓練集測試集
np.random.seed(100)
np.random.shuffle(x_data)
np.random.seed(100)
np.random.shuffle(y_data)
dataset_size = len(x_data)
trainData_size = int(dataset_size*0.7)
testData_size = dataset_size - trainData_size
x_train = x_data[:trainData_size]
y_train = y_data[:trainData_size]
x_test = x_data[trainData_size:]
y_test = y_data[trainData_size:]
# 轉爲dataframe
train = pd.DataFrame(x_train,columns=['SpealLength', 'SpealWidth', 'PetalLength', 'PetalWidth'])
train.insert(0,'target',y_train)
# 訓練過程(算公式過程)
# 開闢一個3*8的ndarray存3類4個特徵的均值和標準差
w = np.zeros((3,8))
# 存儲每類的數量
type_size = np.zeros(3)
# 分別對三類數據對應特徵求均值和標準差
for type in range(3):
temp = train[train['target']==type]
type_size[type] = len(temp)
temp = temp[['SpealLength', 'SpealWidth', 'PetalLength', 'PetalWidth']]
mean = temp.mean()
std = temp.std()
for feature in range(4):
w[type][feature * 2] = mean.iloc[feature]
w[type][feature * 2 + 1] = std.iloc[feature]
# 求正態概率密度
def normal_f(mean,std,x):
x = np.array(x)
return 1/(np.sqrt(2*np.pi)*std)*np.exp(-np.square(x-mean)/(2*np.square(std)))
acc_num = 0
for i in range(len(x_test)):
# 後驗概率
post_prob = np.zeros(3)
for type in range(3):
#先驗概率賦值給後驗概率
post_prob[type] = type_size[type] / len(x_train)
for feature in range(4):
post_prob[type] *= normal_f(w[type][feature * 2],w[type][feature * 2 + 1],x_test[i][feature])
ans = np.argmax(post_prob)
print("guess:",ans,'\n',"right_ans:",y_test[i])
if ans == y_test[i]:
acc_num += 1
print("acc:",acc_num/len(x_test))
最終準確率100%