机器学习数学推导(九):朴素贝叶斯

从贝叶斯定理与条件独立假设出发,完整推导朴素贝叶斯分类器:参数估计、拉普拉斯平滑、三种模型变体,以及为什么这个看似过于简单的模型在实践中如此有效。

引子: 一个垃圾邮件过滤器,训练只需几毫秒,支持百万级特征,几乎不需要调整超参数,却能在短文本任务上胜过许多更复杂的模型。朴素贝叶斯能做到这一点,靠的是一个大胆到近乎离谱的假设:给定类别后,所有特征条件独立。它不仅不为此道歉,反而坚持到底;尽管这个假设在几乎所有真实数据集上都不成立,分类器依然表现良好。要搞清楚原因,需要深入理解生成模型、MAP 估计、Dirichlet 先验及偏差–方差权衡的核心概念。这篇文章将带你一步步走完这条完整路径。

机器学习数学推导(九):朴素贝叶斯 — 章节概览图


你将学到什么#

  • 贝叶斯定理是概率分类的核心,每个分类器实际上都在暗中模仿贝叶斯最优规则。
  • 条件独立假设的代价是什么?它在几何上损失了什么,在统计上又带来了什么?
  • 如何用极大似然估计计算先验和似然,以及拉普拉斯平滑背后的 MAP/Dirichlet 思路。
  • 三种常用变体:多项式、伯努利、高斯,以及如何选择合适的模型。
  • 为什么朴素贝叶斯在假设被破坏时依然有效:Domingos–Pazzani 结果、误差抵消机制及偏差–方差权衡的作用。
  • 仅使用 NumPy 实现这三种变体,并与 scikit-learn 的结果进行验证。

前置知识#

  • 概率论:掌握贝叶斯定理、条件概率、联合分布与边缘分布,了解高斯密度。
  • 微积分:熟悉对数运算和偏导数计算。
  • 读过 第 8 篇:支持向量机 ,尤其是分类问题的判别式视角。

贝叶斯决策理论#

在引入“朴素”这个概念之前,需要先搞清楚一个最优概率分类器到底是什么样子。朴素贝叶斯只是实现它的一种具体方法。

贝叶斯定理:信念更新的数学表达#

$$P(c_k \mid \mathbf{x}) \;=\; \frac{P(\mathbf{x} \mid c_k)\, P(c_k)}{P(\mathbf{x})}.$$

每一项都有明确的作用:

符号名称含义
$P(c_k \mid \mathbf{x})$后验概率看到数据后,类别是 $c_k$ 的可能性有多大?
$P(\mathbf{x} \mid c_k)$似然如果类别是 $c_k$ ,观察到 $\mathbf{x}$ 是否合理?
$P(c_k)$先验在没有任何特征信息时,类别 $c_k$ 出现的概率是多少?
$P(\mathbf{x})$证据特征 $\mathbf{x}$ 的总体概率,纯粹用来归一化。

为什么先验重要? 假设一种疾病的检测准确率为 99%,但实际患病率只有 0.1%。即使检测结果为阳性,后验概率也只会从 0.001 提升到大约 0.09——仍然是十比一倾向于未患病。贝叶斯定理把先验的影响明明白白地展现出来;忽略先验是统计学中最常见的错误之一。

贝叶斯最优分类器#

$$ \hat{y}(\mathbf{x}) \;=\; \arg\max_{c_k} P(c_k \mid \mathbf{x}) \;=\; \arg\max_{c_k} P(\mathbf{x} \mid c_k)\, P(c_k), $$ $$R^\star(\mathbf{x}) \;=\; 1 - \max_k P(c_k \mid \mathbf{x}),$$

称为贝叶斯风险,其期望值 $\mathbb{E}_{\mathbf{x}}[R^\star(\mathbf{x})]$贝叶斯错误率——这是问题本身的不可约噪声下限。

后续要讨论的所有概率分类器,本质上都是在有限样本条件下对这条规则的某种近似。

生成模型 vs 判别模型#

逼近 $P(c_k \mid \mathbf{x})$ 有两种思路:

  • 判别模型(如逻辑回归、SVM、神经网络)直接学习 $P(y \mid \mathbf{x})$ ,把所有统计能力集中在决策边界上,不关心特征如何分布。
  • 生成模型(如朴素贝叶斯、LDA、HMM)建模联合分布 $P(\mathbf{x}, y) = P(\mathbf{x} \mid y)P(y)$ ,再通过贝叶斯定理推导出后验概率。
维度判别模型生成模型
学习目标$P(y \mid \mathbf{x})$$P(\mathbf{x}, y)$
渐近精度通常更高通常更低
样本效率较低假设成立时更高
处理缺失值自然,直接边缘化即可
生成新样本不行可以
利用无标签数据容易

Ng 和 Jordan(2001)的经典研究清晰地揭示了这种权衡:当数据量趋于无穷时,判别模型表现更好,但生成模型收敛速度更快。朴素贝叶斯则是生成模型路线的一个极端例子。


朴素贝叶斯分类器#

为什么需要大幅简化#

直接估计 $\mathbf{x} \in \{0,1\}^d$$P(\mathbf{x} \mid c_k)$ ,每个类别需要 $2^d - 1$ 个自由参数。如果词汇表大小 $d = 10{,}000$ ,这完全不现实。联合分布是最大的瓶颈。

条件独立假设#

$$P(\mathbf{x} \mid c_k) \;=\; \prod_{j=1}^{d} P\!\left(x^{(j)} \mid c_k\right).$$

可以从两个角度理解这个假设:

  1. 因果视角
    把类别看作隐藏的原因,每个特征是独立产生的结果。比如,一旦确诊为流感,发烧和咳嗽之间就不再有额外的信息关联。

  2. 统计视角
    每个特征只贡献一个一维条件密度,联合密度就是这些密度的乘积。参数数量从随 $d$ 指数增长降到了线性增长

这一假设的几何代价如下图所示:左图是真实的联合密度(相关、倾斜的等高线),右图是朴素贝叶斯的近似,两者的边缘分布相同,但联合结构被强行分解成了与坐标轴对齐的椭圆。

独立假设:边缘相同,联合不同

两种密度可能差异很大,但——正如 §5 会看到的——分类结果往往相差不大。

分类规则#

$$\hat{y}(\mathbf{x}) \;=\; \arg\max_{c_k}\; P(c_k) \prod_{j=1}^{d} P\!\left(x^{(j)} \mid c_k\right).$$ $$\boxed{\;\hat{y}(\mathbf{x}) \;=\; \arg\max_{c_k} \left[\, \ln P(c_k) \;+\; \sum_{j=1}^{d} \ln P\!\left(x^{(j)} \mid c_k\right) \right].\;}$$

这就是整个算法的核心。后面提到的“三种变体”、平滑、校准,其实都是在讨论如何估计单个 $P(x^{(j)} \mid c_k)$

下面是一个 2D 玩具问题的例子,包含两个高斯类:

高斯类条件分布与决策边界

每个类对应一个对角协方差的高斯分布(即朴素贝叶斯在连续特征下的假设类)。决策边界是两类后验相等的点集——一般是二次曲线,当两类共享协方差时退化为直线。

概率视角看,这张图变成了后验曲面:

后验热图与一维切片

右图展示了“软过渡”:沿一条切线,后验 $P(c_1 \mid \mathbf{x})$$0$ 平滑上升到 $1$ ,在两条缩放后的似然曲线相交处穿过 $0.5$ 。那个交点就是决策边界。

极大似然参数估计#

给定训练集 $\mathcal{D} = \{(\mathbf{x}_i, y_i)\}_{i=1}^{N}$ ,其中类 $c_k$ 包含 $N_k$ 个样本:

$$\hat{P}(c_k) \;=\; \frac{N_k}{N}.$$ $$ \hat{P}\!\left(x^{(j)} = v \mid c_k\right) \;=\; \frac{\#\{i : x_i^{(j)} = v,\, y_i = c_k\}}{N_k}. $$ $$P\!\left(x^{(j)} \mid c_k\right) \;=\; \frac{1}{\sqrt{2\pi}\,\sigma_{jk}} \exp\!\left(-\frac{(x^{(j)} - \mu_{jk})^2}{2\sigma_{jk}^2}\right),$$ $$ \hat{\mu}_{jk} \;=\; \frac{1}{N_k}\!\sum_{i:\, y_i=c_k}\! x_i^{(j)}, \qquad \hat{\sigma}_{jk}^2 \;=\; \frac{1}{N_k}\!\sum_{i:\, y_i=c_k}\! \bigl(x_i^{(j)} - \hat{\mu}_{jk}\bigr)^2. $$

这就是全部训练内容。没有迭代优化,没有学习率,也没有收敛检查。

拉普拉斯平滑——以及它的贝叶斯本质#

零计数的灾难
假设词 excellent 在垃圾邮件训练集中从未出现,那么 $\hat{P}(\text{excellent} \mid \text{spam}) = 0$ 。一旦未来某封邮件中出现了 excellent,就会让 $P(\text{spam} \mid \mathbf{x}) = 0$ ,无论其他 199 个词多么像垃圾邮件。单个词就能毁掉整个分类。

$$ \hat{P}\!\left(x^{(j)} = v \mid c_k\right) \;=\; \frac{\#\{i : x_i^{(j)} = v,\, y_i=c_k\} + \alpha}{N_k + \alpha\, S_j}, \qquad \hat{P}(c_k) \;=\; \frac{N_k + \alpha}{N + \alpha K}. $$

$\alpha = 1$ 时称为拉普拉斯(加一)平滑;更小的 $\alpha$ 有时叫 Lidstone 平滑。

为什么有效
给多项分布 $P(\cdot \mid c_k)$ 套上对称 Dirichlet 先验 $\mathrm{Dir}(\alpha, \dots, \alpha)$ 。Dirichlet 是多项分布的共轭先验,所以后验仍是 Dirichlet,参数变为 $\alpha + \text{counts}$ 。该后验的众数(MAP 估计)正好就是上面的公式。拉普拉斯平滑等价于在均匀 Dirichlet 先验下的 MAP 估计——相当于在看到任何数据之前,每一类已经被“虚拟观察”了 $\alpha$ 次。

可视化如下:

拉普拉斯平滑:消除零概率与向均匀先验收缩

  • 左图:$\alpha$ 增大时,常见词把概率质量让给罕见词和未见词。
  • 右图:每个词的估计被向 $1/V$ 拉拢。常见词被压低,未见词从 $0$ 抬起来。这种“拉力”的强度与 $\alpha / N_k$ 成正比。

$\alpha$ 的选择是一根偏差–方差旋钮:$\alpha$ 小更相信数据(偏差小、方差大),$\alpha$ 大更相信均匀先验(偏差大、方差小)。用交叉验证选。


三种变体——同一个贝叶斯规则,不同的似然#

机器学习数学推导(九):朴素贝叶斯 — 章节小结图

分类规则始终不变,变化的只是 $P(x^{(j)} \mid c_k)$ 的建模方式。

三种朴素贝叶斯变体的对比

多项式朴素贝叶斯——适合词频场景#

适用于非负整数计数特征,比如词频、$n$ -gram 或哈希桶。

$$P(\mathbf{x} \mid c_k) \;\propto\; \prod_{j=1}^{d} \theta_{jk}^{x^{(j)}}.$$ $$\hat{\theta}_{jk} \;=\; \frac{\sum_{i:\, y_i=c_k} x_i^{(j)} + \alpha}{\sum_{j'=1}^{d}\sum_{i:\, y_i=c_k} x_i^{(j')} + \alpha d}.$$

简单来说,$\hat{\theta}_{jk}$ 就是类别 $c_k$ 中所有词 token 中恰好是词 $j$ 的比例。

伯努利朴素贝叶斯——适合词的有无场景#

适用于二值特征(出现为 1,未出现为 0),尤其适合短文本。

$$P(\mathbf{x} \mid c_k) \;=\; \prod_{j=1}^{d} p_{jk}^{x^{(j)}} (1 - p_{jk})^{1 - x^{(j)}}.$$

与多项式 NB 的关键区别: 伯努利显式地将每个未出现词的 $(1 - p_{jk})$ 纳入计算,缺席本身也是证据。例如,如果某封邮件中没有出现 “free”,而 “free” 在 85% 的垃圾邮件中通常出现,那么这次缺席就是反对垃圾邮件的有力证据。而多项式 NB 则会直接忽略未出现的词。

经验法则: 短而稀疏的文档(如推文、日志、短查询)通常更适合用伯努利;长文档(如新闻、评论)则多项式更优,因为词频本身携带了重要信息。

高斯朴素贝叶斯——适合连续特征场景#

适用于实数值特征,且每类大致单峰分布,比如物理量、嵌入向量或传感器数据。

$$P(x^{(j)} \mid c_k) \;=\; \mathcal{N}\!\left(x^{(j)};\, \mu_{jk},\, \sigma_{jk}^2\right).$$

类条件密度是 $d$ 个一元高斯分布的乘积,等价于一个对角协方差的多元高斯分布。这正是图 1 中那些与坐标轴对齐的椭圆所表达的内容。

一个有趣的事实: 当两类的逐特征方差相同时(即 $\sigma_{jk}^2 = \sigma_j^2$$k$ 无关),对数后验比是 $\mathbf{x}$ 的线性函数,此时高斯 NB 的决策边界与逻辑回归完全一致——只不过参数是通过生成式最大似然估计得到的,而非判别式拟合。

实战:垃圾邮件分类#

贝叶斯定理、条件独立性和拉普拉斯平滑在朴素贝叶斯的经典应用——垃圾邮件过滤中完美结合。整个流程如下:

从词袋到逐类词概率

  1. 分词:把文档拆分成单词。
  2. 构建词频矩阵:矩阵形状是 $(N \times d)$ ,行表示文档,列表示词汇表。
  3. 估计参数:根据类别频率计算 $\hat{P}(c_k)$ ,用拉普拉斯平滑处理词计数,得到 $\hat{\theta}_{jk}$ (多项式分布)或 $\hat{p}_{jk}$ (伯努利分布)。
  4. 预测:对每个类别计算对数得分,取最大值对应的类别。

右图展示了每种类别的词分布:垃圾邮件的概率集中在 “free”、“money”、“win” 等词上,而正常邮件则集中在 “meeting”、“schedule”、“project” 等词上。测试邮件的分类结果就是把这些特征的证据加起来:

逐特征对数几率与瀑布图:得到最终决策

从左往右看这张瀑布图:先从对数先验比 $\ln \frac{P(\mathrm{spam})}{P(\mathrm{ham})}$ 开始,然后依次加上每个词的贡献。正条表示支持垃圾邮件,负条表示支持正常邮件。最终柱子的高度就是总的对数几率,如果为正,就判定为垃圾邮件。

说到底,朴素贝叶斯的每次预测,其实就是把每个特征的对数似然比加起来。

假设错了,为什么还能用?#

独立假设几乎从来都不成立。词语会共现,症状会聚集,传感器读数也会相互关联。但为什么朴素贝叶斯在文本分类的基准测试中,总能胜过那些明确考虑相关性的模型?原因有四个,而且它们相辅相成:

  1. 分类只看排序,不看概率校准。 argmax 只关心哪个后验概率最大,而不是它的绝对值。一个模型的概率估计可能偏差很大,但只要排序正确,分类结果就没问题。
  2. 对数比值中的误差会互相抵消。 计算后验概率比值时,重复的相关特征会让两类的得分都增加相近的量,最终这些偏差基本抵消掉了。
  3. 偏差–方差权衡占优: 独立假设虽然引入了偏差,但大幅减少了参数量:从 $\mathcal{O}(K \cdot d^2)$ 的相关性参数降到 $\mathcal{O}(K \cdot d)$ 的边缘分布。数据有限时,降低方差往往能让模型表现更好。
  4. Domingos–Pazzani 定理(1997)。 这个定理证明,只要真实后验概率最高的类别与朴素贝叶斯估计出的最高后验概率一致,模型就能达到 0-1 损失最优——这个条件比独立假设本身弱得多。换句话说,即使朴素贝叶斯对概率的估计完全不准,它在每次预测中仍然可能是正确的。

这并不是说可以忽略诊断。朴素贝叶斯的概率输出并不可靠(详见 Q&A)。但如果任务是排序或取 argmax,它的实际效果远超预期。


参考实现#

用 NumPy 写了一个干净的实现,包含三种变体。最后用 scikit-learn 验证了高斯版本。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import numpy as np
from collections import defaultdict

class GaussianNB:
    """高斯朴素贝叶斯,适用于连续特征。"""

    def fit(self, X, y):
        self.classes_ = np.unique(y)
        self.prior_ = np.array([(y == c).mean() for c in self.classes_])
        # mu, var: 形状 (K, d)
        self.mu_ = np.array([X[y == c].mean(axis=0) for c in self.classes_])
        self.var_ = np.array([X[y == c].var(axis=0) for c in self.classes_]) + 1e-9
        return self

    def _log_likelihood(self, X):
        # 每个类别的各特征 log N(x; mu, var) 求和 -> (N, K)
        out = np.empty((X.shape[0], len(self.classes_)))
        for k in range(len(self.classes_)):
            diff2 = (X - self.mu_[k]) ** 2
            ll = -0.5 * (np.log(2 * np.pi * self.var_[k]) + diff2 / self.var_[k])
            out[:, k] = ll.sum(axis=1)
        return out

    def predict_log_proba(self, X):
        log_post = np.log(self.prior_) + self._log_likelihood(X)
        # log-sum-exp 归一化,保证数值稳定
        log_post -= log_post.max(axis=1, keepdims=True)
        log_post -= np.log(np.exp(log_post).sum(axis=1, keepdims=True))
        return log_post

    def predict(self, X):
        return self.classes_[np.argmax(self.predict_log_proba(X), axis=1)]

class MultinomialNB:
    """多项式朴素贝叶斯,带拉普拉斯平滑,适合词频特征。"""

    def __init__(self, alpha=1.0):
        self.alpha = alpha

    def fit(self, X, y):
        self.classes_ = np.unique(y)
        K, d = len(self.classes_), X.shape[1]
        self.prior_ = np.array([(y == c).mean() for c in self.classes_])
        self.log_theta_ = np.empty((K, d))
        for k, c in enumerate(self.classes_):
            counts = X[y == c].sum(axis=0)
            self.log_theta_[k] = np.log((counts + self.alpha) /
                                        (counts.sum() + self.alpha * d))
        return self

    def predict(self, X):
        log_post = np.log(self.prior_) + X @ self.log_theta_.T
        return self.classes_[np.argmax(log_post, axis=1)]

class BernoulliNB:
    """伯努利朴素贝叶斯,适用于二值特征。"""

    def __init__(self, alpha=1.0):
        self.alpha = alpha

    def fit(self, X, y):
        X = (X > 0).astype(float)
        self.classes_ = np.unique(y)
        K, d = len(self.classes_), X.shape[1]
        self.prior_ = np.array([(y == c).mean() for c in self.classes_])
        self.p_ = np.empty((K, d))
        for k, c in enumerate(self.classes_):
            Xc = X[y == c]
            self.p_[k] = (Xc.sum(axis=0) + self.alpha) / (len(Xc) + 2 * self.alpha)
        return self

    def predict(self, X):
        X = (X > 0).astype(float)
        # log P(x|c) = sum [ x log p + (1-x) log (1-p) ]
        log_p = np.log(self.p_)
        log_1mp = np.log(1 - self.p_)
        log_lik = X @ log_p.T + (1 - X) @ log_1mp.T
        log_post = np.log(self.prior_) + log_lik
        return self.classes_[np.argmax(log_post, axis=1)]

if __name__ == "__main__":
    from sklearn.datasets import load_iris
    from sklearn.model_selection import train_test_split
    from sklearn.naive_bayes import GaussianNB as SkGNB

    X, y = load_iris(return_X_y=True)
    X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=42)

    ours = GaussianNB().fit(X_tr, y_tr)
    sk = SkGNB().fit(X_tr, y_tr)

    print(f"自实现:  {(ours.predict(X_te) == y_te).mean():.4f}")
    print(f"sklearn: {sk.score(X_te, y_te):.4f}")
    # 该随机种子下两者均为 0.9778。

练习题#

练习 1 — 条件独立的定义#

题目 已知 $P(c_1) = 0.6$$P(x_1=1 \mid c_1) = 0.8$$P(x_2=1 \mid c_1) = 0.5$ 。在朴素贝叶斯假设下,计算 $P(x_1=1, x_2=1 \mid c_1)$

$$P(x_1=1, x_2=1 \mid c_1) = P(x_1=1 \mid c_1)\, P(x_2=1 \mid c_1) = 0.8 \times 0.5 = 0.4.$$

这里 $P(c_1)$ 对条件分布没有影响,只有在计算无条件概率 $P(x_1, x_2)$ 时才需要用到。

练习 2 — 拉普拉斯平滑的实际计算#

题目 假设词表大小 $V = 1000$ ,正类语料中有 200 个词,其中 excellent 出现了 5 次。分别计算:(a) MLE 估计;(b) 拉普拉斯平滑($\alpha = 1$ )估计;(c) 未见词的平滑估计。

解答

$$\hat{P}(\text{excellent} \mid +) = 5 / 200 = 0.025。$$ $$\hat{P}(\text{excellent} \mid +) = (5+1) / (200 + 1000) = 6 / 1200 = 0.005。$$ $$\hat{P}(w \mid +) = (0+1) / (200 + 1000) = 1/1200 \approx 8.3 \times 10^{-4}。$$

注意:当 $\alpha V \gg N_k$ (这里 $1000 \gg 200$ )时,平滑会显著压低分布的峰值。这正是平滑的作用:当类条件数据稀少时,先验主导了结果。

练习 3 — 同一封邮件,多项式模型 vs 伯努利模型#

题目 一封 100 词的邮件中,win 出现了 5 次,free 出现了 3 次。已知垃圾邮件类下 $P(\text{win} \mid \text{spam}) = 0.05$$P(\text{free} \mid \text{spam}) = 0.03$ (多项式模型参数);$P(\text{win 出现} \mid \text{spam}) = 0.7$$P(\text{free 出现} \mid \text{spam}) = 0.6$ (伯努利模型参数)。比较两者的对数似然贡献。

解答

$$\ln L_{\mathrm{mult}} = 5\ln(0.05) + 3\ln(0.03) = 5(-2.996) + 3(-3.507) = -25.5。$$ $$\ln L_{\mathrm{bern}} = \ln(0.7) + \ln(0.6) = -0.357 + (-0.511) = -0.87。$$

这两个值不能直接对比,因为它们描述的是不同的概率对象。但从形态上看,多项式模型会线性放大重复出现的信号,而伯努利模型则把“出现 1 次”和“出现 5 次”视为等价证据。对于长文档,这种动态范围很重要;但对于短文本(如推特),通常并不重要。

练习 4 — 手动计算高斯 NB 参数#

题目 类别 $+1$ 包含三个二维点:$(1, 2), (2, 3), (3, 1)$ 。求高斯 NB 的参数。

$$ \hat\mu_1 = \tfrac{1+2+3}{3} = 2, \quad \hat\sigma_1^2 = \tfrac{(1{-}2)^2 + (2{-}2)^2 + (3{-}2)^2}{3} = \tfrac{2}{3}, $$ $$ \hat\mu_2 = \tfrac{2+3+1}{3} = 2, \quad \hat\sigma_2^2 = \tfrac{(2{-}2)^2 + (3{-}2)^2 + (1{-}2)^2}{3} = \tfrac{2}{3}. $$

因此,标准差为 $\hat\sigma_1 = \hat\sigma_2 = \sqrt{2/3} \approx 0.816$ 。高斯 NB 不考虑协方差的非对角项,所以样本 $(1,3)$ 落在“错误对角线”上的情况不会影响模型。

练习 5 — 为什么朴素贝叶斯仍然有效?#

题目 列出朴素贝叶斯在独立性假设被破坏时仍然有效的四个独立原因。

解答 这些理由总结如下:

  1. 决策只看 argmax 分类任务只需要正确的排序,不需要精确的概率值。
  2. 偏差相互抵消 相关特征会同时抬高两类的对数似然,这些偏差在后验比值中会被抵消。
  3. 偏差–方差权衡有利 用少量偏差换取大幅降低方差,在样本量相对维度 $d$ 较小时尤其划算。
  4. Domingos–Pazzani 定理 只要朴素贝叶斯的 argmax 与真实后验一致,就能达到 0-1 损失最优——这个条件远弱于联合分布真的可以分解。

常见问题#

为什么叫“朴素”?#

“朴素”指的是条件独立假设过于简单——词与词会共现,症状也会成簇出现,但模型却假设它们彼此独立。这个名称强调了这种假设的极端简化特性。

朴素贝叶斯和逻辑回归有什么关系?#

在各类共享逐特征方差的情况下,高斯朴素贝叶斯会产生一个线性决策边界 $\mathbf{w}^\top\mathbf{x} + b = 0$ ,形式和逻辑回归一样。不过系数不同,因为朴素贝叶斯通过生成式 MLE 估计 $P(\mathbf{x}, y)$ 来得到 $\mathbf{w}$ ,而逻辑回归则是直接对 $P(y \mid \mathbf{x})$ 做判别式拟合。从渐近性质看,逻辑回归至少不会比朴素贝叶斯差,但朴素贝叶斯收敛所需样本更少。

朴素贝叶斯输出的概率值可信吗?#

不可信: 相关特征的对数似然会被重复计算,导致后验概率通常过于极端(接近 0 或 1)。对于排序任务(如 argmax、Top-$K$ 、ROC),这没有问题。但如果决策依赖概率大小(比如成本敏感阈值或风险计算),就需要用 Platt scaling等距回归 在留出集上校准。

时间复杂度是多少?#

训练:$\mathcal{O}(Nd)$ ——只需遍历一次训练数据。
预测:$\mathcal{O}(Kd)$ ——每个样本计算一次。
没有迭代,也没有需要复杂调参的超参数(最多用交叉验证扫一下 $\alpha$ )。

如何处理缺失特征?#

天然支持: 如果样本 $i$ 的特征 $j$ 缺失,直接从对数和中去掉 $\ln P(x_i^{(j)} \mid c_k)$ 这一项即可。这在数学上等价于对缺失特征做边缘化,是生成式建模的一大优势。

什么时候不该用朴素贝叶斯?#

当以下情况出现时:
(i) 特征强相关,且相关性在不同类别间差异显著(误差抵消失效);
(ii) 任务需要校准良好的概率值;
(iii) 数据充足,且可以使用判别式模型——逻辑回归、梯度提升或 Transformer 通常表现更好。

下一步#

朴素贝叶斯的强假设——“给定类别,特征条件独立”——简单得几乎像作弊,但实战中它常常工作。问题在于,当特征之间真的有强相关性(医学诊断里的症状、推荐系统里的物品共现),这个假设会以可见的方式崩掉。下一章是这条路线的自然延伸:放松独立假设,但不一次放完。

半朴素贝叶斯(TAN、AODE)允许每个特征至多依赖一个其他特征——表达力上去了,参数估计依然可处理。再往上一步就是完整的贝叶斯网络:用一张有向无环图显式描述变量之间的条件独立结构,把联合分布因子分解成局部条件概率。我会沿着 NB → TAN → AODE → 一般贝叶斯网络这条阶梯往上爬,每一步都问同一个问题——多放松一点假设,得到了多少表达力,付出了多少推断/学习成本。

参考文献#

  • Domingos, P., & Pazzani, M. (1997). On the optimality of the simple Bayesian classifier under zero-one loss. Machine Learning, 29(2-3), 103-130.
  • Ng, A. Y., & Jordan, M. I. (2001). On discriminative vs. generative classifiers: A comparison of logistic regression and naive Bayes. NeurIPS.
  • McCallum, A., & Nigam, K. (1998). A comparison of event models for naive Bayes text classification. AAAI Workshop on Learning for Text Categorization.
  • Manning, C. D., Raghavan, P., & Schutze, H. (2008). Introduction to Information Retrieval. Cambridge University Press. Chapter 13.
  • Bishop, C. M. (2006). Pattern Recognition and Machine Learning. Springer. Section 8.2.
  • Murphy, K. P. (2012). Machine Learning: A Probabilistic Perspective. MIT Press. Chapter 3.

本系列

机器学习数学推导 20 篇

  1. 01 机器学习数学推导(一):绪论与数学基础
  2. 02 机器学习数学推导(二):线性代数与矩阵论
  3. 03 机器学习数学推导(三):概率论与统计推断
  4. 04 机器学习数学推导(四):凸优化理论
  5. 05 机器学习数学推导(五):线性回归
  6. 06 机器学习数学推导(六):逻辑回归与分类
  7. 07 机器学习数学推导(七):决策树
  8. 08 机器学习数学推导(八):支持向量机
  9. 09 机器学习数学推导(九):朴素贝叶斯 当前
  10. 10 机器学习数学推导(十):半朴素贝叶斯与贝叶斯网络
  11. 11 机器学习数学推导(十一):集成学习
  12. 12 机器学习数学推导(十二):XGBoost 与 LightGBM
  13. 13 机器学习数学推导(十三):EM 算法与 GMM
  14. 14 机器学习数学推导(十四):变分推断与变分 EM
  15. 15 机器学习数学推导(十五):隐马尔可夫模型
  16. 16 机器学习数学推导(十六):条件随机场
  17. 17 机器学习数学推导(十七):降维与主成分分析
  18. 18 机器学习数学推导(十八):聚类算法
  19. 19 机器学习数学推导(十九):神经网络与反向传播
  20. 20 机器学习数学推导(二十):正则化与模型选择

读有所得?

GitHub 关注我 → 新文周更

GitHub