初入机器学习之——朴素贝叶斯分类器NBC及Python代码剖析

2023-05-16

初入机器学习之——朴素贝叶斯分类器NBC

  • NBC模型的理论基础
    • 一、参数释义
    • 二、Training阶段模型所需参数
    • 三、Predict阶段
    • 四、代码剖析
      • training
      • predicting

NBC模型的理论基础

理论基础:贝叶斯公式
P ( C ∣ F )    =    P ( F ∣ C ) × P ( C ) P ( F ) P(C\vert F)\;=\;\frac{P(F\vert C)\times P(C)}{P(F)} P(CF)=P(F)P(FC)×P(C)

一、参数释义

考虑到实际的含义,C为class首字母,即我们需要模型去预测出的类别;F为feature首字母,即我们找到的关于类别的特征值(例如,关于一个人帅或者不帅的class,我们有身高、颜值、学历、身材这四种features),并且利用贝叶斯公式的前提条件是各个F之间 相互独立

二、Training阶段模型所需参数

作为一个机器学习和Python的初学者,我研究了很久才知道training dataset和testing dataset如何作用于上述公式(一开始我直接用training dataset把 P ( C ∣ F )    P(C\vert F)\; P(CF)给求出来了,蛋疼)。
对于 P ( C ∣ F )    P(C\vert F)\; P(CF),我们要做的是用training dataset将 P ( C ∣ F )    P(C\vert F)\; P(CF)的概率分布所需的参数求出来,在这里采用的是正态分布,正态分布的模型有两个:
σ , μ \sigma, \mu σ,μ
分别对应标准差和平均值,因为Python自带方差函数,所以我们可以直接求方差 σ 2 \sigma^2 σ2。还有另外一个概率需要得到: P ( C )    P(C)\; P(C),这个概率相对简单,只需要统计每个class在training dataset中出现的次数除以总的class数就能得到。综上所述,在training阶段,我们所需的参数为 σ 2 , μ , P ( C )    \sigma^2,\mu,P(C)\; σ2μP(C)

三、Predict阶段

根据联合分布概率可知,

P ( F ∣ C ) = P ( F 1 ∣ C ) × P ( F 2 ∣ C ) × P ( F 3 ∣ C ) × ⋯ × P ( F n ∣ C ) =                                                     ∏ 1 n P ( F i ∣ C ) \begin{array}{l}P(F\vert C)=P(F_1\vert C)\times P(F_2\vert C)\times P(F_3\vert C)\times\cdots\times P(F_n\vert C)=\\\;\;\;\;\;\;\;\;\\\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\prod\nolimits_1^nP(F_i\vert C)\end{array} P(FC)=P(F1C)×P(F2C)×P(F3C)××P(FnC)=1nP(FiC)

利用对数的性质,将乘积形式变为求和形式,
log ⁡ [ P ( F ∣ C ) ] = log ⁡ [ P ( F 1 ∣ C ) × P ( F 2 ∣ C ) × P ( F 3 ∣ C ) × ⋯ × P ( F n ∣ C ) ] =                                                                                                               ∑ 1 n log ⁡ [ P ( F i ∣ C ) ] \begin{array}{l}\log\lbrack P(F\vert C)\rbrack=\log\lbrack P(F_1\vert C)\times P(F_2\vert C)\times P(F_3\vert C)\times\cdots\times P(F_n\vert C)\rbrack=\\\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\\\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\sum\nolimits_1^n\log\lbrack P(F_i\vert C)\rbrack\end{array} log[P(FC)]=log[P(F1C)×P(F2C)×P(F3C)××P(FnC)]=1nlog[P(FiC)]

接着 ∑ 1 n log ⁡ [ P ( F i ∣ C ) ] × P ( C ) \begin{array}{lc}\sum\nolimits_1^n\log\lbrack P(F_i\vert C)\rbrack&\times\end{array}P(C) 1nlog[P(FiC)]×P(C)得到我们需要的概率( P ( F ) P(F) P(F)相对于分子是个常数,所以不用求),取最大概率的那个C,就是我们利用NBC分类得到的class。

四、代码剖析

因为刚上手Python,所以有一些代码或许可以用更简洁的方式写,大佬们可以指正。

NBC类总体代码如下:

class NBC:
    def __init__(self, feature_types, num_classes, landa=1 * e ** -6):
        """

        Args:
            feature_types:
            num_classes:
            landa: avoid the scenario of log0, defalt 1e-6
        """
        self.feature_types = feature_types
        self.num_classes = num_classes
        self.landa = landa
        self.avg = None
        self.var = None
        self.prior = None

    def fit(self, Xtrain, ytrain):
        """
        Xtrain is the four features , y is the lable of every row,
        we need to use parameters to get some CONSTANTS(average, variance, prior probability)
        in order to predict test datasets
        Args:
            Xtrain:
            ytrain:

        Returns:

        """
        self.prior = self.get_y_pri(ytrain)
        # the four features average values of the three labels
        self.avg = self.get_x_avg(Xtrain, ytrain)
        # the four features's var values of the three labels
        # var = power(std, 2)
        self.var = self.get_x_var(Xtrain, ytrain)

    def predict_prob(self, Xtest):
        """
        calculate the probability of every row in the test dataset
        in order to choose the closest label of this row
        Args:
            Xtest:

        Returns:
            array
        """
        # apply_along_axis means cut the Xtest into rows in order to calculate easier the likelihood
        likelihood = np.apply_along_axis(self.get_likelihood, axis=1, arr=Xtest)
        return self.prior * likelihood

    def predict(self, Xtest):
        """
        choose the largest probability as the label of row, return the label array
        Args:
            Xtest:

        Returns:
            array
        """
        return np.apply_along_axis(self.get_prediction_label, axis=1, arr=self.predict_prob(Xtest))

    def get_prediction_label(self, prob_row):
        """
        get the corresponding label of the largest probability of each row
        Args:
            prob_row:

        Returns:
            array
        """
        return np.argmax(prob_row)

    def get_count(self, ytrain, c):
        """
        get total number of every label in thetrain dataset
        Args:
            ytrain:
            c: class lable

        Returns:
            int count
        """
        count = 0
        for y in ytrain:
            if y == c:
                count += 1
        return count

    def get_y_pri(self, ytrain):
        """
        get prior probability of all labels
        Args:
            ytrain:

        Returns:
            array
        """
        ytrain_len = len(ytrain)
        res = []
        for y in range(self.num_classes):
            pri_p = self.get_count(ytrain, y) / ytrain_len
            res.append(pri_p)
        return np.array(res)

    def get_x_var(self, Xtrain, ytrain):
        """
        get variance of every feature in the train dataset,
        the result is necessary for predicting test dataset
        Args:
            Xtrain:
            ytrain:

        Returns:
            array
        """
        res = []
        for i in range(self.num_classes):
            res.append(Xtrain[ytrain == i].var(axis=0))
        return np.array(res)

    def get_likelihood(self, label_row):
        """
        get likelihood probability of every row of test dataset

        we add landa parameter manually to avoid the computation result of Gaussian distribution may be zero
        Args:
            label_row:

        Returns:
            array
        """

        # landa parameter is very important
        gauss_dis = (1 / sqrt(2 * pi * self.var) * exp(-1 * (label_row - self.avg) ** 2 / (2 * self.var))) + self.landa
        # log(abc) = loga + logb + loc
        return (log(gauss_dis)).sum(axis=1)

    def get_x_avg(self, Xtrain, ytrain):
        """
        get average of every feature in the train dataset,
        the result is necessary for predicting test dataset
        Args:
            Xtrain:
            ytrain:

        Returns:
            array
        """
        res = []
        for i in range(self.num_classes):
            res.append(Xtrain[ytrain == i].mean(axis=0))
        return np.array(res)

首先是NBC类的构造函数:

def __init__(self, feature_types, num_classes, landa=1 * e ** -6):
        """

        Args:
            feature_types:
            num_classes:
            landa: avoid the scenario of log0, defalt 1e-6
        """
        self.feature_types = feature_types
        self.num_classes = num_classes
        self.landa = landa
        self.avg = None
        self.var = None
        self.prior = None

根据二中总结所需要的参数,avg为 μ \mu μ,var为 σ 2 \sigma^2 σ2,prior为 P ( C ) P(C) P(C),另外有一个额外带有默认值的参数landa,是为了防止 log ⁡ 0 \log0 log0的出现。

training

Training阶段

def fit(self, Xtrain, ytrain):
        """
        Xtrain is the four features , y is the lable of every row,
        we need to use parameters to get some CONSTANTS(average, variance, prior probability)
        in order to predict test datasets
        Args:
            Xtrain:
            ytrain:

        Returns:

        """
        self.prior = self.get_y_pri(ytrain)
        # the four features average values of the three labels
        self.avg = self.get_x_avg(Xtrain, ytrain)
        # the four features's var values of the three labels
        # var = power(std, 2)
        self.var = self.get_x_var(Xtrain, ytrain)

获取先验概率:get_y_pri()方法,参数为training dataset,get_count函数是统计该class下的总数,除以总数即为该class的先验概率

    def get_y_pri(self, ytrain):
        """
        get prior probability of all labels
        Args:
            ytrain:

        Returns:
            array
        """
        ytrain_len = len(ytrain)
        res = []
        for y in range(self.num_classes):
            pri_p = self.get_count(ytrain, y) / ytrain_len
            res.append(pri_p)
        return np.array(res)


    def get_count(self, ytrain, c):
        """
        get total number of every label in thetrain dataset
        Args:
            ytrain:
            c: class lable

        Returns:
            int count
        """
        count = 0
        for y in ytrain:
            if y == c:
                count += 1
        return count

获取平均值 μ \mu μ

    def get_x_avg(self, Xtrain, ytrain):
        """
        get average of every feature in the train dataset,
        the result is necessary for predicting test dataset
        Args:
            Xtrain:
            ytrain:

        Returns:
            array
        """
        res = []
        for i in range(self.num_classes):
            res.append(Xtrain[ytrain == i].mean(axis=0))
        return np.array(res)

获取方差 σ 2 \sigma^2 σ2

    def get_x_var(self, Xtrain, ytrain):
        """
        get variance of every feature in the train dataset,
        the result is necessary for predicting test dataset
        Args:
            Xtrain:
            ytrain:

        Returns:
            array
        """
        res = []
        for i in range(self.num_classes):
            res.append(Xtrain[ytrain == i].var(axis=0))
        return np.array(res)

以上我们完成了对NBC的训练,接下来进行激动人心的预测阶段。

predicting

    def predict(self, Xtest):
        """
        choose the largest probability as the label of row, return the label array
        Args:
            Xtest:

        Returns:
            array
        """
        return np.apply_along_axis(self.get_prediction_label, axis=1, arr=self.predict_prob(Xtest))

    def predict_prob(self, Xtest):
        """
        calculate the probability of every row in the test dataset
        in order to choose the closest label of this row
        Args:
            Xtest:

        Returns:
            array
        """
        # apply_along_axis means cut the Xtest into rows in order to calculate easier the likelihood
        likelihood = np.apply_along_axis(self.get_likelihood, axis=1, arr=Xtest)
        return self.prior * likelihood

predict_prob函数计算 中的 P ( F i ∣ C ) P(F_i\vert C) P(FiC),即先验概率乘以似然度,这里将testing dataset以行单位做了切片,调用get_likelihood函数,似然度get_likelihood函数代码如下

    def get_likelihood(self, label_row):
        """
        get likelihood probability of every row of test dataset

        we add landa parameter manually to avoid the computation result of Gaussian distribution may be zero
        Args:
            label_row:

        Returns:
            array
        """

        # landa parameter is very important
        gauss_dis = (1 / sqrt(2 * pi * self.var) * exp(-1 * (label_row - self.avg) ** 2 / (2 * self.var))) + self.landa
        # log(abc) = loga + logb + loc
        return (log(gauss_dis)).sum(axis=1)

正态分布公式
f ( x ) = 1 2 π σ 2 e ( x − μ ) 2 2 σ 2 f(x)=\frac1{\sqrt{2\pi\sigma^2}}e^\frac{(x-\mu)^2}{2\sigma^2} f(x)=2πσ2 1e2σ2(xμ)2
取对数后求和,return后利用argmax函数取概率值最大的class

    def get_prediction_label(self, prob_row):
        """
        get the corresponding label of the largest probability of each row
        Args:
            prob_row:

        Returns:
            array
        """
        return np.argmax(prob_row)

经过实际数据测试,准确率基本都维持在90%以上。

代码地址:https://github.com/hz920120/python_polyu/blob/master/polyu/NBC.py

有错误欢迎大佬指正!😊

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

初入机器学习之——朴素贝叶斯分类器NBC及Python代码剖析 的相关文章

随机推荐

  • 如何使用HAL库手动修改OSC引脚为PD0/1?

    CubeMX不能直接重映射OSC引脚为PD0 1 xff0c 那么 xff0c 如何使用HAL库手动修改OSC引脚为PD0 1 如下图所示配置即可 xff1a
  • “野火FreeRTOS教程”第7章补充知识点-异常流程

    一 知识点 1 Cortex M3 4在复位后CONTROL寄存器初始值为0 xff0c 也就是说MCU会处于线程模式 具有特权访问权限且使用主栈指针 MSP 2 当进入异常时CM3会自动入栈 xff0c 如下图所示 xff1a 3 当异常
  • mini四旋翼飞行器DIY日志

    一 方案 功能描述 xff1a 具备mini四旋翼飞行器的基本功能 xff0c 可以拓展其他模块实现定高 对航向角yaw的校准 xff0c 将所有io引出并设计出最小系统板子功能 xff0c 将设计I2C总线挂载选择电路便于调试和使用 可以
  • Quartus II 13.1.0.162三件套安装包

    QuartusSetup 13 1 0 162 链接 https pan baidu com s 1B01zWG76kfNcGLA0VmwyMw 提取码 jjdd ModelSimSetup 13 1 0 162 链接 https pan
  • DSP Builder安装时的注意事项

    注意事项1 DSP Builder是以组件的形式安装在altera下面的 xff0c 并且altera要与matlab 32位 xff01 xff01 安装在同一路径下 xff0c 这个路径不要带有中文 xff0c 或者空格字符 xff0c
  • Maven3.6.1下载与配置,超详细

    Maven3 6 1下载与配置 xff0c 超详细Maven3 6 1下载与配置 xff0c 超详细Maven3 6 1下载与配置 xff0c 超详细 Maven下载与配置 1 官网下载对应版本 xff0c 推荐下载免安装版 下载地址 ht
  • 【GIS】GIS矢量空间分析(上)

    0 GIS的基本概念 栅格数据与矢量数据 上图中 xff0c a为图形模拟表示的地理对象 xff0c b为控件对象对应的栅格数据模型表示 xff0c c为对应的矢量数据模型表示 矢量模型的表达源于原型空间实体本身 xff0c 通常以坐标来定
  • ROS简介-从零开始讲解ROS(适合超零基础阅读)

    1 前言 笔者以前是机械专业 xff0c 对于计算机方面的学习是少之又少 xff0c 接触机器人的学习之后 xff0c 比如路径规划 算法等 xff0c 发现很难入门 xff0c 不过慢慢摸爬滚打之后还是有了一些认识 xff0c 俗话说的好
  • C++primer plus第六版课后编程练习答案14.1

    include lt iostream gt include lt string gt using namespace std template lt class T1 class T2 gt class Pair private T1 a
  • 区块链——脱坑truffle

    使用truffle构建一个智能合约 实现输出 helloworld 的功能 网上有很多帖子 但也有很多坑 这里展示我的搭建过程 帮助大家绕过那些麻烦 一 安装web3 solc truffle npm g install solc npm
  • ucosii消息队列使用

    ucosii消息队列简介 ucosii的消息队列源码定义在os q c文件 xff1b 接口全部声明在ucos ii h xff0c 总共有如下接口 xff1a span class token keyword void span span
  • rtthrea-ucosii-freertos三系统学习总结

    三系统基本功能对比 RT thread ucosii freertos 任务调度 抢占式 时间片式 xff08 多级队列位图调度 xff09 抢占式 xff08 纯位图调度 xff09 抢占式 时间片式 xff08 遍历列表调度 xff09
  • VScode的git安装与配置

    git下载与安装 1 在官网下载git的最新版本 2 按照提示一步步安装完成 具体步骤参看以下文章 xff1a 转https blog csdn net qq 40342589 article details 105676715 VScod
  • 将python代码封装成c版本的dll动态链接库

    前言 将python程序打包成DLL文件 xff0c 然后用C 43 43 调用生成的DLL文件 xff0c 这是一种用C 43 43 调用python的方法 xff0c 这一块比较容易遇到坑 网上关于这一块的教程不是很多 xff0c 而且
  • gazebo加载异常或者加载缓慢

    在我们安装完ros的时候会在命令行里运行gazebo命令会打开gazebo一个空白世界 xff0c 往往会卡在如图所示的界面 xff1a 这是模型文件加载缓慢需要很长时间 xff0c 这是在ubuntu16 04下的情况 xff0c 在ub
  • FreeRTOS学习笔记二【源码文件介绍及命名规范】

    FreeRTOS学习笔记二 源码文件介绍及命名规范 源码文件介绍源码中的命名规范两个重要数据类型变量名函数名宏名 参考 本文介绍源码中的命名规范 xff0c 下篇开始介绍FreeRTOS中的任务管理 源码文件介绍 Free RTOS源码中包
  • FreeRTOS学习笔记八【队列-下】

    FreeRTOS学习笔记八 队列 下 队列中传输大数据 一个包 或大小可变的数据传输大数据传输不同类型和长度的数据 从多个队列中获取数据队列集合xQueueCreateSet xQueueAddToSet xQueueSelectFromS
  • 软件mongodbmanager.exe 在打开数据库Collection时报错

    The GuidRepresentation for the reader is CSharpLegacy which requires the binary sub type to be UuidLegacy not UuidStanda
  • CMakeList.txt使用指南

    cmake minimum required 设置所需的最低cmake版本 cmake minimum required VERSION major minor patch tweak FATAL ERROR execute process
  • 初入机器学习之——朴素贝叶斯分类器NBC及Python代码剖析

    初入机器学习之 朴素贝叶斯分类器NBC NBC模型的理论基础一 参数释义二 Training阶段模型所需参数三 Predict阶段四 代码剖析trainingpredicting NBC模型的理论基础 理论基础 xff1a 贝叶斯公式 P