朴素贝叶斯

sklearn中的朴素贝叶斯

含义
naive_bayes.GaussianNB 高斯分布下的朴素贝叶斯
naive_bayes.BernoulliNB 伯努利分布下的朴素贝叶斯
naive_bayes.MultinomialNB 多项式分布下的朴素贝叶斯
naive_bayes.ComplementNB 补集朴素贝叶斯


1. 高斯朴素贝叶斯 GaussianNB

class sklearn.naive_bayes.GaussianNB (priors=None, var_smoothing=1e-09)

参数:

  • prior :可输入任何类数组结构,形状为(n_classes,) 表示类的先验概率。如果指定,则不根据数据调整先验,如果不指定,则自行根据数据计 算先验概率 $P(Y)$
  • var_smoothing : 浮点数,可不填(默认值= 1e-9) 在估计方差时,为了追求估计的稳定性,将所有特征的方差中最大的方差以某个比例添加 到估计的方差中。这个比例,由var_smoothing参数控制

Examples:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split

digits = load_digits() #手写数据集
X, y = digits.data, digits.target
# 划分数据集
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=420)
np.unique(Ytrain) #多分类问题,类别是10个

gnb = GaussianNB().fit(Xtrain,Ytrain)

#查看分数
acc_score = gnb.score(Xtest,Ytest) #返回预测的精确性 accuracy

#查看预测结果
Y_pred = gnb.predict(Xtest)

#查看预测的概率结果
prob = gnb.predict_proba(Xtest)
prob.shape #每一列对应一个标签类别下的概率
# (540, 10)

使用混淆矩阵来查看贝叶斯的分类结果

from sklearn.metrics import confusion_matrix as CM

CM(Ytest,Y_pred)

#注意,ROC曲线是不能用于多分类的。多分类状况下最佳的模型评估指标是混淆矩阵和整体的准确度

#array([[47,  0,  0,  0,  0,  0,  0,  1,  0,  0],
#       [ 0, 46,  2,  0,  0,  0,  0,  3,  6,  2],
#       [ 0,  2, 35,  0,  0,  0,  1,  0, 16,  0],
#       [ 0,  0,  1, 40,  0,  1,  0,  3,  4,  0],
#       [ 0,  0,  1,  0, 39,  0,  1,  4,  0,  0],
#       [ 0,  0,  0,  2,  0, 58,  1,  1,  1,  0],
#       [ 0,  0,  1,  0,  0,  1, 49,  0,  0,  0],
#       [ 0,  0,  0,  0,  0,  0,  0, 54,  0,  0],
#       [ 0,  3,  0,  1,  0,  0,  0,  2, 55,  0],
#       [ 1,  1,  0,  1,  2,  0,  0,  3,  7, 41]], dtype=int64)

2. 多项式朴素贝叶斯 MultinomialNB

多项式贝叶斯可能是除了高斯之外,最为人所知的贝叶斯算法了。它也是基于原始的贝叶斯理论,但假设概率分布是服从一个简单多项式分布。多项式分布来源于统计学中的多项式实验,这种实验可以具体解释为:实验包括n次重复试验,每项试验都有不同的可能结果。在任何给定的试验中,特定结果发生的概率是不变的。

  1. 多项式分布擅长的是分类型变量
  2. 多项式实验中的实验结果都很具体,它所涉及的特征往往是次数,频率,计数,出现与否这样的概念,这些概念都是离散的正整数,因此sklearn中的多项式朴素贝叶斯不接受负值的输入

由于这样的特性,多项式朴素贝叶斯的特征矩阵经常是稀疏矩阵(不一定总是稀疏矩阵),并且它经常被用于文本分类

多项式模型在计算先验概率 P(yk)P(y_{k}) 和条件概率 P(xiyk)P(x_{i}|y_{k}) 时,会做一些平滑处理,具体公式为:

undefined

N是总的样本个数,k是总的类别个数,NykN_{y_{k}} 是类别为 yky_k 的样本个数,α\alpha 是平滑值。

undefined

NykN_{y_{k}} 是类别为 yky_k 的样本个数,n是特征的维数,Nyk,xiN_{y_{k},x_{i}} 是类别为 yky_k 的样本中,第 ii 维特征的值是xix_i 的样本个数,α\alpha 是平滑值。

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

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

参数:

  • alpha : 浮点数, 可不填 (默认为1.0)

    拉普拉斯或利德斯通平滑的参数 α\alpha ,如果设置为0则表示完全没有平滑选项。但是需要注意的是,平滑相当于人 为给概率加上一些噪音,因此 $\alpha$ 设置得越大,多项式朴素贝叶斯的精确性会越低(虽然影响不是非常大),布里 尔分数也会逐渐升高

  • fit_prior : 布尔值, 可不填 (默认为True)

    是否学习先验概率 。如果设置为false,则不使用先验概率,而使用统一先验概率(uniform prior),即认为每个标签类出现的概率是 1 / n_classes

  • class_prior:形似数组的结构,结构为(n_classes, ),可不填(默认为None)

    类的先验概率 P(Y=c)P(Y=c)。如果没有给出具体的先验概率则自动根据数据来进行计算


Examples:

导入需要的模块和库

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_los

建立数据集

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])
mnb.class_log_prior_.shape


np.unique(Ytrain)
# array([0, 1])

#可以使用np.exp来查看真正的概率值
np.exp(mnb.class_log_prior_)
# 两类的概率值
# array([0.50142857, 0.49857143])

#重要属性:返回一个固定标签类别下的每个特征的对数概率log(P(Xi|y))
mnb.feature_log_prob_

# array([[-0.76164788, -0.62903951],
#       [-0.72500918, -0.6622691 ]])
mnb.feature_log_prob_.shape
# 2 个特征,2 个标签
# (2, 2)

#重要属性:在fit时每个标签类别下包含的样本数。当fit接口中的sample_weight被设置时,
#该接口返回的值也会受到加权的影响
mnb.class_count_
# 每个类别样本的数量
#array([351., 349.])
mnb.class_count_.shape

分类器的效果如何呢?

#一些传统的接口
mnb.predict(Xtest_)
mnb.predict_proba(Xtest_)
mnb.score(Xtest_,Ytest)
# 0.5433333333333333

效果不太理想

#来试试看把Xtiain转换成分类型数据吧
#注意我们的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

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

3. 伯努利朴素贝叶斯 BernoulliNB

多项式朴素贝叶斯可同时处理二项分布(抛硬币)和多项分布(掷骰子),其中二项分布又叫做伯努利分布,它是一种现实中常见,并且拥有很多优越数学性质的分布。因此,既然有着多项式朴素贝叶斯,我们自然也就又专门用来处理二项分布的朴素贝叶斯:伯努利朴素贝叶斯。

伯努利贝叶斯类BernoulliN假设数据服从多元伯努利分布,并在此基础上应用朴素贝叶斯的训练和分类过程。多元伯努利分布简单来说,就是数据集中可以存在多个特征,但每个特征都是二分类的,可以以布尔变量表示,也可以表示为{0,1}或者{-1,1}等任意二分类组合。因此,这个类要求将样本转换为二分类特征向量,如果数据本身不是二分类的,那可以使用类中专门用来二值化的参数binarize来改变数据。

伯努利朴素贝叶斯与多项式朴素贝叶斯非常相似,都常用于处理文本分类数据。但由于伯努利朴素贝叶斯是处理二项分布,所以它更加在意的是“存在与否”,而不是“出现多少次”这样的次数或频率,这是伯努利贝叶斯与多项式贝叶斯的根本性不同。在文本分类的情况下,伯努利朴素贝叶斯可以使用单词出现向量(而不是单词计数向量)来训练分类器。文档较短的数据集上,伯努利朴素贝叶斯的效果会更加好


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

参数:

  • alpha : 浮点数, 可不填 (默认为1.0)

    拉普拉斯或利德斯通平滑的参数 α\alpha ,如果设置为0则表示完全没有平滑选项。但是需要注意的是,平滑相当于人 为给概率加上一些噪音,因此 设置得越大,多项式朴素贝叶斯的精确性会越低(虽然影响不是非常大),布里 尔分数也会逐渐升高

  • binarize : 浮点数或None,可不填,默认为0

    将特征二值化的阈值,如果设定为None,则会假定说特征已经被二值化完毕

  • fit_prior : 布尔值, 可不填 (默认为True)

    是否学习先验概率 P(Y=c)P(Y=c) 。如果设置为false,则不使用先验概率,而使用统一先验概率(uniform prior),即认为每个标签类出现的概率是 1 / n_classes.

  • class_prior:形似数组的结构,结构为(n_classes, ),可不填(默认为None)

    类的先验概率 P(Y=c)P(Y=c) 。如果没有给出具体的先验概率则自动根据数据来进行计算。


Examples:

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


4. 补集朴素贝叶斯ComplementNB

补集朴素贝叶斯(complement naive Bayes,CNB)算法是标准多项式朴素贝叶斯算法的改进。CNB的发明小组创造出CNB的初衷是为了解决贝叶斯中的“朴素”假设带来的各种问题,他们希望能够创造出数学方法以逃避朴素贝叶斯中的朴素假设,让算法能够不去关心所有特征之间是否是条件独立的。以此为基础,他们创造出了能够解决样本不平衡问题,并且能够一定程度上忽略朴素假设的补集朴素贝叶斯

在实验中,CNB的参数估计已经被证明比普通多项式朴素贝叶斯更稳定,并且它特别适合于样本不平衡的数据集。有时候,CNB在文本分类任务上的表现有时能够优于多项式朴素贝叶斯,因此现在补集朴素贝叶斯也开始逐渐流行


在sklearn中,补集朴素贝叶斯由类ComplementNB完成,它包含的参数和多项式贝叶斯也非常相似:

class sklearn.naive_bayes.ComplementNB (alpha=1.0, fit_prior=True, 
                                        class_prior=None, norm=False)

参数:

  • alpha : 浮点数, 可不填 (默认为1.0)

    拉普拉斯或利德斯通平滑的参数 α\alpha ,如果设置为0则表示完全没有平滑选项。但是需要注意的是,平滑相当于人 为给概率加上一些噪音,因此 $\alpha$ 设置得越大,多项式朴素贝叶斯的精确性会越低(虽然影响不是非常大),布里 尔分数也会逐渐升高

  • norm : 布尔值,可不填,默认False

    在计算权重的时候是否适用L2范式来规范权重的大小。默认不进行规范,即不跟从补集朴素贝叶斯算法的全部 内容,如果希望进行规范,请设置为True

  • fit_prior : 布尔值, 可不填 (默认为True)

    是否学习先验概率 。如果设置为false,则不使用先验概率,而使用统一先验概率(uniform prior),即认为每个标签类出现的概率是 1 / n_classes

  • class_prior:形似数组的结构,结构为(n_classes, ),可不填(默认为None)

    类的先验概率 P(Y=c)P(Y=c)。如果没有给出具体的先验概率则自动根据数据来进行计算

Examples:

那来看看,补集朴素贝叶斯在不平衡样本上的表现吧,同时我们来计算一下每种贝叶斯的计算速度:

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:050863
Gaussian
    Brier:0.006
    Accuracy:0.990
    Recall:0.438
    AUC:0.993
00:00:038898
Bernoulli
    Brier:0.009
    Accuracy:0.987
    Recall:0.771
    AUC:0.987
00:00:049866
Complement
    Brier:0.038
    Accuracy:0.953
    Recall:0.987
    AUC:0.991
00:00:044881

参考

  1. 朴素贝叶斯的三个常用模型:高斯、多项式、伯努利
  2. 朴素贝叶斯理论推导与三种常见模型
Update time: 2020-05-23

results matching ""

    No results matching ""