查看全课大纲(第 24 / 82 节)
  1. 1.函数与数据泛化
  2. 2.向量:从几何直觉到高维空间
  3. 3.矩阵与张量
  4. 4.特征值与特征向量:矩阵变换的不动方向
  5. 5.凸函数:从向量求导的矩阵记号到好优化的函数形状
  6. 6.概率与统计:机器学习的数学基础
  7. 7.独立性与随机变量:贝叶斯公式与二项分布
  8. 8.期望、方差与协方差:随机变量的数字画像
  9. 9.联合概率:当一条轴不够用的时候
  10. 10.概率分布(一):从伯努利到伽马函数
  11. 11.概率分布(二):贝塔、泊松、正态与两个贝叶斯故事
  12. 12.机器学习的模型:找输入与输出的关系
  13. 13.机器学习的应用
  14. 14.过拟合
  15. 15.机器学习的分类
  16. 16.有监督学习:从房价预测说起
  17. 17.损失函数
  18. 18.梯度下降(上):更新规则与学习速率
  19. 19.梯度下降(2)
  20. 20.牛顿方法
  21. 21.KNN简介
  22. 22.距离测算
  23. 23.朴素贝叶斯
  24. 24.朴素贝叶斯的实际应用
  25. 25.信息熵:决策树构建的度量基础
  26. 26.信息增益与决策树的构建
  27. 27.ID3算法
  28. 28.决策树节点的划分
  29. 29.CART树
  30. 30.Bagging
  31. 31.Boosting:自适应提升算法
  32. 32.Gradient Boosting
  33. 33.线性模型:回归与分类的同一副骨架
  34. 34.最小二乘:把最优参数直接解出来
  35. 35.最小二乘法的几何与概率视角
  36. 36.极大似然:给最小二乘一个概率出身
  37. 37.逻辑回归(1):把线性模型接到分类上
  38. 38.逻辑回归(2):损失函数与多分类
  39. 39.---- 手造数据: 5 个样本, 2 个特征; x2 几乎 = 2*x1 (偏差手工指定, 无随机) ----
  40. 40.讲师例: 向量 "23014" -- 三把范数尺子量同一个向量
  41. 41.优化方法(1):坐标下降与前向选择
  42. 42.优化方法(2):前向策略与最小角回归
  43. 43.拉格朗日乘子法(1):从无约束到等式约束
  44. 44.拉格朗日乘子法(2):等式约束下的平行条件与拉格朗日函数
  45. 45.拉格朗日乘子法(3):不等式约束与 KKT 条件
  46. 46.最大间隔:把分类问题变成优化问题
  47. 47.拉格朗日对偶问题:把 w 和 b 全部换成 α
  48. 48.支持向量:边界上的少数派
  49. 49.SVM 计算过程:一笔到底算完,再走进核方法
  50. 50.贝叶斯公式:概率即信念
  51. 51.隐含变量和概率模型:给看不见的原因建模
  52. 52.EM 算法:期望与最大化的迭代
  53. 53.琴生不等式:EM 的数学钥匙
  54. 54.三个硬币问题:EM 的复盘与衔接
  55. 55.高斯混合模型:用隐变量解释双峰数据
  56. 56.隐马尔可夫模型
  57. 57.隐马尔可夫模型(2):前向算法与动态混合模型
  58. 58.隐马尔可夫模型在 NLP 中的运用
  59. 59.EM 算法:把「为什么收敛」推到底
  60. 60.HMM 在 NLP 中的运用:从分词到机器翻译
  61. 61.HMM 参数估计:Baum-Welch 的三块拉格朗日
  62. 62.高维下的高斯模型
  63. 63.主题模型:从词袋到隐含主题
  64. 64.Dirichlet 分布(1)
  65. 65.Dirichlet 分布(2)
  66. 66.统计学习内容回顾
  67. 67.K-means 算法
  68. 68.PCA 降维
  69. 69.SVD 降维
  70. 70.从聚类到流形
  71. 71.局部线性嵌入
  72. 72.随机邻域嵌入:SNE 与 t-SNE
  73. 73.无参模型:让数据自己说话
  74. 74.高斯过程:函数空间里的正态分布
  75. 75.高斯过程(2):噪声、正则化与核的线性组合
  76. 76.神经网络简介:从感知器到自编码器
  77. 77.反向传播:把误差一层层传回去
  78. 78.卷积神经网络(CNN):让特征自己学出来
  79. 79.循环神经网络(RNN):给网络装上记忆
  80. 80.深度学习回顾:静态一类,动态一类
  81. 81.增强学习(1):蒙特卡洛、树搜索与 Q-learning
  82. 82.强化学习(2):从乌鸦吃核桃到井字棋的 value 回传

朴素贝叶斯的实际应用

约 33 分钟

📺 正在播放小象官方高清录播(支持倍速与清晰度调节)

小象实战讲义 · 机器学习算法精讲

本节我们将通过一个具体的分类问题和一个经典的文本分类应用——垃圾邮件过滤,来深入理解朴素贝叶斯算法是如何从理论走向实践的。你将看到,即便基于一个“朴素”的独立性假设,该算法依然能在许多现实任务中取得令人惊讶的效果。

💡 核心导读

  • 从天气到决策:通过经典的“打网球问题”,学习如何将朴素贝叶斯公式转化为具体的查表计算。
  • 文本的向量化表示:了解如何将一封邮件(文本数据)转化为一个高维的特征向量,这是应用机器学习于文本领域的关键一步。
  • 垃圾邮件分类实战:剖析如何用朴素贝叶斯构建一个垃圾邮件过滤器,并理解其核心计算步骤。
  • 平滑技术的重要性:认识“零概率”问题,并学习拉普拉斯平滑等技巧如何避免计算崩溃。

1. 经典案例:打网球问题

我们从一个经典的机器学习数据集——“打网球问题”开始。这个例子最早出现在 Tom Mitchell 的《Machine Learning》一书中,它清晰地展示了朴素贝叶斯在离散特征分类问题上的应用。

1.1 问题描述

我们有一份过去14天的天气记录作为训练数据。每一天有四个天气特征:

  • Outlook:天气概况,取值为 Sunny(晴)、Overcast(多云)、Rain(雨)。
  • Temperature:温度,取值为 Hot(热)、Mild(温和)、Cool(凉)。
  • Humidity:湿度,取值为 High(高)、Normal(正常)。
  • Wind:风力,取值为 Strong(强)、Weak(弱)。

每一天还有一个目标值(标签):

  • Play Tennis:是否去打网球,取值为 Yes 或 No。

在14天的数据中,有9天去打网球(Yes),5天没去(No)。

现在,给定一个新的一天,其特征为: Outlook=Sunny, Temperature=Cool, Humidity=High, Wind=Strong

我们的任务是:预测这一天是否会去打网球(Yes 或 No)。

1.2 朴素贝叶斯分类过程

根据朴素贝叶斯公式,对于新实例 x′\mathbf{x}',我们计算其属于类别 cc 的概率正比于: P(c∣x′)∝P(c)∏i=1dP(xi′∣c)P(c \mid \mathbf{x}') \propto P(c) \prod_{i=1}^{d} P(x_i' \mid c) 其中 d=4d=4 是特征数。

我们需要分别计算 c=Yesc = \text{Yes} 和 c=Noc = \text{No} 的情况,然后比较大小,或者进一步归一化得到概率。

第一步:计算先验概率 P(c)P(c)

  • P(Yes)=9/14P(\text{Yes}) = 9 / 14
  • P(No)=5/14P(\text{No}) = 5 / 14

第二步:计算条件概率 P(xi′∣c)P(x_i' \mid c) 这需要通过“查数”从训练数据中统计得到。例如,对于 Outlook=Sunny:

  • 在所有 Play=Yes 的9天中,Outlook=Sunny 出现了2天,所以 P(Sunny∣Yes)=2/9P(\text{Sunny} \mid \text{Yes}) = 2/9。
  • 在所有 Play=No 的5天中,Outlook=Sunny 出现了3天,所以 P(Sunny∣No)=3/5P(\text{Sunny} \mid \text{No}) = 3/5。

同理,我们可以计算出所有需要的条件概率,汇总如下表:

特征/条件P(⋅∣Yes)P(\cdot \mid \text{Yes})P(⋅∣No)P(\cdot \mid \text{No})
Outlook=Sunny2/93/5
Temperature=Cool3/91/5
Humidity=High3/94/5
Wind=Strong3/93/5

第三步:代入公式计算 对于新实例 x′\mathbf{x}':

  • P(Yes∣x′)∝(2/9)×(3/9)×(3/9)×(3/9)×(9/14)≈0.0053P(\text{Yes} \mid \mathbf{x}') \propto (2/9) \times (3/9) \times (3/9) \times (3/9) \times (9/14) \approx 0.0053
  • P(No∣x′)∝(3/5)×(1/5)×(4/5)×(3/5)×(5/14)≈0.0206P(\text{No} \mid \mathbf{x}') \propto (3/5) \times (1/5) \times (4/5) \times (3/5) \times (5/14) \approx 0.0206

第四步:决策 比较两个未归一化的值,0.0206>0.00530.0206 > 0.0053,因此我们预测这一天 不会 去打网球(No)。

如果需要得到归一化的概率:

  • P(Yes∣x′)=0.0053/(0.0053+0.0206)≈0.205P(\text{Yes} \mid \mathbf{x}') = 0.0053 / (0.0053 + 0.0206) \approx 0.205
  • P(No∣x′)=0.0206/(0.0053+0.0206)≈0.795P(\text{No} \mid \mathbf{x}') = 0.0206 / (0.0053 + 0.0206) \approx 0.795

可以看到,预测为 No 的概率远大于 Yes。

2. 迈向现实:垃圾邮件过滤

打网球问题展示了朴素贝叶斯的基本机制。现在,我们将其应用到一个更复杂、也更经典的现实问题:垃圾邮件(Spam Email)过滤。

先纠正一个常见误称:垃圾邮件叫 spam email,不叫 rubbish email——spam 这个词有段好玩的来历:它本是英国一部肥皂剧里最受欢迎的午餐肉罐头;剧中有个人进餐馆,发现菜单上所有的菜都是午餐肉——炒午餐肉、蒸午餐肉、凉拌午餐肉、炸午餐肉……everything is spam。后来人们就用 spam 形容那种”塞给你一大堆内容、但全是无意义重复、对你没有用”的邮件——比如群发的”诚邀您参加我们的会议”。它不是被扔掉的垃圾(rubbish),而是”量大而无用”的轰炸。顺带一提,朴素贝叶斯 Naive Bayes 简称 NB——讲师打趣说,这简称本身也是个”好词”。

2.1 问题定义与数据表示

  • 输入 x\mathbf{x}:一封电子邮件。
  • 输出 yy:邮件的类别标签。通常 y=1y=1 表示正常邮件(Non-Spam),y=0y=0 表示垃圾邮件(Spam)。(标签映射可以互换,不影响算法本质)。

关键挑战:如何将一封文本邮件表示成机器学习算法可以处理的数值向量 x\mathbf{x}?

我们采用 词袋模型(Bag of Words):

  1. 构建一个包含 VV 个词的词典(Vocabulary),例如 [“a”, “apple”, “buy”, “the”, “饭”, …]。
  2. 对于任何一封邮件,我们将其表示为一个长度为 VV 的向量 x=[x1,x2,…,xV]\mathbf{x} = [x_1, x_2, …, x_V]。
  3. 向量中的每个元素 xjx_j 表示词典中第 jj 个词在这封邮件中出现的次数(或是否出现,即0或1)。

例如,一封内容为 “buy apple” 的邮件,在词典 [“a”, “apple”, “buy”, “the”] 下的表示可能是 [0, 1, 1, 0]。

这种表示方法完全忽略了词的顺序(语序),只关心词是否出现以及出现的频率,因此被称为“词袋”。

2.2 朴素贝叶斯垃圾邮件分类器

现在,问题转化为:给定一个用高维向量表示的新邮件 x′\mathbf{x}',判断 P(y=0∣x′)P(y=0 \mid \mathbf{x}') 和 P(y=1∣x′)P(y=1 \mid \mathbf{x}') 哪个更大。

根据朴素贝叶斯公式: P(y=c∣x′)∝P(y=c)∏j=1VP(xj′∣y=c)P(y=c \mid \mathbf{x}') \propto P(y=c) \prod_{j=1}^{V} P(x_j' \mid y=c) 这里 c∈{0,1}c \in \lbrace 0, 1\rbrace,VV 是词典大小。

模型参数估计:

  1. 先验概率 P(y=c)P(y=c):在训练集中,统计垃圾邮件和正常邮件的数量。

    • P(y=1)=正常邮件数总邮件数P(y=1) = \frac{\text{正常邮件数}}{\text{总邮件数}}
    • P(y=0)=垃圾邮件数总邮件数P(y=0) = \frac{\text{垃圾邮件数}}{\text{总邮件数}}
  2. 条件概率 P(xj=k∣y=c)P(x_j = k \mid y=c):这表示在类别 cc 的邮件中,词典第 jj 个词出现次数为 kk 的概率。为了简化,我们常使用伯努利朴素贝叶斯,即只关心词是否出现(k=1k=1 或 00)。那么我们需要估计:

    • P(xj=1∣y=1)P(x_j = 1 \mid y=1):在所有正常邮件中,第 jj 个词出现过的邮件比例。
    • P(xj=1∣y=0)P(x_j = 1 \mid y=0):在所有垃圾邮件中,第 jj 个词出现过的邮件比例。

具体计算时,对于每个词 wjw_j:

  • P(xj=1∣y=1)=包含词wj的正常邮件数+1正常邮件总数+2P(x_j=1 \mid y=1) = \frac{\text{包含词} w_j \text{的正常邮件数} + 1}{\text{正常邮件总数} + 2}
  • P(xj=1∣y=0)=包含词wj的垃圾邮件数+1垃圾邮件总数+2P(x_j=1 \mid y=0) = \frac{\text{包含词} w_j \text{的垃圾邮件数} + 1}{\text{垃圾邮件总数} + 2}

注意:公式中分子加1,分母加2的操作称为 拉普拉斯平滑(Laplace Smoothing) 或 加一平滑。这是为了解决“零概率问题”。

2.3 零概率问题与平滑技术

零概率问题:如果新邮件中出现了一个词 wtw_t,而这个词在训练集的某个类别(比如正常邮件)中从未出现过,那么根据最大似然估计,P(xt=1∣y=1)=0P(x_t=1 \mid y=1) = 0。由于概率是连乘的,这会导致整个 P(y=1∣x′)P(y=1 \mid \mathbf{x}') 的计算结果变为0,模型就无法做出有效判断。

平滑技术:为了避免零概率,我们在估计概率时给每个计数加上一个小的常数(通常是1)。这相当于假设每个词在任何类别的邮件中都至少“出现”了很小的次数。平滑后的概率估计虽然略有偏差,但保证了数值稳定性,并且通常能提升模型的泛化能力。

除了加一平滑,也可以直接为未出现的词赋予一个极小的固定概率(如 10−410^{-4},约万分之一——词典若有两万个词,加一平滑后的兜底概率也是这个量级)。

3. 算法实现与代码实践

下面,我们用一个极简化的示例,演示如何用纯 Python 标准库实现一个伯努利朴素贝叶斯分类器,用于区分两段文本的类别。

import math
from collections import defaultdict

class BernoulliNaiveBayes:
    """伯努利朴素贝叶斯分类器(极简演示版)"""
    
    def __init__(self, alpha=1.0):
        """
        初始化
        :param alpha: 平滑参数(拉普拉斯平滑中的加数)
        """
        self.alpha = alpha
        self.prior = {}          # 先验概率 log(P(y))
        self.cond_prob = {}      # 条件概率 log(P(x_j=1|y))
        self.vocab = set()       # 词典
    
    def fit(self, X, y):
        """
        训练模型
        :param X: 文本列表,每个元素是一个字符串
        :param y: 类别标签列表
        """
        # 1. 构建词典
        for doc in X:
            self.vocab.update(doc.split())
        vocab_list = list(self.vocab)
        V = len(vocab_list)
        word_to_idx = {word: i for i, word in enumerate(vocab_list)}
        
        # 2. 计算先验概率(取对数)
        class_counts = defaultdict(int)
        for label in y:
            class_counts[label] += 1
        total_docs = len(y)
        for c, count in class_counts.items():
            self.prior[c] = math.log(count / total_docs)
        
        # 3. 计算条件概率(取对数,并应用平滑)
        # 初始化计数
        doc_count = {c: 0 for c in class_counts}  # 各类别文档数
        word_count = {c: [0] * V for c in class_counts} # 各类别中词出现的文档数
        
        for doc, label in zip(X, y):
            doc_count[label] += 1
            words_in_doc = set(doc.split())  # 伯努利模型:只关心是否出现
            for word in words_in_doc:
                if word in word_to_idx:
                    word_count[label][word_to_idx[word]] += 1
        
        # 计算 log(P(word|class))
        self.cond_prob = {c: [0.0] * V for c in class_counts}
        for c in class_counts:
            for j in range(V):
                # 拉普拉斯平滑: (count + alpha) / (doc_count + 2*alpha)
                prob = (word_count[c][j] + self.alpha) / (doc_count[c] + 2 * self.alpha)
                self.cond_prob[c][j] = math.log(prob)
            # 同时存储未出现的概率 log(1 - P(word|class)),预测时使用
            self.cond_prob[c + '_absent'] = [math.log(1.0 - math.exp(lp)) for lp in self.cond_prob[c]]
        
        # 保存映射
        self.word_to_idx = word_to_idx
        self.classes = list(class_counts.keys())
    
    def predict(self, X):
        """
        预测类别
        :param X: 文本列表
        :return: 预测的类别列表
        """
        predictions = []
        for doc in X:
            words = set(doc.split())
            scores = {}
            for c in self.classes:
                # 分数 = log(P(y)) + Σ log(P(x_j|y))
                score = self.prior[c]
                for word, idx in self.word_to_idx.items():
                    if word in words:
                        score += self.cond_prob[c][idx]        # 词出现
                    else:
                        score += self.cond_prob[c + '_absent'][idx] # 词未出现
                scores[c] = score
            # 选择分数最高的类别
            predictions.append(max(scores, key=scores.get))
        return predictions

# ===== 示例:简单的电影评论情感分类 =====
# 训练数据:简单的正面/负面评论
train_texts = [
    "good great wonderful fantastic",  # 正面
    "bad terrible awful horrible",     # 负面
    "good nice excellent",             # 正面
    "poor boring dull",                # 负面
]
train_labels = ['pos', 'neg', 'pos', 'neg']

# 测试数据
test_texts = [
    "good great",      # 应预测为正面
    "bad awful",       # 应预测为负面
    "good bad",        # 混合词,看先验和具体概率
]

# 训练和预测
nb = BernoulliNaiveBayes(alpha=1.0)
nb.fit(train_texts, train_labels)
preds = nb.predict(test_texts)

print("训练数据词典:", sorted(nb.vocab))
print("\n测试结果:")
for text, label in zip(test_texts, preds):
    print(f"  文本: '{text}' -> 预测: {label}")

# 输出关键概率(取指数恢复概率值)
print(f"\n先验概率:")
for c, logp in nb.prior.items():
    print(f"  P({c}) = {math.exp(logp):.3f}")

print(f"\n条件概率示例 P(word|pos) 和 P(word|neg):")
sample_words = ['good', 'bad', 'great', 'awful']
for w in sample_words:
    if w in nb.word_to_idx:
        idx = nb.word_to_idx[w]
        p_pos = math.exp(nb.cond_prob['pos'][idx])
        p_neg = math.exp(nb.cond_prob['neg'][idx])
        print(f"  P({w}|pos)={p_pos:.3f}, P({w}|neg)={p_neg:.3f}")
训练数据词典: ['awful', 'bad', 'boring', 'dull', 'excellent', 'fantastic', 'good', 'great', 'horrible', 'nice', 'poor', 'terrible', 'wonderful']

测试结果:
  文本: 'good great' -> 预测: pos
  文本: 'bad awful' -> 预测: neg
  文本: 'good bad' -> 预测: pos

先验概率:
  P(pos) = 0.500
  P(neg) = 0.500

条件概率示例 P(word|pos) 和 P(word|neg):
  P(good|pos)=0.750, P(good|neg)=0.250
  P(bad|pos)=0.250, P(bad|neg)=0.500
  P(great|pos)=0.500, P(great|neg)=0.250
  P(awful|pos)=0.250, P(awful|neg)=0.500

代码解读与注意事项:

  1. 伯努利模型:代码实现了伯努利朴素贝叶斯,即特征 xjx_j 表示“词 wjw_j 是否在文档中出现”(0或1)。因此,在计算文档概率时,需要同时考虑词出现 P(xj=1∣y)P(x_j=1 \mid y) 和词未出现 P(xj=0∣y)=1−P(xj=1∣y)P(x_j=0 \mid y) = 1 - P(x_j=1 \mid y) 的情况。
  2. 对数空间计算:概率连乘容易导致数值下溢(结果接近0)。因此,实际计算在对数空间进行,将连乘转化为连加,最后比较对数概率的大小。
  3. 平滑:alpha=1.0 对应标准的拉普拉斯加一平滑。
  4. 示例规模:示例数据极小,仅用于演示算法流程。真实垃圾邮件分类需要数万封邮件和数万规模的词典。

4. 中文垃圾邮件分类实战提示

在实际课程中,我们提供了一个完整的中文垃圾邮件分类项目代码包。它包含以下核心部分:

  • 数据:约7000封垃圾邮件和7000封正常邮件用于训练,近400封未标注邮件用于测试。
  • 文本预处理:使用 jieba 库进行中文分词,并移除了“的”、“了”、“呢”等停用词。
  • 核心算法:实现了与上述原理一致的朴素贝叶斯分类器,并针对中文特点进行了调整。
  • 性能:在测试集上准确率可达约94%。

关键实践步骤:

  1. 分词:中文需要先分词。例如,“我喜欢机器学习”应分词为 [“我”, “喜欢”, “机器”, “学习”]。
  2. 特征选择:并非所有词都有区分度。可以过滤掉出现次数太少或太多的词,或使用信息增益等方法选择关键特征。
  3. 平滑策略:对于只在垃圾邮件里出现、正常邮件中从未见过的词,课程代码直接赋予固定小概率 0.01——这是平滑的另一种形式。
  4. 环境小坑:代码包里的中文停用词表文件名是中文的,个别系统读不出来时,把它改成任意英文文件名并保持调用路径一致即可。

提示:本课程提供的实战代码包含了更复杂的工程细节。建议学员在理解本节基本原理后,运行并研究该代码,以加深对朴素贝叶斯应用于真实文本任务的理解。

最后想想”朴素”假设在文本上有多离谱:我们说”我喜欢喝——“后面几乎必然跟着水、饮料、可乐、酒,而绝不会是”喝桌子、喝手机、喝电源”——词与词之间显然高度相关。朴素贝叶斯却假设每个词相互独立,这是非常强的假设;但正如课程实战所示,一个”不合理”的假设配上高效的计算,照样能做到约 94% 的准确率。

📝 动手练一练

  1. 概念辨析:在“打网球问题”中,如果我们计算得到 P(Yes∣x′)=0.0053P(\text{Yes} \mid \mathbf{x}') = 0.0053 和 P(No∣x′)=0.0206P(\text{No} \mid \mathbf{x}') = 0.0206,我们已经可以做出决策。为什么通常还需要将它们归一化为概率 0.2050.205 和 0.7950.795?在什么场景下归一化是必要的?
👉 点击查看参考答案

参考答案: 归一化在以下场景是必要的:

  • 需要输出概率值:当系统不仅需要输出类别,还需要输出属于该类别的置信度或概率时。例如,在垃圾邮件过滤中,我们可能想告诉用户“此邮件有79.5%的可能性是垃圾邮件”,而不仅仅是“这是垃圾邮件”。
  • 多分类问题:当类别超过两个时,我们需要比较所有类别的概率,而归一化后的概率之和为1,更直观。
  • 模型集成或后续处理:如果朴素贝叶斯的输出要作为其他模型的输入,或者需要与另一个独立模型的输出进行比较、加权平均,那么标准化的概率是必需的。

在仅需要硬分类决策的场景下,比较未归一化的“得分”(正比于概率)已经足够,因为归一化分母相同,不影响大小比较。

  1. 代码修改:在上一节的代码示例中,我们实现了伯努利模型(只关心词是否出现)。请思考如何修改代码,使其实现多项式朴素贝叶斯(Multinomial Naive Bayes)模型,即特征值 xjx_j 表示词 wjw_j 在文档中出现的次数。你只需要描述 fit 和 predict 方法中核心计算部分需要如何改变即可。
👉 点击查看参考答案

参考答案: 从伯努利模型改为多项式模型,核心变化在于条件概率 P(xj∣y)P(x_j \mid y) 的含义和计算方式:

在 fit 方法中:

  • 计数改变:不再统计“包含词 wjw_j 的文档数”,而是统计“类别 cc 的所有文档中,词 wjw_j 出现的总次数”。
  • 公式改变:条件概率估计变为: P(wj∣y=c)=词wj在类别c中的总出现次数+α类别c中所有词的总出现次数+V⋅αP(w_j \mid y=c) = \frac{\text{词} w_j \text{在类别}c\text{中的总出现次数} + \alpha}{\text{类别}c\text{中所有词的总出现次数} + V \cdot \alpha} 这里 VV 是词典大小,α\alpha 是平滑参数。
  • 存储改变:cond_prob[c][j] 存储的不再是 P(词出现∣c)P(\text{词出现} \mid c),而是 P(词wj∣c)P(\text{词} w_j \mid c)。

在 predict 方法中:

  • 计算改变:对于一篇文档,其属于类别 cc 的得分计算变为: log⁡P(c)+∑j=1Vxj′⋅log⁡P(wj∣c)\log P(c) + \sum_{j=1}^{V} x_j' \cdot \log P(w_j \mid c) 其中 xj′x_j' 是文档中词 wjw_j 出现的次数。这里是对文档中每一个出现的词,将其对数概率乘以出现次数后累加。注意,多项式模型通常不考虑词未出现的情况(即 xj=0x_j=0 的项,因为 log⁡P(wj∣c)\log P(w_j \mid c) 乘以0后贡献为0)。

简单来说,伯努利模型是“文档-词”的二维关系(是否出现),而多项式模型是“词”本身在类别中的分布,预测时用词频进行加权。

本章小结

本节我们深入探讨了朴素贝叶斯算法的两个核心应用。从结构清晰的“打网球”决策问题,到高维稀疏的文本分类任务,朴素贝叶斯展现了其独特的魅力:

  • 原理直观:基于贝叶斯定理,将后验概率分解为先验概率与条件概率的乘积。
  • 实现简单:核心参数(先验和条件概率)可以通过简单的计数和比例计算得到,训练速度极快。
  • 效果显著:尽管其“特征条件独立”的假设在现实中往往不成立(尤其是对于文本),但在许多分类任务上,尤其是文本分类,它仍然是强大且高效的基线模型。

朴素贝叶斯的成功也提醒我们,在机器学习中,一个合理的、即使不完全正确的假设,结合高效的计算,往往能带来实用的解决方案。

📋 行动清单

学完本节,你可以立即尝试:

  • 运行示例代码:将本节提供的伯努利朴素贝叶斯代码复制到 Python 环境中运行,并尝试修改训练数据,观察预测结果如何变化。
  • 分析平滑影响:在示例代码中,将 alpha 参数改为 0(无平滑)和 10(强平滑),重新训练并预测测试数据中的第三句 “good bad”,观察预测类别和概率值的变化,理解平滑的作用。
  • 构思你的分类器:思考一个你可以用朴素贝叶斯解决的简单二分类问题(例如,根据几个关键词判断一条短信是否是促销信息),并设计出它的特征表示方法。

—— 小象教研组

配套资料 · 直接下载

课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。

  • 第5章课件:经典机器学习模型 I
    下载
  • 第5章笔记:朴素贝叶斯
    下载
  • 第5章代码包
    下载