转载自:https://www.cnblogs.com/B-Hanan/p/12871863.html
核心思想
贝叶斯决策理论的核心思想,即选择具有最高概率的决策。
背景:假定p1(x,y)表示点(x,y)属于类别1的概率,p2(x,y)表示点(x,y)
属于类别2的概率,那么对于一个新数据点(x,y),可以采用下面的规则来判断它的类别:
理论基础
“属性条件独立性假设”:对于已知类别,假定所有属性相互独立,换言之,假设
每个属性独立地对分类结果发生影响。这也是‘朴素’的来源。
另一层意思是:每个属性同等重要。
基于属性条件独立性假设,贝叶斯公式可以改写为:
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)=argmaxc∈γ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为是和否的概率
Age | Work | House | Loan | Class | |
---|---|---|---|---|---|
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}
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
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)=argmaxc[logp(θc)+∑ifilogθci]=argmaxc[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)=argmaxc[logp(θ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)=argmaxc[logp(θ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 #是