基于原始的贝叶斯理论,但假设概率分布是服从一个简单多项式分布。可以具体解释为:实验包括n次重复试验,每项试验都有不同的可能结果。在任何给定的试验中,特定结果发生的概率是不变的。特点如下:
参数 | 含义 |
---|---|
alpha | 浮点数, 可不填 (默认为1.0) 拉普拉斯或利德斯通平滑的参数 ,如果设置为0则表示完全没有平滑选项。平滑相当于人为给概率加上噪音,因此 设置得越大,多项式朴素贝叶斯的精确性会越低(影响不是非常大),布里尔分数也会升高 |
fit_prior | 布尔值, 可不填 (默认为True) 是否学习先验概率,如果设置为false,则不使用先验概率,而使用统一先验概率(uniformprior),即认为每个标签类出现的概率是 1 n _ c l a s s e s \frac{1}{n_{\_}classes} n_classes1 |
class_prior | 形似数组的结构,结构为(n_classes, ),可不填(默认为None)类的先验概率 。如果没有给出具体的先验概率则自动根据数据来进行计算 |
一个多项式朴素贝叶斯的例子
第一步:导入模块和数据建立并归一化
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
import numpy as np
class_1 = 500
class_2 = 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)
mnb.class_log_prior_
#查看正正的概率值
np.exp(mnb.class_log_prior_)
mnb.score(Xtest_,Ytest)
brier_score_loss(Ytest,mnb.predict_proba(Xtest_)[:,1],pos_label=1)
第三步: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)
brier_score_loss(Ytest,mnb.predict_proba(Xtest_)[:,1],pos_label=1)
伯努利朴素贝叶斯是专门处理二项分布的朴素贝叶斯。它假设数据服从多元伯努利分布,即每个特征都是二分类的,如果数据本身不是二分类,那可以使用类中专门用于二值化的参数binarize来改变数据。在处理文本分类数据时,伯努利贝叶斯通常在意“存在与否”而不是“出现次数”。通常文本较短时使用伯努利贝叶斯效果更好。
sklearn中的伯努利朴素贝叶斯
参数 | 含义 |
---|---|
alpha | 浮点数, 可不填 (默认为1.0) 拉普拉斯或利德斯通平滑的参数 ,如果设置为0则表示完全没有平滑选项。平滑相当于人为给概率加上噪音,因此 设置得越大,多项式朴素贝叶斯的精确性会越低(影响不是非常大),布里尔分数也会升高 |
binarize | 浮点数或None,可不填,默认为0 将特征二值化的阈值,如果设定为None,则会假定说特征已经被二值化完毕 |
fit_prior | 布尔值, 可不填 (默认为True) 是否学习先验概率,如果设置为false,则不使用先验概率,而使用统一先验概率(uniformprior),即认为每个标签类出现的概率是 1 n _ c l a s s e s \frac{1}{n_{\_}classes} n_classes1 |
class_prior | 形似数组的结构,结构为(n_classes, ),可不填(默认为None)类的先验概率 。如果没有给出具体的先验概率则自动根据数据来进行计算 |
sklearn中简单的使用
from sklearn.naive_bayes import BernoulliNB
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)
#设置二值化阈值
bnl = BernoulliNB(binarize=0.5).fit(Xtrain_,Ytrain)
bnl.score(Xtest_,Ytest)
brier_score_loss(Ytest,bnl_.predict_proba(Xtest_)[:,1],pos_label=1)
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
class_2 = 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)
X.shape
第二步:查看不同贝叶斯在不平衡数据集的表现
name = ["MultinomialNB","Gaussian","BernoulliNB"]
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)))
从结果看,多项式朴素贝叶斯受影响最严重,伯努利最能忍受样本不均衡问题。如果现实中,目标是捕捉少数类,可以利用补集朴素贝叶斯,它修正了包括无法处理样本不平衡在内的传统朴素贝叶斯的众多特点
CNB使用每个标签类别的补集的概念计算每个特征的权重
θ ^ i , y ≠ c = α i + ∑ y j ≠ c x i j α i n + ∑ i , y ≠ c ∑ i = 1 n x i j \hat{\theta}_{i,y\neq c}=\frac{\alpha_i+\sum_{y_j {\neq {c} }}{x_{ij}}}{\alpha_in+\sum_{i,y\neq c}\sum_{i=1}^{n}x_{ij}} θ^i,y=c=αin+∑i,y=c∑i=1nxijαi+∑yj=cxij
补充朴素贝叶斯一个样本的预测规则为:
p ( Y ≠ c ∣ X ) = a r g min c ∑ i x i w c i p(Y\neq c|X)=arg\min_{c}\sum_{i}x_iw_{ci} p(Y=c∣X)=argcmini∑xiwci
即求解出最小补集最小的标签,也就是Y=c此时最大
sklean中的补集朴素贝叶斯
参数 | 含义 |
---|---|
alpha | 浮点数, 可不填 (默认为1.0) 拉普拉斯或利德斯通平滑的参数 ,如果设置为0则表示完全没有平滑选项。平滑相当于人为给概率加上噪音,因此 设置得越大,多项式朴素贝叶斯的精确性会越低(影响不是非常大),布里尔分数也会升高 |
norm | 布尔值,可不填,默认False 在计算权重的时候是否适用L2范式来规范权重的大小。默认不进行规范,即不跟从补集朴素贝叶斯算法的全部内容,如果希望进行规范,请设置为True |
fit_prior | 布尔值, 可不填 (默认为True) 是否学习先验概率,如果设置为false,则不使用先验概率,而使用统一先验概率(uniformprior),即认为每个标签类出现的概率是 1 n _ c l a s s e s \frac{1}{n_{\_}classes} n_classes1 |
class_prior | 形似数组的结构,结构为(n_classes, ),可不填(默认为None)类的先验概率 。如果没有给出具体的先验概率则自动根据数据来进行计算 |
补集朴素贝叶斯的在不平衡样本上的表现
from sklearn.naive_bayes import ComplementNB
from time import time
import datetime
import pytz
name = ["MultinomialNB","Gaussian","BernoulliNB","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,pytz.timezone('UTC')).strftime("%M:%S:%f"))
可以看到补集朴素贝叶斯牺牲了部分整体的精确度和布里尔指数,但是得到了十分高的召回率Recall,捕捉出了很多的少数类,并在此基础上维持了和原本多项式朴素贝叶斯一致的AUC分数。和其他贝叶斯算法相比,运行速度也很快。
单词计数向量
一个样本可以包含一段话或者一篇文章,一个特征代表一个单词,是一个离散的、代表次数的正整数。展示一个案例:
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
sample = ["Machine learning is fascinating, it is wonderful"
,"Machine learning is a sensational techonology"
,"Elsa is a popular character"]
vec = CountVectorizer()
X = vec.fit_transform(sample)
X
CVresult = pd.DataFrame(X.toarray(),columns = vec.get_feature_names())
CVresult
TF-IDF
全程term frequency-inverse document frequency,词频逆文档频率,通过单词在文档中出现的频率来衡量其权重,即IDF的大小与一个词的常见程度成反比。sklearn当中,我们使用feature_extraction.text中类TfidfVectorizer来执行这种编码
文本分类案例
第一步:导入数据以及探索数据
from sklearn.datasets import fetch_20newsgroups
data = fetch_20newsgroups()
data.target_names
参数 | 含义 |
---|---|
subset | 选择类中包含的数据子集 输入"train"表示选择训练集,“test"表示输入测试集,”all"表示加载所有的数据 |
categories | 可输入None或者数据所在的目录 选择一个子集下,不同类型或不同内容的数据所在的目录。如果不输入默认None,则会加载全部的目录 |
download_if_missing | 可选,默认是True 如果发现本地数据不全,是否自动进行下载 |
shuffle | 布尔值,可不填,表示是否打乱样本顺序 对于假设样本之间互相独立并且服从相同分布的算法或模型(比如随机梯度下降)来说可能很重要 |
第二步:提取希望得到的数据集
import numpy as np
import pandas as pd
categories = ["sci.space",
"rec.sport.hockey"
,"talk.politics.guns"
,"talk.politics.mideast"] #政治 - 中东问题
train = fetch_20newsgroups(subset="train",categories = categories)
test = fetch_20newsgroups(subset="test",categories=categories)
train
#查看提取的文章类别
train.target_names
#查看文章总数
len(train.data)
#提取某一篇文章
train.data[11]
#查看标签
np.unique(train.target)
#查看是否有样本不平衡问题
for i in [0,1,2,3]:
print(i,(train.target == i ).sum()/len(train.target))
from sklearn.feature_extraction.text import TfidfVectorizer as TFIDF
Xtrain = train.data
Xtest = test.data
Ytrain = train.target
Ytest = test.target
tfidf = TFIDF().fit(Xtrain)
Xtrain_ = tfidf.transform(Xtrain)
Xtest_ = tfidf.transform(Xtest)
Ytest_1 = Ytest.copy()
Ytest_1 = pd.get_dummies(Ytest_1)
Xtrain_
tosee = pd.DataFrame(Xtrain_.toarray(),columns=tfidf.get_feature_names())
tosee.head()
第四步:在贝叶斯上分别建模,查看结果
from sklearn.naive_bayes import MultinomialNB,ComplementNB,BernoulliNB
from sklearn.metrics import brier_score_loss as BS
name = ["Multinomial","Complement","Bournulli"]
models = [MultinomialNB(),ComplementNB(),BernoulliNB()]
for name,clf in zip(name,models):
clf.fit(Xtrain_,Ytrain)
y_pred = clf.predict(Xtest_)
proba = clf.predict_proba(Xtest_)
score = clf.score(Xtest_,Ytest)
print(name)
Bscore = []
for i in range(len(np.unique(Ytrain))):
bs = BS(Ytest_1[i],proba[:,i])
Bscore.append(bs)
print("\tBrier uder{}:{:.3f}".format(train.target_names[i],bs))
print("\tAverage Brier:{:.3f}".format(np.mean(Bscore)))
print("\tAccuracy:{:.3f}".format(score))
print("\n")
可以看到补集贝叶斯分数更高,但精确度更高。使用概率校准来进行突破:
from sklearn.calibration import CalibratedClassifierCV
name = ["Multinomial"
,"Multinomial + Isotonic"
,"Multinomial + Sigmoid"
,"Complement"
,"Complement + Isotonic"
,"Complement + Sigmoid"
,"Bernoulli"
,"Bernoulli + Isotonic"
,"Bernoulli + Sigmoid"]
models = [MultinomialNB()
,CalibratedClassifierCV(MultinomialNB(), cv=2, method='isotonic')
,CalibratedClassifierCV(MultinomialNB(), cv=2, method='sigmoid')
,ComplementNB()
,CalibratedClassifierCV(ComplementNB(), cv=2, method='isotonic')
,CalibratedClassifierCV(ComplementNB(), cv=2, method='sigmoid')
,BernoulliNB()
,CalibratedClassifierCV(BernoulliNB(), cv=2, method='isotonic')
,CalibratedClassifierCV(BernoulliNB(), cv=2, method='sigmoid')
]
for name,clf in zip(name,models):
clf.fit(Xtrain_,Ytrain)
y_pred = clf.predict(Xtest_)
proba = clf.predict_proba(Xtest_)
score = clf.score(Xtest_,Ytest)
print(name)
Bscore = []
for i in range(len(np.unique(Ytrain))):
bs = BS(Ytest_1[i],proba[:,i])
Bscore.append(bs)
print("\tBrier uder{}:{:.3f}".format(train.target_names[i],bs))
print("\tAverage Brier:{:.3f}".format(np.mean(Bscore)))
print("\tAccuracy:{:.3f}".format(score))
print("\n")
通过比较,补集贝叶斯使用Sigmoid进行概率校准时的模型综合最优秀。对于机器学习而言,朴素贝叶斯也许不是最常用的方法,但由于它的简单快捷还是占有一席之地。只要能够提供足够的证据,合理利用高维数据进行训练,朴素贝叶斯就可以提供不错的效果。