欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Sklearn(v3)——朴素贝叶斯(3)

发布时间:2025/3/21 编程问答 23 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。