假设你正在查看邮箱,突然收到一封标题为"紧急!账户验证通知"的邮件。你的大脑瞬间开始快速计算:这个标题包含敏感词的概率有多大?发件人地址是否可疑?这些特征共同作用下,判断它是垃圾邮件的概率是多少?这就是朴素贝叶斯算法的核心思想。

目录

一、从生活直觉到数学公式:贝叶斯法则的智慧

1.1 贝叶斯定理:概率世界的黄金法则

1.2 朴素之处:特征条件的独立性假设

二、理论基础

2.1 贝叶斯定理

2.2 朴素假设

2.3 常见变种

三、算法流程

3.1 训练阶段

3.2 预测阶段

四、实战演练:手写数字识别

4.1 数据准备与可视化

4.2 模型训练与评估 

4.3 核心代码解析

五、总结


一、从生活直觉到数学公式:贝叶斯法则的智慧

1.1 贝叶斯定理:概率世界的黄金法则

我们先来看一个经典案例:某种疾病的发病率为0.1%,检测准确率为99%。当某人检测结果为阳性时,实际患病的概率是多少?会很高吗?

根据贝叶斯定理:

P(患病|阳性) = (P(阳性|患病)*P(患病)) / P(阳性)
            = (0.99*0.001) / (0.99*0.001 + 0.01*0.999)
            ≈ 9%

 这个反直觉的结果展示了贝叶斯定理的强大:它通过整合先验知识和新证据来修正概率判断。

1.2 朴素之处:特征条件的独立性假设

朴素贝叶斯算法基于贝叶斯定理,通过计算各类别的后验概率,选择具有最大后验概率的类别作为预测结果。其“朴素”之处在于假设各特征之间是条件独立的,即在已知类别的条件下,特征之间相互独立。尽管这一假设在实际问题中往往不成立,但朴素贝叶斯算法在很多场景下依然表现良好,尤其在文本分类、垃圾邮件检测等领域有着广泛应用。

二、理论基础

2.1 贝叶斯定理

贝叶斯定理公式如下:

P(Y|X) = \frac{P(X|Y)P(Y)}{P(X)}

其中:

  • P(Y|X):即后验概率,即在给定特征 X 后,类别为 Y 的概率;

  • P(X|Y):似然函数,即在类别 Y 下,观测到特征 X 的概率;

  • P(Y):先验概率,即类别 Y 出现的概率;

  • P(X):观测到特征 X 的概率(对所有类别来说是常数)。

2.2 朴素假设

朴素贝叶斯的核心假设是特征条件独立,即:

P(X|Y) = \prod_{i=1}^{n}P(x_i|Y)

这使得计算大规模特征时大大简化,不必考虑各特征之间的复杂联合分布。

2.3 常见变种

根据特征分布的不同,朴素贝叶斯主要有以下几种变体:

  • 高斯朴素贝叶斯:假设特征服从高斯分布,常用于连续型数据;

例如鸢尾花数据集

from sklearn.datasets import load_iris
iris = load_iris()
X, y = iris.data, iris.target

条件概率计算 

P(x_i \mid y) = \frac{1}{\sqrt{2\pi \sigma_y^2}} \exp\left( -\frac{(x_i - \mu_y)^2}{2\sigma_y^2} \right) 

  • 多项式朴素贝叶斯:适用于离散的计数特征,例如文本中的词频;

from sklearn.feature_extraction.text import CountVectorizer
docs = ["优惠 特价 促销", "会议 报告 总结"]
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(docs)
  • 伯努利朴素贝叶斯:适用于二值特征,判断某个词是否出现等场景。

from sklearn.preprocessing import Binarizer
binarizer = Binarizer(threshold=0.5)
X_binary = binarizer.fit_transform(X)

三、算法流程

3.1 训练阶段

计算各类别的先验概率 P(Y)。

对于每个类别,估计特征的条件概率 P(x_i|Y)(根据不同的分布假设,估计方式不同)。

3.2 预测阶段

给定一个新的样本 X,计算每个类别的后验概率:

P(Y|X) \propto P(Y) \prod_{i=1}^{n}P(x_i|Y)

选择后验概率最大的类别作为预测结果。

四、实战演练:手写数字识别

4.1 数据准备与可视化

from sklearn.datasets import load_digits#导入手写数字数据集,包含1797个手写数字图片
import matplotlib.pyplot as plt#绘图函数

digits = load_digits()#加载数字数据集 这里image被展平为一维数组(原本是二维)
plt.figure(figsize=(10,4))#创建绘图窗口,宽高单位 英寸
for index, (image, label) in enumerate(zip(digits.data[:5], digits.target[:5])):
    #zip样本与标签配对,enumerate 每一个对象加上索引
    
    plt.subplot(1,5,index+1)#构建子图网格,窗口分为1行5列,当前是第 index+1 个图像
    plt.imshow(image.reshape(8,8), cmap=plt.cm.gray_r)#显示图像,将1维数组变回二维8×8数组,cmap灰度反转
    plt.title(f'Label: {label}')#加上标签
plt.tight_layout()#自动调整子图布局

 

为了方便理解,这里再补充一个点

上面代码第三行 load_digits() 函数,将返回的数据集对象赋值给变量 digits。这个数据集对象包含多个属性,其中常用的有:

  • digits.data:一个二维数组,形状为 (n_samples, n_features),其中 n_samples 是样本数量(这里是 1797),n_features 是特征数量(这里是 8x8 = 64,因为每个图像被展平为一个一维向量)。每一行代表一个手写数字图像的特征向量。
  • digits.target:一个一维数组,包含每个样本对应的真实标签(0 - 9 的数字)。

4.2 模型训练与评估 

from sklearn.naive_bayes import GaussianNB#从sklearn朴素贝叶斯模块导入高斯朴素贝叶斯分类器
from sklearn.model_selection import train_test_split#用于将数据集划分为训练集和测试集,方便评估模型泛化能力。
from sklearn.metrics import confusion_matrix#计算混淆矩阵,用于直观展示分类模型的预测结果(真实标签与预测标签的匹配情况)。
import seaborn as sns#导入 Seaborn 库,用于更美观的可视化(这里用于绘制混淆矩阵热图)

X_train, X_test, y_train, y_test = train_test_split(
    digits.data, digits.target, test_size=0.3)#30%数据作为测试集
#digits.data 手写数字数据集的特征(图像像素展平后的向量)。
#digits.target 手写数字数据集的真实标签(0-9 的数字)

model = GaussianNB()#创建高斯朴素贝叶斯分类器
model.fit(X_train, y_train)#用训练数据及标签进行模型训练

# 可视化混淆矩阵
plt.figure(figsize=(10,8))#创建绘图窗口
sns.heatmap(confusion_matrix(y_test, model.predict(X_test)), 
            annot=True, fmt='d', cmap='Blues')
plt.xlabel('Predicted')
plt.ylabel('True')

同样这里再解释一下倒数第三行代码(其余直接看注释)

confusion_matrix(y_test, model.predict(X_test)):计算测试集的混淆矩阵。model.predict(X_test) 用训练好的模型预测测试集特征,得到预测标签,再与真实标签 y_test 对比。(即用模型预测出的标签与真实标签对比)

sns.heatmap(...):用 Seaborn 的热图展示混淆矩阵:

  • annot=True:在每个格子中显示具体数值。
  • fmt='d':数值显示为整数。
  • cmap='Blues':使用蓝色系颜色映射,颜色深浅表示数值大小(如深蓝色代表数值大)。

 上面的图像中:

对角线元素表示预测正确的样本数,比如真实标签为 0 ,且预测为 0 的有 56 个

非对角线元素则表示预测错误的样本数

颜色越深,表示数值越大,颜色浅表示数值小

通过混淆矩阵,可直观分析模型在哪些数字上表现好(如 0、1、4 等对角线数值高的类别),以及哪些数字容易被误判(如非对角线数值高的组合),进而指导模型优化(如调整参数、增加特定类别样本等)。

4.3 核心代码解析

高斯朴树贝叶斯分类器代码如下 

class GaussianNB:
    def fit(self, X, y):
        self.classes = np.unique(y)  # 获取数据中的所有类别
        self.means = {}  # 存储每个类别下特征的均值
        self.vars = {}   # 存储每个类别下特征的方差
        self.priors = {} # 存储每个类别的先验概率

        for c in self.classes:
            X_c = X[y == c]  # 筛选出类别为 c 的所有样本特征
            self.means[c] = X_c.mean(axis=0)  # 计算类别 c 中每个特征的均值
            self.vars[c] = X_c.var(axis=0)    # 计算类别 c 中每个特征的方差
            self.priors[c] = X_c.shape[0] / X.shape[0]  # 计算类别 c 的先验概率(样本数占比)
    def predict(self, X):
        posteriors = []  # 存储每个类别对输入样本的后验概率(对数形式)
        for c in self.classes:
            # 计算先验概率的对数
            prior = np.log(self.priors[c])  
            # 计算高斯分布似然概率的对数(拆分公式便于计算)
            likelihood = -0.5 * np.sum(np.log(2 * np.pi * self.vars[c]))  # 固定项
            likelihood -= 0.5 * np.sum(((X - self.means[c])**2) / self.vars[c], axis=1)  # 指数项
            posteriors.append(prior + likelihood)  # 后验概率 = 先验对数 + 似然对数
        # 返回后验概率最大的类别
        return self.classes[np.argmax(posteriors, axis=0)]  

五、总结

朴素贝叶斯算法虽然依赖于特征独立性的假设,但其实现简单、速度快、效果良好,使其在实际应用中十分常见。本文从贝叶斯定理出发,阐述了朴素贝叶斯算法的基本理论和假设,并通过详细的Python案例实战,帮助大家理解如何在真实问题中应用该算法。

希望这篇博客文章能让你对朴素贝叶斯算法有更深入的认识,并在后续的机器学习实践中游刃有余。如果你有任何问题或改进建议,欢迎在评论区留言讨论!

如果这篇文章对你有所启发,期待你的点赞关注!

Logo

脑启社区是一个专注类脑智能领域的开发者社区。欢迎加入社区,共建类脑智能生态。社区为开发者提供了丰富的开源类脑工具软件、类脑算法模型及数据集、类脑知识库、类脑技术培训课程以及类脑应用案例等资源。

更多推荐