朴素贝叶斯原理+Python代码实现

前言

​ 朴素贝叶斯可以说是贝叶斯派的一个很为经典的算法了。相对容易,因为朴素贝叶斯要求就是最大后验概率,实际上与最小期望代价是等价的,所以本文将从最小期望方差推导。不侧重推导,侧重实现。
数学基础:【概率论与数理统计知识复习-哔哩哔哩】

原理推导

最小期望风险(以离散随机变量为例)

​ 朴素贝叶斯,其中的朴素是英文“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=yX)
​ 所以,对于损失函数,其期望为
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)))=yminXYL(Y,f(X))P(X,Y)=yminXYL(Y,f(X))P(YX)P(X)=yminX[YL(Y,f(X))P(YX)]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^*) YL(Y,f(X=x))P(YX=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} yminYL(Y,f(X=x))P(YX=x)=yminCkL(Ck,f(X=x))P(CkX=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} =yminCkL(Ck,f(X=x))P(CkX=x)=yminCkL(Ck=f(X=x))P(Ck=f(X=x)X=x)=yminCkL(Ck=y)P(Ck=y)X=x)=yminL(Ck=y)[1P(Ck=yX=x)]=ymaxP(y=CkX=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(yx)
​ 即最大后验概率。比如当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(yx)=P(x)P(xy)P(y)=i=1kP(xyi)P(yi)P(xy)P(y)
​ 可见,想要计算出 P ( y ∣ x ) P(y|x) P(yx),就必须得计算出 P ( x ∣ y ) P ( y ) P(x|y)P(y) P(xy)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(xy)=P(x=x1,x=x2,,x=xky)
​ 这个是很难计算的,所以,在前面我们就有了一个假设,认为 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(xy)=i=1kP(x=xiy)
​ 而这些 P ( x = x i ∣ y ) P(x=x^i|y) P(x=xiy)就是在标签为 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)

结束

​ 以上便是朴素贝叶斯的原理推导和代码实现了,如有什么问题,还望指出。阿里嘎多

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值