朴素贝叶斯算法 — 超详细公式讲解+代码实例

article/2025/10/1 3:49:46
  • 本文收录于Github仓库,欢迎前来 star 呀~ https://github.com/Veal98/cs-wiki
  • 在线阅读地址/更好的阅读体验请移步:cswiki.top
    在这里插入图片描述

👔 朴素贝叶斯算法 Naive Bayes


💡 思维导图

1. 朴素贝叶斯法概述

朴素贝叶斯法是基于贝叶斯定理与特征条件独立性假设的分类方法。对于给定的训练集,首先基于特征条件独立假设学习输入输出的联合概率分布(朴素贝叶斯法这种通过学习得到模型的机制,显然属于生成模型);然后基于此模型,对给定的输入 x,利用贝叶斯定理求出后验概率最大的输出 y。

学习朴素贝叶斯算法之前,我们先搞定下面这些基本概念和数学公式 👇

2. 朴素贝叶斯法的基本公式

① 联合概率分布

联合概率表示为包含多个条件并且所有的条件都同时成立的概率,记作 P ( X = a , Y = b ) P(X=a,Y=b) P(X=a,Y=b) P ( a , b ) P(a,b) P(a,b) P ( a b ) P(ab) P(ab)

联合概率分布就是联合概率在样本空间中的分布情况

② 条件概率 conditional probability

有一个装了 7 块石头的罐子,其中 3 块是白色的,4 块是黑色的。如果从罐子中随机取出一块石头,那么是白色石头的可能性是多少?

显然,取出白色石头的概率为 3/7 ,取到黑色石头的概率是 4/7 。我们使用 P(white) 来表示取到白色石头的概率,其概率值可以通过白色石头数目除以总的石头数目来得到。

如果这 7 块石头如下图所示,放在两个桶中,那么上述概率应该如何计算

要计算 P(white) 或者 P(black) ,显然,石头所在桶的信息是会改变结果的,这就是条件概率 conditional probability。假定计算的是从 B 桶取到白色石头的概率,这个概率可以记作 P(white|bucketB) ,我们称之为 “在已知石头出自 B 桶的条件下,取出白色石头的概率”。

很容易得到,P(white|bucketA) 值为 2/4 ,P(white|bucketB) 的值为 1/3 。

条件概率的计算公式如下:

放到我们这个例子中来: P(white|bucketB) = P(white and bucketB) / P(bucketB)

公式解读:

  • P(white|bucketB):在已知石头出自 B 桶的条件下,取出白色石头的概率
  • P(white and bucketB):取出 B 桶中 白色石头的概率 = 1 / 7
  • P(bucketB):取出 B 桶中石头的概率 3 / 7

④ 贝叶斯定理

另外一种有效计算条件概率的方法称为贝叶斯定理。贝叶斯定理告诉我们如何交换条件概率中的条件与结果,即如果已知 P(X|Y),要求 P(Y|X):

⭐⭐⭐ P ( Y ∣ X ) = P ( X ∣ Y ) P ( Y ) P ( X ) P(Y|X) = \frac{P(X|Y) P(Y) } {P(X)} P(YX)=P(X)P(XY)P(Y)

这里的每个概率都有其特定的名称:

  • P ( Y ) P(Y) P(Y)先验概率先验概率(prior probability)是指事情还没有发生,求这件事情发生的可能性的大小,是先验概率。它往往作为"由因求果"问题中的"因"出现。

  • P ( Y ∣ X ) P(Y|X) P(YX)后验概率后验概率是指事情已经发生,求这件事情发生的原因是由某个因素引起的可能性的大小。后验概率的计算要以先验概率为基础

  • P ( X ∣ Y ) P(X|Y) P(XY) :条件概率,又叫似然概率,一般是通过历史数据统计得到。一般不把它叫做先验概率,但从定义上也符合先验定义。

④ 朴素贝叶斯分类器

朴素贝叶斯法通过训练数据集学习联合概率分布 P ( X , Y ) P(X,Y) P(X,Y),其实就是学习先验概率分布和条件概率分布:

  • 先验概率分布:

  • 条件概率分布:

于是由条件概率公式 P ( X ∣ Y ) = P ( X , Y ) P ( Y ) P(X|Y) = \frac{P(X,Y)}{P(Y)} P(XY)=P(Y)P(X,Y) 可以求出联合概率分布 P ( X , Y ) P(X,Y) P(X,Y)

💡 条件独立性假设就是各个特征之间互不影响,每个特征都是条件独立的。这一假设使得朴素贝叶斯法变得简单,但是有时候会牺牲一定的分类准确率。

朴素贝叶斯法分类时,对给定的输入 x,通过上述学习到的模型计算后验概率分布 P ( Y = c k ∣ X = x ) P(Y = c_k|X = x) P(Y=ckX=x)将后验概率最大的类作为 x 的类的输出。后验概率根据贝叶斯定理进行计算:

💡 对分母上的 P ( X = x ) P(X = x) P(X=x) 应用了全概率公式

将条件独立性假设 4.3 带入上式:

这就是朴素贝叶斯分类的基本公式 👆

朴素贝叶斯分类器就是取后验概率最大时的分类:

显然,上式中的分母对于所有类别来说都是一样的,对计算结果不会产生影响,所以,朴素贝叶斯分类器可以简化为:⭐⭐⭐

其实朴素贝叶斯分类器的后验概率最大化等价于0-1损失函数时的期望风险最小化。

3. 朴素贝叶斯算法

朴素贝叶斯算法基于不同的概率估计方法具有不同的形式。概率估计方法有以下两种:

  • 极大似然估计
  • 贝叶斯估计

① 极大似然估计

可以用极大似然估计法去估计相应的概率。

  • 先验概率 P ( Y = c k ) P(Y = c_k) P(Y=ck) 的极大似然估计是:

  • 设第 j 个特征 x ( j ) x^{(j)} x(j) 可能取值的集合为 a j 1 , a j 2 . . . . . . a j S j {a_{j1},a_{j2}......a_{jS_j}} aj1,aj2......ajSj S j S_j Sj 表示第 j 个特征可能取值有 S j S_j Sj 个。比如特征 1 可能取值有 2 个,则 S 1 = 2 S_1 = 2 S1=2),条件概率 P ( X ( j ) = a j l ∣ Y = c k ) P(X^{(j)} = a_{jl} | Y = c_k) P(X(j)=ajlY=ck) 的极大似然估计是:

    其中, x i ( j ) x_i^{(j)} xi(j) 表示第 i 个样本的第 j 个特征; a j l a_{jl} ajl 表示第 j 个特征可能取的第 l l l 个值(比如特征 1 可能取值有 2 个,则 l l l 可以为 1 或 2); I I I 为指示函数

基于极大似然估计法,⭐ 朴素贝叶斯算法如下:

💬 举个例子

② 贝叶斯估计

用极大似然估计可能会出现所要估计的概率为 0 的情况,这会影响到后验概率的计算结果,使分类产生偏差。解决这一问题的方法是采用贝叶斯估计。

  • 条件概率的贝叶斯估计

    其中, λ ≥ 0 λ ≥ 0 λ0。当 λ = 0 λ = 0 λ=0 时就是极大似然估计。常取 λ = 1 λ = 1 λ=1,这时称为拉普拉斯平滑 Laplacian smoothing

  • 先验概率的贝叶斯估计

    K K K 的含义和 S j S_j Sj 相同,即表示分类的个数。

💬 举个例子:数据同上例 4.1,按照拉普拉斯平滑估计概率:

4. 实例:使用朴素贝叶斯算法辨别文档中的侮辱性词汇

该实例来源于《机器学习实战》这本书,撸一遍《统计学习方法》后再看这本书上的算法,真的是豁然开朗 😎

项目概述:使用朴素贝叶斯构建一个快速过滤器来屏蔽侮辱性文档。如果某篇文档使用了负面或者侮辱性的语言,那么就将该文档标识为侮辱性文档。对此问题建立两个类别: 侮辱类和非侮辱类,使用 1 和 0 分别表示。

① 将文本转换成 0-1 序列

目的:我们需要把文档中的每个单词利用 0 和 1 来表示,这样方便我们进行处理

首先手动输入文档数据集的,一个列表代表一篇文档:

② 利用极大似然估计计算条件概率和先验概率

import numpy as np# 先验概率
def trainNB0(trainMatrix, trainCategory):"""Desc:返回每个类别对应的先验概率和条件概率Params:trainMatrix: 训练数据集,即各个文档对应的 0-1 序列trainCategory: 训练数据集的类别,即各个文档对应的分类Return:p0Vect: 去重词汇表中每个单词在侮辱性文档中出现的概率p1Vect:去重词汇表中每个单词在非侮辱性文档中出现的概率"""numTrainDocs = len(trainMatrix) # 文件数numWords = len(trainMatrix[0]) # 单词数# 先验概率 👇pAbusive = sum(trainCategory) / float(numTrainDocs) # 侮辱性文件的出现概率,即 trainCategory 中所有 1 的个数(0 1 相加即得 1 的个数)# 条件概率 👇# (非)侮辱性单词在每个文件中出现的次数列表# 比如说 p0Num = [1,3,12,....] 表示第 2 个文档中出现了 3 次非侮辱词汇p0Num = np.zeros(numWords) # [0,0,0,.....] 非侮辱性单词在每个文件中出现的次数列表p1Num = np.zeros(numWords) # [0,0,0,.....] 侮辱性单词出在每个文件中出现的次数列表# (非)侮辱性单词在(非)侮辱性文档出现的总数p0Denom = 0.0 # 0 非侮辱性词汇在所有非侮辱的文档的出现总数p1Denom = 0.0 # 1 侮辱性词汇在所有侮辱性的文档的出现总数for i in range(numTrainDocs):# 是否是侮辱性文件if trainCategory[i] == 1:# 如果是侮辱性文件,对侮辱性文件的向量进行相加,表示在所有侮辱性文件中,去重词汇表中各个词汇出现的次数p1Num +=  trainMatrix[i]# 对向量中的所有元素进行求和,表示在所有侮辱性文件中,去重词汇表中所有词汇出现的次数之和p1Denom += sum(trainMatrix[i])else:# 如果是非侮辱性文件,对非侮辱性文件的向量进行相加,表示在所有非侮辱性文件中,去重词汇表中各个词汇出现的次数p0Num += trainMatrix[i]# 对向量中的所有元素进行求和,表示在所有非侮辱性文件中去重词汇表中所有词汇出现的次数之和p0Denom += sum(trainMatrix[i])# 在类别 1 即侮辱性文档的条件下,去重词汇表中每个单词出现的概率p1Vect = p1Num / p1Denom# 在类别 0 即非侮辱性文档的条件下,去重词汇表中每个单词出现的概率p0Vect = p0Num / p0Denomreturn pAbusive, p0Vect, p1Vect

🏃‍ 测试代码:

pAbusive, p0Vect, p1Vect = trainNB0(trainMat, classVec)

😒 可以看到,基于极大似然估计的朴素贝叶斯算法的结果差强人意

这是因为在利用基于极大似然估计的朴素贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获得文档属于某个类别的概率,比如计算 P ( X 1 ( 1 ) ∣ Y = 1 ) ∗ P ( X 1 ( 2 ) ∣ Y = 1 ) ∗ P ( X 1 ( 3 ) ∣ Y = 1 ) ∗ . . . . . . P(X^{(1)}_1|Y=1) * P(X^{(2)}_1|Y=1) * P(X^{(3)}_1|Y=1) *...... P(X1(1)Y=1)P(X1(2)Y=1)P(X1(3)Y=1)......如果其中一个概率值为 0,那么最后的乘积也为 0为降低这种影响,接下来我们采用贝叶斯估计对上述算法做一下微小的修改 👇

③ 利用贝叶斯估计优化算法

基于拉普拉斯平滑(λ = 1),在条件概率的计算公式的分子分母上分别加上 λ 和 S j λ S_jλ Sjλ S j S_j Sj 表示分类的个数,此处只有两个分类,所以 S j = 2 S_j = 2 Sj=2

即将条件概率和先验概率的分子初始化为 1,将分母初始化为 2 :

# (非)侮辱性单词在每个文件中出现的次数列表
# 比如说 p0Num = [1,3,12,....] 表示第 2 个文档中出现了 3 次非侮辱词汇
p0Num = np.ones(numWords) # [1,1,1,.....] 非侮辱性单词在每个文件中出现的次数列表
p1Num = np.ones(numWords) # [1,1,1,.....] 侮辱性单词出在每个文件中出现的次数列表# (非)侮辱性单词在(非)侮辱性文档出现的总数
p0Denom = 2.0 # 0 非侮辱性词汇在所有非侮辱的文档的出现总数
p1Denom = 2.0 # 1 侮辱性词汇在所有侮辱性的文档的出现总数

OK,修改好之后我们再来运行一下:

💡 p1Vect 中 第 11 个数值最大,即表示去重词汇表中第 11 个位置的单词即 stupid 是在侮辱性文档中出现概率最大的词:

然而,至此,我们的代码仍然不是完美的,还需要解决一个问题:下溢出问题 👇

④ 解决下溢出问题

🔺 下溢出问题:这是由于太多很小的数相乘造成的。比如计算乘积 P ( X 1 ( 1 ) ∣ Y = 1 ) ∗ P ( X 1 ( 2 ) ∣ Y = 1 ) ∗ P ( X 1 ( 3 ) ∣ Y = 1 ) ∗ . . . . . . P(X^{(1)}_1|Y=1) * P(X^{(2)}_1|Y=1) * P(X^{(3)}_1|Y=1) *...... P(X1(1)Y=1)P(X1(2)Y=1)P(X1(3)Y=1)...... 时,由于大部分因子都非常小,所以程序会下溢出或者得到不正确的答案。(😱 用 Python 尝试相乘许多很小的数,最后四舍五入后会得到 0)。

💡 一种解决办法是对乘积取自然对数。在代数中有 ln(A * B) = ln(A) + ln(B), 于是通过求对数可以避免下溢出或者浮点数舍入导致的错误。同时,采用自然对数进行处理不会有任何损失。

下图给出了函数 F(x)ln(F(x)) 的曲线。可以看出,它们在相同区域内同时增加或者减少,并且在相同点上取到极值。它们的取值虽然不同,但不影响最终结果。

✍ 继续修改代码如下:

p1Vect = np.log(p1Num / p1Denom)
p0Vect = np.log(p0Num / p0Denom)

当然,这样获取到的条件概率就是对数形式,所以在接下来的朴素贝叶斯分类器中我们也要为其做相应的修改。

🏃‍ 测试修改后的代码:

OK,问题解决完毕,接下来就可以来构建完整的朴素贝叶斯分类器了 👇

⑤ 编写朴素贝叶斯分类器

回顾一下朴素贝叶斯分类器:

我们将其改写为对数形式:

✍ 朴素贝叶斯分类器的代码如下:

# 朴素贝叶斯分类器
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):"""Desc:输入某篇文档的0-1序列 vec2Classify,输出该篇所属的类别(侮辱性文档 1,非侮辱性文档 0)Args:vec2Classify: 某篇文档的 0-1 序列p0Vec:在类别 0 即非侮辱性文档的条件下,去重词汇表中每个单词出现的概率(对数形式)p1Vec:在类别 1 即侮辱性文档的条件下,去重词汇表中每个单词出现的概率(对数形式)pClass1: 该篇文档是侮辱性文件的概率(先验概率),注意转换成对数形式Return:类别 1/0"""p1 = sum(vec2Classify * p1Vec) + np.log(pClass1) p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1) if p1 > p0:return 1else:return 0

🏃‍ 测试分类器:

# 测试朴素贝叶斯分类器
def test(testDoc):"""Args:testDoc: 测试文档"""# 1. 加载数据集postingList, classVec = loadDataSet()# 2. 创建去重词汇表vocabList = createVocabList(postingList) # 去重后的词汇表# 3. 创建每篇文档对应的 0-1 序列trainMat = []for doc in postingList:trainMat.append(setOfWords2Vec(vocabList, doc))# 4. 计算条件概率和先验概率pAbusive, p0Vect, p1Vect = trainNB0(trainMat, classVec)# 5. 朴素贝叶斯分类器thisDoc = setOfWords2Vec(vocabList, testDoc) # 将测试文档转换成 0-1 序列print(testDoc, 'classified as: ', classifyNB(thisDoc, p0Vect, p1Vect, pAbusive))

📚 References

  • 《统计学习方法 - 第 2 版》
  • 《Machine Learning in Action》
  • 《机器学习 - 周志华》
  • 黄海广 — 《统计学习方法》的代码实现
  • Github - AiLearning
  • 百度百科 — 先验概率
  • 先验概率,后验概率,似然概率,条件概率,贝叶斯,最大似然

http://chatgpt.dhexx.cn/article/SqQjp4K4.shtml

相关文章

贝叶斯定理

贝叶斯定理 通常,事件A在事件B的条件下的概率,与事件B在事件A的条件下的概率是不一样的;然而,这两者是有确定的关系,贝叶斯法则就是这种关系的陈述。 贝叶斯法则又被称为贝叶斯定理、贝叶斯规则,是指概率统…

dbus 学习

和菜鸟一起学linux之DBUS基础学习记录 D-Bus三层架构 D-Bus是一个为应用程序间通信的消息总线系统, 用于进程之间的通信。它是个3层架构的IPC 系统,包括: 1、函数库libdbus ,用于两个应用程序互相联系和交互消息。 2、一个基于libdbus构造…

ubuntu DBUS 收集

ubuntu DBUS 收集 libdbus-1.so.3.19.11 是dbus-1.12.16.tar.gz 包编译出来的 参考文档: https://www.freedesktop.org/wiki/Software/dbus/ https://www.freedesktop.org/wiki/IntroductionToDBus/ https://dbus.freedesktop.org/doc/dbus-tutorial.html https://docs.gtk.…

Linux DBUS服务器端程序

DBus 服务器端接收方式 DBus 服务器端用来接收signal和method调用。从收集的资料中发现,主要有三种接收方式。 一,采用while循环,监听dbus_connection_read_write()函数。有消息到来时在循环内部进行处理。优点是结构简单,处理方…

Linux -dbus总线

下载编译dbus 下载https://dbus.freedesktop.org/releases/dbus/ dbussrc1.14.0-Linux文档类资源-CSDN下载 dbus-1.14.0.tar.xz xz -d dbus-1.14.0.tar.xz tar xvf dbus-1.14.0.tar2.配置编译 ./configure --prefix/data/opensrc/dbus #--prefix/data/opensrc/dbus 指定输…

DBus通讯

linux下进程间通信的方式主要有Pipe(管道),FIFO(命名管道),信号,共享内存,消息队列,信号灯等,这些方式各有 各得特点,如管道是linux下命令行中常用的,用于父子进程的通信。但是这些通…

Linux DBUS客户端程序

DBUS客户端程序,发送一个信号,信号携带int型数据。信号的object path为"/test/signal/server",interface名为 "test.signal.Type",信号名为"Test"。接收端可以根据这三个属性来判断是否是想接收的信…

四、QtDbus

文章目录 概述一、QtDBus模块Debug备忘单 二、QtDBus类型系统1、QtDBus类型系统简介2、原生类型3、复合类型4、扩展类型系统5、类型系统使用 三、QtDBus常用类1、QDBusMessage2、QDBusConnection3、QDBusInterface4、QDBusReply5、QDBusAbstractAdaptor6、QDBusAbstractInterfa…

Hello Qt——QtDBus快速入门

一、QtDBus简介 QtDBus是一个使用D-Bus协议进行进程间通信的仅在Unix运行的库&#xff0c;是对D-Bus底层API的封装实现。 QtDBus模块提供了使用Qt信号槽机制扩展的接口。要使用QtDBus模块&#xff0c;需要在代码中加入以下代码&#xff1a; #include <QtDBus> 如果使用…

DBUS

DBUS是一种高级的进程间通信机制。DBUS支持进程间一对一和多对多的对等通信&#xff0c;在多对多的通讯时&#xff0c;需要后台进程的角色去分转消息&#xff0c;当一个进程发消息给另外一个进程时&#xff0c;先发消息到后台进程&#xff0c;再通过后台进程将信息转发到目的进…

DBUS是什么 如何使用

DBus提供了一种低延时,低开销,高可用性的进程间通信方式,其以消息作为驱动,采用二进制的协议,实现一对一及多对多的对等通信,避免通信的序列化&#xff08;编码过程&#xff09;过程,提高通信效率.DBus进程通信的核心是提供了一个后台中转守护进程,需要通信的进程首先连接到DBu…

dbus总线通信的原理和使用

1.什么是D-Bus D-Bus是一种高级的进程间通信机制&#xff0c;它由freedesktop.org项目提供&#xff0c;使用GPL许可证发行。D-Bus最主要的用途是在Linux桌面环境为进程提供通信&#xff0c;同时能将Linux桌面环境和Linux内核事件作为消息传递到进程。注册后的进程可通过总线接…

制作maven-archeType

制作maven-archeType 项目背景 解决每次开发新项目&#xff0c;要创建很多目录结构或者从老项目中修改包名&#xff0c;pom等&#xff0c;所以就自己制作一个项目骨架&#xff0c;便于以后新项目目录结构生成。 制作maven-archeType 1.自己开发一个maven-archeType项目&…

[WARNING] No archetype found in remote catalog. Defaulting to internal catalog(已解决)

前言&#xff1a; 遇到问题后&#xff0c;首先&#xff0c;在网络上查找答案。结果告诉我&#xff0c;让我重启IDEA&#xff0c;可是我使用的是CMD命令行&#xff0c;根本没有使用IDEA。或者&#xff0c;告诉我如何操作&#xff0c;却没有解释问题发生的根本原因。于是&#xf…

idea自定义archetype及错误处理

介绍&#xff1a;公司内部会制定自己的规范及包结构。当创建新项目的时候就需要选择骨架&#xff0c;即可生成包结构。本文章简单介绍如何创建&#xff0c;解决遇到的各种问题。 一、创建项目。 idea点击file--->new--->project--->点击左侧的Spring initializr- 图2…

Maven 三种archetype说明合集

Maven 三种archetype说明合集【转载】_maven-archetype-quickstart_太阳神LoveU的博客-CSDN博客 新建Maven project项目时&#xff0c;需要选择archetype。 那么&#xff0c;什么是archetype&#xff1f; archetype的意思就是模板原型的意思&#xff0c;原型是一个Maven项目模…

maven自定义archetype

在开发过程中我们经常会创建一系列结构类似的新项目&#xff0c;这些项目结构和基础配置基本或完全一致&#xff0c;maven就提供了archetype类型来规定新建项目的结构及基础配置&#xff0c;利用archetype就可以快速简单的搭建新项目。 一、创建Maven项目的一般步骤 一般情况下…

自定义Maven Archetype模板工程

文章目录 Maven Archetype介绍什么是Maven Archetype为什么要有模板工程创建模板工程的三种方式 常用的archetypemaven-archetype-quickstartmaven-archetype-webapp 自定义一个Maven模板工程生成模板上传模板到仓库(此步骤可选) 使用模板工程 源码地址&#xff1a;https://git…

如何选择创建Maven的archetype

前言&#xff1a; 在使用IDEA的Maven插件创建我们的maven项目时提供了如图所示的原型&#xff0c;为我们快速创建合适的项目提供了很大的帮助。下面我们将详细介绍各个archetype。 官网对archetype(原型)的介绍&#xff1a; http://maven.apache.org/guides/introduction/in…

Maven model archetype说明

前言 新建一个model&#xff0c;其中有一个选项“Create from archetype”感觉很奇怪&#xff0c;我就来了解一下这些内容&#xff0c;做一下笔记&#xff0c; 什么是Archetype Archetype翻译过来就是&#xff1a;骨架&#xff0c;项目工程骨架。 Archetype是Maven工程的模板…