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.9966666666666667

brier_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)))

结果:

Multinomial
	Brier:0.007
	Accuracy:0.990
	Recall:0.000
	AUC:0.991
Gaussian
	Brier:0.006
	Accuracy:0.990
	Recall:0.438
	AUC:0.993
Bernoulli
	Brier:0.009
	Accuracy:0.987
	Recall:0.771
	AUC:0.987

从结果上来看多项式朴素贝叶斯判断出了所有的多数类样本但放弃了全部的少数类样本受到样本不均衡问题响最严重。高斯比多项式在少数类的判断上更加成功一些至少得到了43.8%recall伯努利贝叶斯虽然整体的准确度和布里尔分数不如多项式和高斯朴素贝叶斯和但至少成功捕捉出了77.1%的少数类伯努利贝叶斯最能够忍受样本不均衡问题

可是伯努利贝叶斯只能用于处理二项分布数据在现实中强行将所有的数据都二值化不会永远得到好结果在我们有多个特征的时候我们更需要一个个去判断究竟二值化的阈值该取多少才能够让算法的效果优秀这样做无疑是非常低效的那如果我们的目标是捕捉少数类我们应该怎么办呢?高斯朴素贝叶斯的效果虽然比多项式好但是没有好到可以用来帮助我们捕捉少数类的程度——43.8%还不如抛硬币的结果孜孜不倦的统计学家们改进了朴素贝叶斯算法修正了包括无法处理样本不平衡在内的传统朴素贝叶斯的众多缺点得到了新兴贝叶斯算法集朴素贝叶斯

改进多项式朴素贝叶斯:补集朴素贝叶斯ComplementNB

from sklearn.naive_bayes import ComplementNB
from time import time
import datetime

name = ["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"))

 结果:

Multinomial
	Brier:0.007
	Accuracy:0.990
	Recall:0.000
	AUC:0.991
00:00:060486
Gaussian
	Brier:0.006
	Accuracy:0.990
	Recall:0.438
	AUC:0.993
00:00:018604
Bernoulli
	Brier:0.009
	Accuracy:0.987
	Recall:0.771
	AUC:0.987
00:00:028316
Complement
	Brier:0.038
	Accuracy:0.953
	Recall:0.987
	AUC:0.991
00:00:030288

可以发现,补集朴素贝叶斯牺牲了部分整体的精确度和布里尔指数但是得到了十分高的召回率Recall捕捉出了98.7%的少数类,并且在此基础上维持了和原本的多项式朴素贝叶斯一致的AUC分数和其他的贝叶斯算法比起来我们的补集朴素贝叶斯的运行速度也十分优秀如果我们的目标是捕捉少数类,那我们毫无疑问会希望选择补集朴素叶斯作为我们的算法 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
朴素叶斯算法是一种经典的机器学习算法,常用于文本分类、情感分析等领域。在Sklearn中,实现了三种朴素叶斯算法:高斯朴素叶斯、多项式朴素叶斯和伯努利朴素叶斯。 在使用Sklearn中的朴素叶斯算法时,通常需要进行如下几个步骤: 1. 准备数据集:将数据集分为训练集和测试集,通常采用80%的数据作为训练集,20%的数据作为测试集。 2. 特征工程:将原始数据转化为机器学习算法所需的特征表示。对于文本数据,通常采用词袋模型或TF-IDF模型进行特征提取。 3. 构建模型:选择适合数据集的朴素叶斯算法,如高斯朴素叶斯、多项式朴素叶斯或伯努利朴素叶斯,并利用训练集进行模型训练。 4. 模型评估:使用测试集对模型进行评估,如计算准确率、精确率、召回率、F1值等指标。 下面是一个使用Sklearn中的多项式朴素叶斯算法进行文本分类的示例代码: ```python from sklearn.datasets import fetch_20newsgroups from sklearn.feature_extraction.text import CountVectorizer from sklearn.naive_bayes import MultinomialNB from sklearn.metrics import accuracy_score # 加载数据集 newsgroups_train = fetch_20newsgroups(subset='train') newsgroups_test = fetch_20newsgroups(subset='test') # 特征工程:采用词袋模型进行特征提取 vectorizer = CountVectorizer() X_train = vectorizer.fit_transform(newsgroups_train.data) X_test = vectorizer.transform(newsgroups_test.data) # 构建模型:采用多项式朴素叶斯算法进行分类 clf = MultinomialNB() clf.fit(X_train, newsgroups_train.target) # 模型评估:计算测试集的准确率 y_pred = clf.predict(X_test) accuracy = accuracy_score(newsgroups_test.target, y_pred) print("Accuracy:", accuracy) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值