朴素貝葉斯定理
原理請參考:
http://www.ruanyifeng.com/blog/2011/08/bayesian_inference_part_one.html
https://www.cnblogs.com/TimVerion/p/11197043.html
即 后驗概率 = 先驗概率 * 調整因子
在分類中,先驗概率指樣本中該類別占所有類別的概率,調整因子則是每個樣本特征的概率乘積,舉個例子。
帥不帥 | 性格 | 上進不 | 值不值得交朋友 |
---|---|---|---|
帥 | 好 | 不上進 | 不值得 |
不帥 | 不好 | 不上進 | 不值得 |
帥 | 好 | 上進 | 值得 |
不帥 | 好 | 上進 | 值得 |
這里的先驗概率就是指:值得交朋友(1/2) , 不值得交朋友(1/2)
調整因子是指你要預測的樣本的特征概率,如果有一個樣本是不帥|好|不上進(例子特征不分散,因為只有兩個值,我們先不管這個)
那么值得交的后驗概率= 1/2 * 調整因子 = 0, 調整因子 = 不帥在值得交的數據中占(1/2) * 好在值得占(1) * 不上進在值得占(0)
不值得交的后驗概率 = 1/2* 1/2 * 1/2 * 1 = 1/8
所以這個人值不值得交呢,根據數據是1/8>0,那就是不值得交了。不過因為樣本數據較少,出現某個為0的概率,這就有點問題了,因為實際不可能概率為0的。
平滑參數
所以我們需要引入一個平滑參數,來使這個值不為0
那么我們計算概率時不是直接使用:符合要求的樣本/總樣本,而是 符合要求的樣本 + alpha/(總樣本+標簽類別數或特征類別數 * alpha),alpha一般取1.0
即先驗概率:值得交朋友(2 + 1/(4+2 * 1))=1/3 , 不值得交朋友(2 + 1/(4+2 * 1)) = 1/3
而特征概率的計算需要這樣計算:其他先不看,我們直接看值得交中不上進的概率(也就是先前為0的概率)= 0+1/(2 + 2*1) = 1/4, 注意這里的類別數是指len(上進,不上進)
值得交的后驗概率:1/3 * 1/2 * 3/4 * 1/4 = 1/32
不值得交的后驗概率: 1/3 * 1/2 * 1/2 * 3/4 = 1/16
雖然還是不值得交,但至少值得交的概率不為0了。如果你還不懂的話,直接看驗證碼的識別,然后在回來看這個。
sklearn中的api
sklearn.naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)
參數
- alpha:上面說的平滑參數
- fit_prior: 是否考慮先驗概率,也就是每個類別所占的比例
- class_prior: 給定的先驗概率數組
屬性 - class_log_prior_ : 數組, 維度(n_classes, ),每個類別的對數概率。n_classes為類別數量,比如有10個類別,每個類別樣本都是100個,則數組為(In 1/10, In 1/10,...)
- intercept_ : 同class_log_prior_
- feature_log_prob_ : 數組,維度(n_classes,n_features)給定一類特征的經驗對數概率P(x_i|y)。沒看懂
- coef_ : 同feature_log_prob_
- class_count_ : 數組,維度(n_classes, )每個類別的樣本個數
- classes_ : 數組,維度(n_classes,)每個類別的標簽
- feature_count_ : 數組,形狀(n_classes,n_features)擬合期間每個(類,特征)遇到的樣本數。沒看懂
方法 - fit(x, y[, sample_weight]): 使用樣本x和標簽y作訓練
- get_params(deep=True): 獲取模型的所有參數,deep不知道有什么用
- partial_fit(x, y[, classes, sample_weight]): 一批一批的訓練樣本(當樣本足夠大時)
- predict(test_x): 根據樣本test_x,返回預測y
- predict_proba(test_x): 返回樣本test_x屬於每個類別的概率,也就是說返回的是維度為(樣本數, k)的二維數組,每行一維數組的所有元素和為1,數組長度為k。
- score(test_x, y, sample_weight =None): 根據樣本test_x預測test_y, 然后對比實際的y返回的正確分數,sample_weight為權重
- set_params(**args): 重新設置模型參數
當然還有其他朴素貝葉斯分類或回歸器,區別如下:
特征是離散變量時,使用多項式模型(MultinomialNB)
當特征是連續變量時,使用高斯模型(GaussianNB)
伯努利模型(BernoulliNB)和多項式模型是一致的,但要求特征是二值化的(1,0)
生成模型
根據上面的描述可知,像這種簡單驗證碼,可以使用多項式模型,也可以使用伯努利模型,因為圖片已經被二值化。
已知圖片是18x10的二維數組,數組的每個元素都是0,1之間的數。我們可以組成180個特征,而驗證碼都是0-9的數字,所以分類是這樣來計算的
假設180個特征分別為x1, x2,...,x180,標簽為0-9,每個標簽的樣本個數都是120個
某個樣本屬於0的概率:P(0) = P0(x1)P0(x2)....P0(x180)P總(0), P0(x1)表示x1在0類別樣本中所占的比例(概率),P總(0)表示0占總樣本的比例(概率)即1/10, 這些值都是可以從訓練樣本求得。
代碼和KNN的基本一樣,如下:
from sklearn import naive_bayes
import os
from PIL import Image
import numpy as np
def func():
x = []
y = []
for label in os.listdir('train'):
for file in os.listdir(f'train/{label}'):
im = Image.open(f'train/{label}/{file}')
pix = np.array(im)
pix = (pix > 180) * 1
pix = pix.ravel()
x.append(list(pix))
y.append(int(label))
train_x = np.array(x)
train_y = np.array(y)
model = naive_bayes.MultinomialNB(alpha=1)
model.fit(train_x, train_y)
x = []
y = []
for label in os.listdir('test'):
for file in os.listdir(f'test/{label}'):
im = Image.open(f'test/{label}/{file}')
pix = np.array(im)
pix = (pix > 180) * 1
pix = pix.ravel()
x.append(list(pix))
y.append(int(label))
test_x = np.array(x)
test_y = np.array(y)
score = model.score(test_x, test_y)
return score
if __name__ == "__main__":
score = func()
print(score)
在這種簡單驗證碼識別上,朴素貝葉斯也可以達到100%的正確率。如果將樣本特征改成16個的話,你會發現朴素貝葉斯和KNN錯誤的地方都是一樣的,都是同一個驗證碼識別成了同一個錯誤。
最后,我正在學習一些機器學習的算法,對於一些我需要記錄的內容我都會分享到博客和微信公眾號,歡迎關注。平時的話一般分享一些爬蟲或者Python的內容。另外,如果博客有錯誤的話,還請指出。
這是已標注的數據:https://www.lanzous.com/i8epywd
最后,我正在學習一些機器學習的算法,對於一些我需要記錄的內容我都會分享到博客和微信公眾號(python成長路),歡迎關注。平時的話一般分享一些爬蟲或者Python的內容。