探索贝叶斯-多项式/伯努力/补集朴素贝叶斯

目录

1. 多项式朴素贝叶斯及其变化

1.1 多项式朴素贝叶斯MultinomialNB

2. 伯努力朴素贝叶斯BernoulliNB

3. 补集朴素贝叶斯

4. 探索贝叶斯:贝叶斯的样本不均衡问题


1. 多项式朴素贝叶斯及其变化

1.1 多项式朴素贝叶斯MultinomialNB

class sklearn.naive_bayes.MultinomialNB(alpha=1.0,fit_prior=True,class_prior=None)

        多项式贝叶斯也是基于原始的贝叶斯理论,但假设概率分布是服从一个简单多项式分布。多项式分布来源于统计学中的多项式实验,这种实验可以具体解释为:实验包括n次重复试验,每项试验都有不同的可能结果。在任何给定的试验中,特定结果发生的概率是不变的。
        举个例子,比如,一个特征矩阵表示投掷硬币的结果,则得到正面的概率为P(X=正面|Y) = 0.5,反面的概率为P(X=反面|Y) = 0.5,只有这两种可能,并且两种结果互不干涉,两个随机事件的概率加和为1,这就是二项分布。这种情况下,适合于多项式朴素贝叶斯的特征矩阵应该长这样:

测试编号 X1:出现正面 X2:出现反面
0 0 1
1 1 0
2 1 0
3 0 1

假设另一个特征矩阵表示投掷骰子的结果,则i就可以在[1,2,3,4,5,6]中取值,六种结果互不干涉,且只要样本量足够大,概率都为1/6,这就是一个多项分布。多项分布的特征矩阵应该长这样:

测试编号 出现1 出现2 出现3 出现4 出现5 出现6
0 1 0 0 0 0 0
1 0 0 0 0 0 1
2 0 0 1 0 0 0
……
m 0 0 0 0 0 1

可以看出:多项式分布擅长的是分类型变量,在其原理假设中,P(X_{i}|Y)的概率是离散的,并且不同X_{i}下的P(X_{i}|Y)相互独立,互不影响。虽然sklearn中的多项式分布也可以处理连续型变量,但现实中,如果我们真的想要处理连续型变量,应当使用高斯朴素贝叶斯。多项式实验中的实验结果都很具体,它所涉及的特征往往是次数,频率,计数,出现与否这样的概念,这些概念都是离散的正整数,因此,sklearn中的多项式朴素贝叶斯不接受负值的输入

        由于这样的特性,多项式朴素贝叶斯的特征矩阵经常是稀疏矩阵(不一定总是稀疏矩阵),并且它经常被用于文本分类。我们可以使用著名的TF-IDF向量技术,也可以使用常见并且简单的单词计数向量手段与贝叶斯配合使用。这两种手段都属于常见的文本特征提取的方法,可以很简单地通过sklearn来实现。

        从数学的角度来看,在一种标签类别Y=c下,有一组分别对应特征的参数向量\theta _{c}=(\theta _{c1},\theta _{c2},....,\theta _{cn}),其中n表示特征的总数。一个\theta _{ci}表示这个标签类别下的第i个特征所对应的参数。这个参数被我们定义为:

记作P(X_{i}|Y=c),表示Y=c这个条件固定的时候,一组样本在 X_{i}在这个特征上的取值被取到的概率。对于一个在标签类别下,结构为(m, n)的特征矩阵来说,有:

X_{y}=\begin{bmatrix} x_{11} & x_{12}& x_{13}& ...& x_{1n}\\ x_{21} & x_{22}& x_{23}& ...& x_{2n}\\ x_{31} & x_{32}& x_{33}& ...& x_{3n}\\ & & ...& & \\ x_{m1} & x_{m2}& x_{m3}& ...& x_{mn}\\ \end{bmatrix}

其中每个x_{ji}都是特征X_{i},基于这些理解,通过平滑后的最大似然估计来求解参数\theta_{y}:

\alpha被称为平滑系数,令\alpha>0来防止训练数据中出现过的一些词汇没有出现在测试集中导致的0概率,以避免让参数θ为0的情况。如果\alpha=1,则这个平滑叫做拉普拉斯平滑,\alpha<1,叫做利德斯通平滑。两种平滑都属于自然语言处理中比较常用的用来平滑分类数据的统计手段。

在sklearn中,用来执行多项式朴素贝叶斯的类MultinomialNB包含如下参数和属性:

参数
alpha : 浮点数, 可不填 (默认为1.0)
拉普拉斯或利德斯通平滑的参数\alpha,如果设置为0则表示完全没有平滑选项。但是需要注意的是,平滑相当于人为给概率加上一些噪音,因此\alpha设置得越大,多项式朴素贝叶斯的精确性会越低(虽然影响不是非常大)。
fit_prior : 布尔值, 可不填 (默认为True)
是否学习先验概率P(Y=c)。如果设置为false,则所有的样本类别输出都有相同的类别先验概率。即认为每个标签类出现的概率是\frac{1}{n.classes}
class_prior:形似数组的结构,结构为(n_classes, ),可不填(默认为None)
类的先验概率P(Y=c)。如果没有给出具体的先验概率则自动根据数据来进行计算

 通常,在实例化多项式朴素贝叶斯的时候,会让所有的参数保持默认。先来简单建一个多项式朴素贝叶斯的例子试试看:

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)
(ytrain==1).sum()/ytrain.shape[0] #计数:所有标签类别=1的样本量
0.49857142857142855
(ytrain==0).sum()/ytrain.shape[0] #计数:所有标签类别=1的样本量
0.5014285714285714
mnb.score(xtest_,ytest)
0.5433333333333333
brier_score_loss(ytest,mnb.predict_proba(xtest_)[:,0],pos_label=0)
0.24977828412546035

布里尔分数较高,精确度较低,把xtrain转换成分类型数据:

from sklearn.preprocessing import KBinsDiscretizer #对连续型变量分箱
kbs=KBinsDiscretizer(n_bins=10,encode='onehot').fit(xtrain)
xtrain_=kbs.transform(xtrain)
xtest_=kbs.transform(xtest)
# 建立多项式朴素贝叶斯分类器
mnb=MultinomialNB().fit(xtrain_,ytrain)
mnb.score(xtest_,ytest)
0.9966666666666667
brier_score_loss(ytest,mnb.predict_proba(xtest_)[:,0],pos_label=0)
0.001459393277821188

可以看出多项式朴素贝叶斯的基本操作和代码较简单。同样的数据,如果采用哑变量方式分箱处理,多项式贝叶斯效果会突飞猛进。

2. 伯努力朴素贝叶斯BernoulliNB

class sklearn.naive_bayes.BernoulliNB (alpha=1.0, binarize=0.0,fit_prior=True,class_prior=None)

        多项式朴素贝叶斯可同时处理二项分布(抛硬币)和多项分布(掷骰子),其中二项分布又叫做伯努利分布,它是一种现实中常见,并且拥有很多优越数学性质的分布。因此,既然有着多项式朴素贝叶斯,自然也就又专门用来处理理二项分布的朴素贝叶斯:伯努利利朴素贝叶斯。
        伯努利贝叶斯类BernoulliNB假设数据服从多元伯努利分布,并在此基础上应用朴素贝叶斯的训练和分类过程。多元伯努利分布简单来说,就是数据集中可以存在多个特征,但每个特征都是二分类的,可以用布尔变量表示,也可以表示为{0,1}或者{-1,1}等任意二分类组合。因此,这个类要求将样本转换为二分类特征向量,如果数据本身不是二分类的,可以使用类中专门用来二值化的参数binarize来改变数据。
        伯努利朴素贝叶斯与多项式朴素贝叶斯非常相似,都常用于处理文本分类数据。但由于伯努利朴素贝叶斯是处理二项分布的,所以它更加在意的是“存在与否”,而不是“出现多少次”这样的次数或频率,这就是伯努利贝叶斯与多项式贝叶斯的根本性不同。在文本分类的情况下,伯努利朴素贝叶斯可以使用单词出现向量(而不是单词计数向量)来训练分类器。文档较短的数据集上,伯努利朴素贝叶斯的效果会更加好。

伯努力朴素贝叶斯
alpha : 浮点数, 可不填 (默认为1.0)
拉普拉斯或利德斯通平滑的参数\alpha,如果设置为0则表示完全没有平滑选项。但是需要注意的是,平滑相当于人为给概率加上一些噪音,因此\alpha设置得越大,伯努利朴素贝叶斯的精确性会越低(虽然影响不是非常大),布里尔分数也会逐渐升高。
binarize : 浮点数或None,可不填,默认为0
将特征二值化的阈值,如果设定为None,则假定为特征已经被二值化完毕
fit_prior : 布尔值, 可不填 (默认为True)
是否学习先验概率P(Y=c)。如果设置为false,则不使用先验概率,而使用统一先验概率(uniform prior),即认为每个标签类出现的概率是\frac{1}{n.classes}
class_prior:形似数组的结构,结构为(n_classes, ),可不不填(默认为None)
类的先验概率P(Y=c)。如果没有给出具体的先验概率则自动根据数据来进行计算。

 在sklearn中,伯努利朴素贝叶斯的实现也非常简单:

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)
0.49666666666666665
brier_score_loss(ytest,bnl_.predict_proba(xtest_)[:,1],pos_label=1)
0.25000009482193225
# 设置阈值为0.5
bnl_=BernoulliNB(binarize=0.5).fit(xtrain_,ytrain)
bnl_.score(xtest_,ytest)
0.983333333333333
brier_score_loss(ytest,bnl_.predict_proba(xtest_)[:,1],pos_label=1)
0.010405875827339534

和多项式贝叶斯⼀样,伯努利贝叶斯的结果也受到数据结构非常大的影响。因此,根据数据的模样选择贝叶斯,是贝叶斯模型选择中十分重要的一点。

3. 补集朴素贝叶斯

补集朴素贝叶斯是多项式朴素贝叶斯的一种改进,它包含的参数和多项式朴素贝叶斯也非常相似。

4. 探索贝叶斯:贝叶斯的样本不均衡问题

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
              )
from sklearn.naive_bayes import ComplementNB
from time import time
import datetime
name=["Multinomial","GaussianNB","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!="GaussianNB":
        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:040009
GaussianNB
	Brier:0.006
	Accuracy:0.990
	Recall:0.438
	AUC:0.993
00:00:023005
Bernoulli
	Brier:0.009
	Accuracy:0.987
	Recall:0.771
	AUC:0.987
00:00:035008
Complement
	Brier:0.038
	Accuracy:0.953
	Recall:0.987
	AUC:0.991
00:00:033008

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

 
 

猜你喜欢

转载自blog.csdn.net/weixin_60200880/article/details/129307096