前言
朴素贝叶斯可以说是贝叶斯派的一个很为经典的算法了。相对容易,因为朴素贝叶斯要求就是最大后验概率,实际上与最小期望代价是等价的,所以本文将从最小期望方差推导。不侧重推导,侧重实现。
数学基础:【概率论与数理统计知识复习-哔哩哔哩】
原理推导
最小期望风险(以离散随机变量为例)
朴素贝叶斯,其中的朴素是英文“Naive”翻译过来,Naive也有天真的意思。因此,也称为天真贝叶斯,为什么要这么叫呢?因为在这个模型中,我们认为随机变量之间是相互独立的。
先看损失函数
L
(
Y
,
f
(
X
)
)
=
{
1
,
Y
≠
f
(
X
)
0
,
Y
=
f
(
X
)
L(Y,f(X))=\left\{ \begin{matrix} 1,Y\ne{f(X)}\\ 0,Y=f(X) \end{matrix} \right.
L(Y,f(X))={1,Y=f(X)0,Y=f(X)
其中
f
(
X
)
=
max
y
P
(
Y
=
y
∣
X
)
f(X)=\max\limits_{y}P(Y=y|X)
f(X)=ymaxP(Y=y∣X)
所以,对于损失函数,其期望为
min
y
E
(
L
(
Y
,
f
(
x
)
)
)
=
min
y
∑
X
∑
Y
L
(
Y
,
f
(
X
)
)
∗
P
(
X
,
Y
)
=
min
y
∑
X
∑
Y
L
(
Y
,
f
(
X
)
)
∗
P
(
Y
∣
X
)
∗
P
(
X
)
=
min
y
∑
X
[
∑
Y
L
(
Y
,
f
(
X
)
)
∗
P
(
Y
∣
X
)
]
∗
P
(
X
)
\begin{equation} \begin{aligned} &\min\limits_{y}E(L(Y,f(x))) \\&=\min\limits_{y}\sum\limits_{X}\sum\limits_{Y}L(Y,f(X))*P(X,Y) \\&=\min\limits_{y}\sum\limits_{X}\sum\limits_{Y}L(Y,f(X))*P(Y|X)*P(X) \\&=\min\limits_{y}\sum\limits_{X}\left[\sum\limits_{Y}L(Y,f(X))*P(Y|X)\right]*P(X) \end{aligned} \end{equation}
yminE(L(Y,f(x)))=yminX∑Y∑L(Y,f(X))∗P(X,Y)=yminX∑Y∑L(Y,f(X))∗P(Y∣X)∗P(X)=yminX∑[Y∑L(Y,f(X))∗P(Y∣X)]∗P(X)
我们希望其期望最小,那么也就是对于每一个 X = x ∗ X=x^* X=x∗,我们希望 ∑ Y L ( Y , f ( X = x ∗ ) ) ∗ P ( Y ∣ X = x ∗ ) \sum\limits_{Y}L(Y,f(X=x^*))*P(Y|X=x^*) Y∑L(Y,f(X=x∗))∗P(Y∣X=x∗)最小
min
y
∑
Y
L
(
Y
,
f
(
X
=
x
∗
)
)
∗
P
(
Y
∣
X
=
x
∗
)
=
min
y
∑
C
k
L
(
C
k
,
f
(
X
=
x
∗
)
)
∗
P
(
C
k
∣
X
=
x
∗
)
\begin{equation} \begin{aligned} &\min\limits_{y}\sum\limits_{Y}L(Y,f(X=x^*))*P(Y|X=x^*) \\&=\min\limits_{y}\sum\limits_{Ck}L(Ck,f(X=x^*))*P(Ck|X=x^*) \end{aligned} \end{equation}
yminY∑L(Y,f(X=x∗))∗P(Y∣X=x∗)=yminCk∑L(Ck,f(X=x∗))∗P(Ck∣X=x∗)
当
C
k
=
f
(
X
=
x
∗
)
Ck=f(X=x^*)
Ck=f(X=x∗),
L
(
C
k
,
f
(
X
=
x
∗
)
)
=
0
L(Ck,f(X=x^*))=0
L(Ck,f(X=x∗))=0。
=
min
y
∑
C
k
L
(
C
k
,
f
(
X
=
x
∗
)
)
∗
P
(
C
k
∣
X
=
x
∗
)
=
min
y
∑
C
k
L
(
C
k
≠
f
(
X
=
x
∗
)
)
∗
P
(
C
k
≠
f
(
X
=
x
∗
)
∣
X
=
x
∗
)
=
min
y
∑
C
k
L
(
C
k
≠
y
)
∗
P
(
C
k
≠
y
)
∣
X
=
x
∗
)
=
min
y
L
(
C
k
≠
y
)
∗
[
1
−
P
(
C
k
=
y
∣
X
=
x
∗
)
]
=
max
y
P
(
y
=
C
k
∣
X
=
x
∗
)
\begin{equation} \begin{aligned} \\&=\min\limits_{y}\sum\limits_{Ck}L(Ck,f(X=x^*))*P(Ck|X=x^*) \\&=\min\limits_{y}\sum\limits_{Ck}L(Ck\ne{f(X=x^*)})*P(Ck\ne{f(X=x^*})|X=x^*) \\&=\min\limits_{y}\sum\limits_{Ck}L(Ck\ne{y})*P(Ck\ne{y})|X=x^*) \\&=\min\limits_{y}L(Ck\ne{y})*[1-P(Ck={y}|X=x^*)] \\&=\max\limits_{y}P(y=Ck|X=x^*) \end{aligned} \end{equation}
=yminCk∑L(Ck,f(X=x∗))∗P(Ck∣X=x∗)=yminCk∑L(Ck=f(X=x∗))∗P(Ck=f(X=x∗)∣X=x∗)=yminCk∑L(Ck=y)∗P(Ck=y)∣X=x∗)=yminL(Ck=y)∗[1−P(Ck=y∣X=x∗)]=ymaxP(y=Ck∣X=x∗)
其中,因为
L
(
C
k
≠
y
)
=
1
L(Ck\ne{y})=1
L(Ck=y)=1,并且取反,从最小值变成最大值。所以最终的结果
max
y
P
(
y
∣
x
)
\max\limits_{y}P(y|x)
ymaxP(y∣x)
即最大后验概率。比如当y可以取0和1时。我们就要计算
P
(
y
=
0
∣
x
)
P(y=0|x)
P(y=0∣x)和
P
(
y
=
1
∣
x
)
P(y=1|x)
P(y=1∣x)的概率,哪一个大就说明属于哪一类。
由贝叶斯定理可知
P
(
y
∣
x
)
=
P
(
x
∣
y
)
P
(
y
)
P
(
x
)
=
P
(
x
∣
y
)
P
(
y
)
∑
i
=
1
k
P
(
x
∣
y
i
)
∗
P
(
y
i
)
P(y|x)=\frac{P(x|y)P(y)}{P(x)}=\frac{P(x|y)P(y)}{\sum\limits_{i=1}^kP(x|y_i)*P(y_i)}
P(y∣x)=P(x)P(x∣y)P(y)=i=1∑kP(x∣yi)∗P(yi)P(x∣y)P(y)
可见,想要计算出
P
(
y
∣
x
)
P(y|x)
P(y∣x),就必须得计算出
P
(
x
∣
y
)
P
(
y
)
P(x|y)P(y)
P(x∣y)P(y),显然,对于我们的x,在实际的数据中,其大多数情况下,多半是高维的。所以
P
(
x
∣
y
)
=
P
(
x
=
x
1
,
x
=
x
2
,
⋯
,
x
=
x
k
∣
y
)
P(x|y)=P(x=x^{1},x=x^{2},\cdots,x=x^{k}|y)
P(x∣y)=P(x=x1,x=x2,⋯,x=xk∣y)
这个是很难计算的,所以,在前面我们就有了一个假设,认为
x
1
,
x
2
,
⋯
,
x
n
x^{1},x^{2},\cdots,x^{n}
x1,x2,⋯,xn之间是相互独立的,所以
P
(
x
∣
y
)
=
∏
i
=
1
k
P
(
x
=
x
i
∣
y
)
P(x|y)=\prod\limits_{i=1}^kP(x=x^i|y)
P(x∣y)=i=1∏kP(x=xi∣y)
而这些
P
(
x
=
x
i
∣
y
)
P(x=x^i|y)
P(x=xi∣y)就是在标签为
y
y
y的情况下,
x
=
x
i
x=x^i
x=xi对应的概率。对于
P
(
y
)
P(y)
P(y)也是如此。
而他们的计算方式就是用满足条件的数量除以总数量(二项\多项式分布)
比如,现在我们有一堆数据
材料(x1) | 制造(x2) | 是否购买y |
---|---|---|
好 | 好 | 是 |
不好 | 好 | 是 |
好 | 不好 | 否 |
所以,对于 P ( y = 购买 ) = 2 3 P(y=购买)=\frac{2}{3} P(y=购买)=32,即一共有三个,其中购买的有两个,所以概率为 2 3 \frac{2}{3} 32
而对于 P ( x 2 = 好 ∣ y = 买 ) P(x2=好|y=买) P(x2=好∣y=买),就可以先在y等于买的类别中,寻找x2为好的个数,即在"y=好"的有两个,在这两个标签为好的类别中,发现"制造=好"有两个,而对于"Y=好"情况下,“制造=好”的总数也是两个,所以最终的概率为1。
连续型变量
那么对于连续型的随机变量,我们又改如何呢?
一般地,我们认为,对于连续型的随机变量,它应当是符合正态分布(当燃这只是我们大多数情况下这么认为,实际上可以根据实际情况而定)
对于连续型随机变量,我们知道,连续型变量在某一点处的概率是为0的,那么怎么办呢?假如我们的数据的x=1,那么我们要计算其概率呢?在概率论中,是不存在计算某一个点的连续型概率的,书上都是计算小于某个点的概率,比如x<1的概率这样
那怎么办呢?对于连续型变量,我们一般用其密度函数代替其概率,但我们知道,密度函数的值是可以大于1的,但是这并不影响,我们看一下正态分布的密度函数
假如我们x=1,从其在密度函数上的x=1处的高度相对较高,说明其出现的概率是相对较高,而对于x=4.5,我们就认为其出现的概率很小。这是可行。所以用某一点处的概率密度值代替概率是相对合理的。
代码实现
为了能够绘画图出来,该代码仅仅针对连续型数据。离散型数据相对来说比较容易,读者可依连续型的类推。
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
class Naive_Bayes():
def __init__(self,x,y):
self.x=x #数据x
self.y=y #标签值y
self.classify,self.couters=np.unique(y,return_counts=True) #获取类别数和相应类别数的数量
self.num=self.y.shape[0] #数据量
def predict(self,x_test):
'''
:param x_test: 测试数据
:return:
'''
result=np.zeros(shape=(x_test.shape[0],self.classify.shape[0])) #用于储存每一个类别的概率值
dim=0
for clas,couter in zip(self.classify,self.couters):#迭代每一个类别
p_yi=couter/self.num #求出p(y_i),即第i个类别的概率
x_i=self.x[self.y.reshape(-1)==clas] #取出属于第i个类别的数据
# 由于此代码使用的都是连续型变量,故此处求出x_i的均值和标准差(为了密度函数)
xi_mean=np.mean(x_i,axis=0)
xi_std=np.std(x_i,axis=0)
#构造密度函数
density_function=stats.norm.pdf(x_test,loc=xi_mean,scale=xi_std)#求出对应x的密度值
density_mul=np.ones((density_function.shape[0],1)) #生成一个全为1的数组(为了做乘法操作)
#对密度函数的每一个维度的值做乘法操作。
for i in range(density_function.shape[1]):
density_mul*=density_function[:,i:i+1]
#最后乘以标签值对应的概率,得到最终的概率
p_yi_xi=density_mul*p_yi
#将概率储存起来
result[:,dim]=p_yi_xi.reshape(-1)
dim+=1
#按列对比概率,哪一个维度大就说明是哪一类
pre_label=np.argmax(result,axis=1)
print("预测结果为:",pre_label)
#绘图
figure_plot(x_test,pre_label)
def figure_plot(x,y):#绘图函数,与模型无关
color_map={0:"r",1:"b"}
color=[color_map[i] for i in y.squeeze()]
plt.scatter(x[:,0],x[:,1],c=color)
plt.savefig("result.png")
plt.show()
if __name__ == '__main__':
x1=stats.norm.rvs(5,1,(100,2)) #生成均值为5,方差为1的数据,维度(100,2)
y1=np.zeros((100,1)) #生成对应的类别标签,记作0
x2=stats.norm.rvs(0,1 ,(100,2)) #生成均值为0,方差为1的数据,维度(100,2)
y2 = np.ones((100, 1)) #生成对应的类别标签,记作1
x=np.concatenate((x1,x2),axis=0) #将数据合并
y=np.concatenate((y1,y2),axis=0) #将标签合并
#数据标准化,可有可无哦,但有更好
x_mean=np.mean(x,axis=0)
x_std=np.std(x,axis=0)
x=(x-x_mean)/x_std
#生成测试数据,与上面的训练数据雷同
x_test1=stats.norm.rvs(5,1,(100,2))
x_test2 = stats.norm.rvs(0, 1, (100, 2))
x_test=np.concatenate((x_test1,x_test2),axis=0)
x_test_mean=np.mean(x_test,axis=0)
x_test_std=np.std(x_test,axis=0)
x_test=(x_test-x_test_mean)/x_test_std
#初始化数据
svm=Naive_Bayes(x,y)
#预测
svm.predict(x_test)
结束
以上便是朴素贝叶斯的原理推导和代码实现了,如有什么问题,还望指出。阿里嘎多