各类贝叶斯分类器的不同 高斯朴素贝叶斯 多项式朴素贝叶斯 伯努利朴素贝叶斯 Categorical Naive Bayes(类朴素贝叶斯)

转载自:https://www.cnblogs.com/B-Hanan/p/12871863.html

核心思想

贝叶斯决策理论的核心思想,即选择具有最高概率的决策。

背景:假定p1(x,y)表示点(x,y)属于类别1的概率,p2(x,y)表示点(x,y)
属于类别2的概率,那么对于一个新数据点(x,y),可以采用下面的规则来判断它的类别:

  • 若p1(x,y)>p2(x,y),那么类别为1;
  • 若p1(x,y)<p2(x,y),那么类别为2.

理论基础

“属性条件独立性假设”:对于已知类别,假定所有属性相互独立,换言之,假设
每个属性独立地对分类结果发生影响。这也是‘朴素’的来源。
另一层意思是:每个属性同等重要。

基于属性条件独立性假设,贝叶斯公式可以改写为:

 

P(c|x)=P(c)P(x|c)p(x)=p(c)p(x)∏i=1dP(xi|c)P(c|x)=P(c)P(x|c)p(x)=p(c)p(x)∏i=1dP(xi|c)

 

其中d为属性数目,xixi为x在第i个属性上的取值。

由于对所有类别来说P(x)相同,因此基于贝叶斯准则有

 

hNB(x)=argmaxc∈γP(c)∏i=1dP(xi|c)hNB(x)=arg⁡maxc∈γ⁡P(c)∏i=1dP(xi|c)

 

朴素贝叶斯分类器的训练过程就是基于训练集D来估计类先验概率p(c),并为每个属性估计条件概率P(xi|c)P(xi|c).

  • 离散属性:条件概率计算:p(xi|c)=∣∣Dc,xi∣∣|Dc|p(xi|c)=|Dc,xi||Dc|.
    Dc,xiDc,xi表示DcDc中在第ii个属性上取值为xixi的样本组成的集合。

  • 连续属性:考虑概率密度函数,假定p(xi|c)∼N(μc,i,σ2c,i)p(xi|c)∼N(μc,i,σc,i2),其中μc,i,σ2c,iμc,i,σc,i2分别是c类样本在第ii个属性上取值的均值和标准差,则有

 

p(xi|c)=12π−−√σc,iexp(−(xi−μc,i)22σ2c,i)p(xi|c)=12πσc,iexp⁡(−(xi−μc,i)22σc,i2)

 

当某个属性值在训练集中没有与某个类同时出现过,将使得P(xi|c)=0P(xi|c)=0,使得后续的判别出现问题。所以为了避免其它属性携带的信息被训练集中未出现的属性值'抹去',在估计概率值时通常要进行'平滑'。

针对P(x_i|c)计算的不同,朴素贝叶斯分类器出现了不同的变体


1. 自己动手算

以决策树中的'贷款数据表为例',对下列样本进行预测:

Age 	Work 	House 	Loan 	Class
中年 	否 	是 	一般 	?

import pandas as pd
DATA=pd.read_excel(r'F:\Python_processing\Python_Jupyter脚本集\机器学习\loan.xlsx')
#1.首先待预测样本不再已知样本中,年龄是‘中年’
DATA[DATA['Age']=='中年']
#2. 计算P(c):即分别计算class为是和否的概率
 AgeWorkHouseLoanClass
5中年一般
6中年
7中年
8中年非常好
9中年非常好
def getResults(dataframe):
    p_c_dict=dataframe.value_counts()
    p_c=dict([ (c_i,round(c_value/p_c_dict.values.sum(),3)) for c_i,c_value in zip(p_c_dict.index,p_c_dict.values)])
    return p_c 
#特征

columns=[i for i in DATA.columns[:-1]]
data1=DATA[DATA['Class']=='是'][columns]
data2=DATA[DATA['Class']=='否'][columns]
print('class # 是')
for i in columns:
    #划分数据
    temp_data=data1[i]
    #开始统计结果
    print(i,getResults(temp_data))
    
print(''.center(50,"="))
    
print('class # 否')
for i in columns:
    #划分数据
    temp_data=data2[i]
    #开始统计结果
    print(i,getResults(temp_data))

        

输出结果:
class # 是
Age {'老年': 0.444, '中年': 0.333, '青年': 0.222}
Work {'是': 0.556, '否': 0.444}
House {'是': 0.667, '否': 0.333}
Loan {'好': 0.444, '非常好': 0.444, '一般': 0.111}
==================================================
class # 否
Age {'青年': 0.5, '中年': 0.333, '老年': 0.167}
Work {'否': 1.0}
House {'否': 1.0}
Loan {'一般': 0.667, '好': 0.333}

p_c=getResults(DATA['Class'])
p_c

{'是': 0.6, '否': 0.4}

  • class:是

 

p(class=是)∗p(中年|class=是)∗p(Work=否|class=是)∗p(House=是|class=是)∗p(loan=一般|class=是)=0.6∗0.333∗0.444∗0.667∗0.111=0.006567911114400001p(class=是)∗p(中年|class=是)∗p(Work=否|class=是)∗p(House=是|class=是)∗p(loan=一般|class=是)=0.6∗0.333∗0.444∗0.667∗0.111=0.006567911114400001

 

  • class:否

 

p(class=否)∗p(中年|class=否)∗p(Work=否|class=否)∗p(House=是|class=否)∗p(loan=一般|class=否)=0.4∗0.333∗1.0∗0∗0.667=0p(class=否)∗p(中年|class=否)∗p(Work=否|class=否)∗p(House=是|class=否)∗p(loan=一般|class=否)=0.4∗0.333∗1.0∗0∗0.667=0

 

所以预测该person的贷款类型为 “是”.

(该样本是基于person 9修改loan后得到,根据决策树节的分支可知,loan在众多属性特征重要性中属于最后,所以上述预测结果可以接受!!)

关于连续变量的案例,见周志华《机器学习》。


2. 调用Sklearn库

Sklearn.naive_bayes官方帮助文档

高斯朴素贝叶斯

假设p(xi|c)或p(xi|y)p(xi|c)或p(xi|y)服从高斯分布。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB

X,y=load_iris(return_X_y=True)
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.5,random_state=0)
gnb=GaussianNB().fit(X_train,y_train)
y_pred=gnb.predict(X_test)
print("Number of mislabeled points out of a total %d points:%d"
     %(X_test.shape[0],(y_test!=y_pred).sum()))

Number of mislabeled points out of a total 75 points:4

from sklearn.metrics import confusion_matrix

confusion_matrix(y_test,y_pred)

array([[21, 0, 0],
[ 0, 30, 0],
[ 0, 4, 20]], dtype=int64)

多项式朴素贝叶斯

MultinomialNB实现了对多个分布数据的朴素贝叶斯算法,是文本分类中使用的两个经典朴素Bayes变体之一(其中数据通常表示为字向量计数,尽管TF-ID向量在实践中也很好地工作)。

对p(xi|c)或p(xi|y)p(xi|c)或p(xi|y)采用平滑处理:

p(xi|c)=|Dci|+α|Dc|+α∗np(xi|c)=|Dci|+α|Dc|+α∗n

nn表示特征数量;α>=0α>=0;。

from sklearn.naive_bayes import MultinomialNB
import numpy as np
rng = np.random.RandomState(1)
X = rng.randint(5, size=(6, 100))
y = np.array([1, 2, 3, 4, 5, 6])
from sklearn.naive_bayes import MultinomialNB
clf = MultinomialNB()
clf.fit(X, y)
print(clf.predict(X[2:3]))

[3]

补码朴素贝叶斯

补码朴素贝叶斯(ComplementNB,cNB)是标准多项式朴素贝叶斯(MNB)算法的一种自适应算法,特别适用于不平衡的数据集。
具体内容见论文:Tackling the Poor Assumptions of Naive Bayes Text Classifiers

论文提出(多项式)朴素贝叶斯自身的系统错误以及在文本分类上的缺陷:

  • 在有偏数据集上,权重的决策边界偏向样本数较多的类。
  • 朴素贝叶斯对不符合独立性假设的(特征所在的)类影响较大。

多项式朴素贝叶斯
假定有固定的类c∈{1,2,...,m}c∈{1,2,...,m},每一个对应预定的多项式参数集合,类cc对应的参数为:
θc={θc1,θc2,...,θcn}θc={θc1,θc2,...,θcn},其中nn代表词袋大小,
∑iθci=1,θci∑iθci=1,θci表示单词ii在类cc中出现的概率。文本分类中文档的似然函数可以
表示为

p(d|θc)=(∑ifi)!∏ifi∏i(θci)fip(d|θc)=(∑ifi)!∏ifi∏i(θci)fi


fifi表示文档dd中单词ii出现的次数。
多项式朴素贝叶斯分布的目标优化函数为:

 

l(d)=argmaxc[logp(θc)+∑ifilogθci]=argmaxc[bc+∑ifiwci]l(d)=arg⁡maxc⁡[log⁡p(θc)+∑ifilog⁡θci]=arg⁡maxc⁡[bc+∑ifiwci]

 

bcbc是阈值项(中括号里面第一项是个常数),wciwci是单词ii在类cc中的权重。
这些值是决策边界的自然参数。 对于二进制分类,这尤其容易看到,其中通过将正类参数和负类参数之间的差设置为零来定义边界,

 

(b+−b−)+∑ifi(w+i−w−i)=0(b+−b−)+∑ifi(w+i−w−i)=0

 

基于多项式分布于狄利克雷分布共轭,可以估计出参数θciθci,

 

θci\^=Nci+αiNc+αθci\^=Nci+αiNc+α

 

从而可以得到多项式NB的优化条件:

 

lMNB(d)=argmaxc[logp(θc)\^+∑ifilog(Nci+αiNc+α)]lMNB(d)=arg⁡maxc⁡[log⁡p(θc)\^+∑ifilog⁡(Nci+αiNc+α)]

 

α=∑iαi,αiα=∑iαi,αi表示一种先验
为了简单,使用均匀分布作为先验,多项式NB的决策边界转为为对下列式子的估计:

 

wci\^=logθci\^wci\^=log⁡θci\^

 

Complement NB
针对在有偏数据集上,权重的决策边界偏向样本数较多的类的问题。论文
提出了Complement Naive Bayes(CNB),与MNB不同的是,CNB的估计为:

 

θ\~ci\^=N\~ci+αiN\~c+αθ\~ci\^=N\~ci+αiN\~c+α

 

CNB的优化目标为:

 

lCNB(d)=argmaxc[logp(θc)−∑ifiN\~ci+αiN\~c+α]lCNB(d)=arg⁡maxc⁡[log⁡p(θc)−∑ifiN\~ci+αiN\~c+α]

 

N\~cN\~c表示除过cc以外的类出现的次数。

注:
负号表示我们要分配给与complement参数估计值不匹配的c类文档的事实。

这个主要应用在文本分类上,论文提出了具体的处理方案:

伯努利朴素贝叶斯

BernoulliNB实现了根据多元Bernoulli分布分布的数据的朴素贝叶斯训练和分类算法,即可能有多个特征,但每一个特征都被假定为一个二元值(Bernoulli,boole)变量。因此,这个类需要将样本表示为二进制值的特征向量;如果传递任何其他类型的数据,则BernoulliNB实例可以对其输入进行二进制化(取决于binarize参数)。

Bernoulli朴素贝叶斯的决策规则是基于

 

p(xi|y)=p(i|y)xi+(1−p(i|y))(1−xi)p(xi|y)=p(i|y)xi+(1−p(i|y))(1−xi)

 

关于p(i|y)p(i|y)的理解:
它不同于多项式NB的规则,因为它明确地惩罚一个特征i的不出现,它是y类的指示,其中多项变量会简单地忽略一个未发生的特征。

它与多项NB规则不同之处在于它明确地惩罚了一个特征的不出现。这是班级的指标,其中多项式变体会忽略一个未发生的特性。

在文本分类的情况下,可以使用单词出现向量(而不是字数向量)来训练和使用该分类器。BernoulliNB在某些数据集上,特别是那些文档较短的数据集中,性能可能会更好。如果时间允许,最好对这两种模式进行评估。

Categorical Naive Bayes(类朴素贝叶斯)

CategoricalNB对分类分布的数据实施分类朴素贝叶斯算法。 它假定由索引描述的每个特征都有其自己的分类分布。

对于训练集中的每个特征 XX,CategoricalNB估计以类y为条件的X的每个特征i的分类分布。 样本的索引集定义为J=1,...,mJ=1,...,m,mm作为样本数。

给定c类的特征i中t类(属性值)的概率估计为:

p(xi=t|y=c;α)=Ntic+αNc+αnip(xi=t|y=c;α)=Ntic+αNc+αni

Ntic=|{j∈J∣xij=t,yj=c}|Ntic=|{j∈J∣xij=t,yj=c}|是属性值tt出现特征xixi,样本,属于属于'c'的次数;

Nc=|{j∈J∣yj=c}|Nc=|{j∈J∣yj=c}| 属于类c的样本数,nini是可用的特征数。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import CategoricalNB

X,y=load_iris(return_X_y=True)
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.5,random_state=0)
cat=CategoricalNB().fit(X_train,y_train)
y_pred=cat.predict(X_test)
print("Number of mislabeled points out of a total %d points:%d"
     %(X_test.shape[0],(y_test!=y_pred).sum()))

Number of mislabeled points out of a total 75 points:7

#列名
column=DATA.columns
##House后面有空格
DATA.columns=[i.strip() for i in column]
column=DATA.columns
column

Index(['Age', 'Work', 'House', 'Loan', 'Class'], dtype='object')

from sklearn.preprocessing import OrdinalEncoder
ord_encoder=OrdinalEncoder().fit(DATA[column[:-1]])
ord_encoder2=OrdinalEncoder().fit(DATA[['Class']])
ord_encoder.categories_

[array(['中年', '老年', '青年'], dtype=object),
array(['否', '是'], dtype=object),
array(['否', '是'], dtype=object),
array(['一般', '好', '非常好'], dtype=object)]

X=pd.DataFrame(ord_encoder.transform(DATA[column[:-1]]),columns=column[:-1])
y=pd.DataFrame(ord_encoder2.transform(DATA[['Class']]),columns=["Class"])
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.5,random_state=0)
cat2=CategoricalNB().fit(X_train,y_train)
y_pred=cat2.predict(X_test)
y_pred

array([0., 0., 1., 1., 0., 0., 1., 1.])

mat=confusion_matrix(y_test,y_pred)
mat

array([[4, 0],
[0, 4]], dtype=int64)

print("准确率:%3.2f"%(
    (np.eye(2)*mat).sum()/mat.sum()*100))

准确率:100.00

#对上面动手算的结果进行验证
raw_test=['中年','否','是','一般']
test=ord_encoder.transform([raw_test])
cat2.predict(test)

array([1.])

#对上面的预测结果进行还原
a=ord_encoder2.inverse_transform([cat2.predict(test)])
print("该样本%s的class #%s"%(raw_test,a.flatten().tolist()[0]))

该样本['中年', '否', '是', '一般']的class #是

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值