Sklearn(v3)——朴素贝叶斯(3)
多項式樸素貝葉斯MultinomialNB
?
from sklearn.preprocessing import MinMaxScaler from sklearn.naive_bayes import MultinomialNB from sklearn.model_selection import train_test_split from sklearn.datasets import make_blobs from sklearn.metrics import brier_score_loss class_1 = 500 class_2 = 500 #兩個類別分別設定500個樣本 centers = [[0.0, 0.0], [2.0, 2.0]] #設定兩個類別的中心 clusters_std = [0.5, 0.5] #設定兩個類別的方差 X, y = make_blobs(n_samples=[class_1, class_2],centers=centers,cluster_std=clusters_std,random_state=0, shuffle=False) Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)#先歸一化,保證輸入多項式樸素貝葉斯的特征矩陣中不帶有負數,多項式樸素貝葉斯拒絕負值輸入 mms = MinMaxScaler().fit(Xtrain) Xtrain_ = mms.transform(Xtrain) Xtest_ = mms.transform(Xtest)mnb = MultinomialNB().fit(Xtrain_,Ytrain) #重要屬性:調用根據數據獲取的,每個標簽類的對數先驗概率log(P(Y)) #由于概率永遠是在[0,1]之間,因此對數先驗概率返回的永遠是負值 mnb.class_log_prior_結果:
array([-0.69029411, -0.69600841])?y的兩種取值的先驗概率,基本上一致表示不存在樣本不均衡問題
print((Ytrain == 1).sum()/Ytrain.shape[0]) print(mnb.class_log_prior_ .shape) #可以使用np.exp來查看真正的概率值 print(np.exp(mnb.class_log_prior_)) #重要屬性:返回一個固定標簽類別下的每個特征的對數概率log(P(Xi|y)) print(mnb.feature_log_prob_) print(mnb.feature_log_prob_.shape)結果:
0.49857142857142855 (2,) [0.50142857 0.49857143] [[-0.76164788 -0.62903951][-0.72500918 -0.6622691 ]] (2, 2) #一些傳統的接口 mnb.predict(Xtest_)結果:?
mnb.predict_proba(Xtest_)結果:?
?
mnb.score(Xtest_,Ytest) #0.5433333333333333 brier_score_loss(Ytest,mnb.predict_proba(Xtest_)[:,1],pos_label=1) #0.24977828412546035效果不太理想,思考一下多項式貝葉斯的性質,我們能夠做點什么呢?
多項式貝葉斯處理的是分類型數據而不是連續型數據
#來試試看把Xtiain轉換成分類型數據吧 #注意我們的Xtrain沒有經過歸一化,因為做啞變量之后自然所有的數據就不會又負數了 from sklearn.preprocessing import KBinsDiscretizer #對連續型變量進行分箱 kbs = KBinsDiscretizer(n_bins=10, encode='onehot').fit(Xtrain) Xtrain_ = kbs.transform(Xtrain) Xtest_ = kbs.transform(Xtest)Xtrain_.shape #把原先的兩個特征分了10個箱鎖分出來的啞變量 #(700, 20)mnb = MultinomialNB().fit(Xtrain_, Ytrain) mnb.score(Xtest_,Ytest) #0.9966666666666667brier_score_loss(Ytest,mnb.predict_proba(Xtest_)[:,1],pos_label=1) #0.0014593932778211862可以看出,多項式樸素貝葉斯的基本操作和代碼都非常簡單。同樣的數據,如果采用啞變量方式的分箱處理,多項式貝葉斯的效果會突飛猛進。作為在文本分類中大放異彩的算法,我們將會在案例中來詳細講解多項式貝葉斯的使用,?并為大家介紹文本分類的更多細節。
伯努利樸素貝葉斯BernoulliNB
多項式樸素貝葉斯可同時處理二項分布(拋硬幣)和多項分布(擲骰子),其中二項分布又叫做伯努利分布,它是一?種現實中常見,并且擁有很多優越數學性質的分布。因此,既然有著多項式樸素貝葉斯,我們自然也就又專門用來處理二項分布的樸素貝葉斯:伯努利樸素貝葉斯。
伯努利貝葉斯類BernoulliN假設數據服從多元伯努利分布,并在此基礎上應用樸素貝葉斯的訓練和分類過程。多元伯努利分布簡單來說,就是數據集中可以存在多個特征,但每個特征都是二分類的,可以以布爾變量表示,也可以表示?為{0,1}或者{-1,1}等任意二分類組合。因此,這個類要求將樣本轉換為二分類特征向量,如果數據本身不是二分類的,那可以使用類中專門用來二值化的參數binarize來改變數據。
多項式樸素貝葉斯——這個特征對這個樣本而言發生了幾次(單詞計數)
伯努利樸素貝葉斯——這個特征發生了嗎?發生還是沒發生(單詞出現)
伯努利樸素貝葉斯與多項式樸素貝葉斯非常相似,都常用于處理文本分類數據。但由于伯努利樸素貝葉斯是處理二項分布,所以它更加在意的是“存在與否”,而不是“出現多少次”這樣的次數或頻率,這是伯努利貝葉斯與多項式貝葉斯的根本性不同。在文本分類的情況下,伯努利樸素貝葉斯可以使用單詞出現向量(而不是單詞計數向量)來訓練分類器。文檔較短的數據集上,伯努利樸素貝葉斯的效果會更加好。如果時間允許,建議兩種模型都試試看。
來看看伯努利樸素貝葉斯類的參數:
from sklearn.naive_bayes import BernoulliNB #普通來說我們應該使用二值化的類sklearn.preprocessing.Binarizer來將特征一個個二值化 #然而這樣效率過低,因此我們選擇歸一化之后直接設置一個閾值 #歸一化,消除負數 mms = MinMaxScaler().fit(Xtrain) Xtrain_ = mms.transform(Xtrain) Xtest_ = mms.transform(Xtest)#不設置二值化 bnl_ = BernoulliNB().fit(Xtrain_, Ytrain) bnl_.score(Xtest_,Ytest) brier_score_loss(Ytest,bnl_.predict_proba(Xtest_)[:,1],pos_label=1) #0.49666666666666665 #0.25000009482193225#設置二值化閾值為0.5 bnl = BernoulliNB(binarize=0.5).fit(Xtrain_, Ytrain) bnl.score(Xtest_,Ytest) brier_score_loss(Ytest,bnl.predict_proba(Xtest_)[:,1],pos_label=1) #0.9833333333333333 #0.010405875827339534和多項式貝葉斯一樣,伯努利貝葉斯的結果也受到數據結構非常大的影響。因此,根據數據的模樣選擇貝葉斯,是貝葉斯模型選擇中十分重要的一點。?
探索貝葉斯:貝葉斯的樣本不均衡問題
from sklearn.naive_bayes import MultinomialNB, GaussianNB, BernoulliNB from sklearn.model_selection import train_test_split from sklearn.datasets import make_blobs from sklearn.preprocessing import KBinsDiscretizer from sklearn.metrics import brier_score_loss as BS,recall_score,roc_auc_score as AUC class_1 = 50000 #多數類為50000個樣本 class_2 = 500 #少數類為500個樣本 centers = [[0.0, 0.0], [5.0, 5.0]] #設定兩個類別的中心 clusters_std = [3, 1] #設定兩個類別的方差 X, y = make_blobs(n_samples=[class_1, class_2],centers=centers,cluster_std=clusters_std,random_state=0, shuffle=False) name = ["Multinomial" ,"Gaussian","Bernoulli"] models = [MultinomialNB(),GaussianNB(),BernoulliNB()]for name,clf in zip(name,models):Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)if name != "Gaussian":kbs = KBinsDiscretizer(n_bins=10, encode='onehot').fit(Xtrain)Xtrain = kbs.transform(Xtrain)Xtest = kbs.transform(Xtest)clf.fit(Xtrain,Ytrain)y_pred = clf.predict(Xtest)proba = clf.predict_proba(Xtest)[:,1]score = clf.score(Xtest,Ytest)print(name)print("\tBrier:{:.3f}" .format(BS(Ytest,proba,pos_label=1)))print("\tAccuracy:{:.3f}" .format(score))print("\tRecall:{:.3f}" .format(recall_score(Ytest,y_pred)))print("\tAUC:{:.3f}" .format(AUC(Ytest,proba)))結果:
MultinomialBrier:0.007Accuracy:0.990Recall:0.000AUC:0.991 GaussianBrier:0.006Accuracy:0.990Recall:0.438AUC:0.993 BernoulliBrier:0.009Accuracy:0.987Recall:0.771AUC:0.987從結果上來看,多項式樸素貝葉斯判斷出了所有的多數類樣本,但放棄了全部的少數類樣本,受到樣本不均衡問題影響最嚴重。高斯比多項式在少數類的判斷上更加成功一些,至少得到了43.8%的recall。伯努利貝葉斯雖然整體的準確度和布里爾分數不如多項式和高斯樸素貝葉斯和,但至少成功捕捉出了77.1%的少數類。可見,伯努利貝葉斯最能夠忍受樣本不均衡問題。
可是,伯努利貝葉斯只能用于處理二項分布數據,在現實中,強行將所有的數據都二值化不會永遠得到好結果,在我們有多個特征的時候,我們更需要一個個去判斷究竟二值化的閾值該取多少才能夠讓算法的效果優秀。這樣做無疑是非常低效的。那如果我們的目標是捕捉少數類,我們應該怎么辦呢?高斯樸素貝葉斯的效果雖然比多項式好,但是也沒有好到可以用來幫助我們捕捉少數類的程度——43.8%,還不如拋硬幣的結果。因此,孜孜不倦的統計學家們改進了樸素貝葉斯算法,修正了包括無法處理樣本不平衡在內的傳統樸素貝葉斯的眾多缺點,得到了新興貝葉斯算法:補集樸素貝葉斯。
改進多項式樸素貝葉斯:補集樸素貝葉斯ComplementNB
from sklearn.naive_bayes import ComplementNB from time import time import datetimename = ["Multinomial","Gaussian","Bernoulli","Complement"] models = [MultinomialNB(),GaussianNB(),BernoulliNB(),ComplementNB()] for name,clf in zip(name,models):times = time()Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)#預處理if name != "Gaussian":kbs = KBinsDiscretizer(n_bins=10, encode='onehot').fit(Xtrain)Xtrain = kbs.transform(Xtrain)Xtest = kbs.transform(Xtest)clf.fit(Xtrain,Ytrain)y_pred = clf.predict(Xtest)proba = clf.predict_proba(Xtest)[:,1]score = clf.score(Xtest,Ytest)print(name)print("\tBrier:{:.3f}".format(BS(Ytest,proba,pos_label=1)))print("\tAccuracy:{:.3f}".format(score))print("\tRecall:{:.3f}".format(recall_score(Ytest,y_pred)))print("\tAUC:{:.3f}".format(AUC(Ytest,proba)))print(datetime.datetime.fromtimestamp(time()-times).strftime("%M:%S:%f"))?結果:
MultinomialBrier:0.007Accuracy:0.990Recall:0.000AUC:0.991 00:00:060486 GaussianBrier:0.006Accuracy:0.990Recall:0.438AUC:0.993 00:00:018604 BernoulliBrier:0.009Accuracy:0.987Recall:0.771AUC:0.987 00:00:028316 ComplementBrier:0.038Accuracy:0.953Recall:0.987AUC:0.991 00:00:030288可以發現,補集樸素貝葉斯犧牲了部分整體的精確度和布里爾指數,但是得到了十分高的召回率Recall,捕捉出了98.7%的少數類,并且在此基礎上維持了和原本的多項式樸素貝葉斯一致的AUC分數。和其他的貝葉斯算法比起來,我們的補集樸素貝葉斯的運行速度也十分優秀。如果我們的目標是捕捉少數類,那我們毫無疑問會希望選擇補集樸素貝葉斯作為我們的算法。?
?
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的Sklearn(v3)——朴素贝叶斯(3)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Sklearn(v3)——朴素贝叶斯(2
- 下一篇: 李宏毅深度学习——第一天