---
title: "朴素贝叶斯算法 讲解及示例（课程作业）"
description: 
date: 2026-04-12T22:10:40+08:00
image: 
math: 
license: 
rooms: 
    - '书房' 
hidden: false
comments: false
draft: false
slug: "00G"
---
### 朴素贝叶斯算法
#### 1.简介
朴素贝叶斯算法的原理，是通过贝叶斯公式$$\underbrace{P(Y|X)}_{{后验}} = \frac{\overbrace{P(X|Y)}^{{似然}}\cdot\overbrace{P(Y)}^{先验}}{\underbrace{P(X)}_{证据}}$$由
- “先验”$P(Y_j)$（样本中目标事件$Y_j$的发生频率）
- “似然”$P(X_i|Y_j)$（样本中目标事件$Y_j$发生时，各“证据”$X_i$的出现频率）

计算得到“后验”$P(Y_j|X_i)$（给定待判断的“证据”$X_i$，该“证据”出现的情况下目标事件$Y_j$的发生概率），通过比较后验的大小，来判断该“证据”出现的情况下最可能发生什么事件。  
由于$P(X_i)$固定，实际上只需要计算固定$i$下的$P(Y_jX_i)$（被称为“联合概率”）并比较大小，最大的$P(Y_jX_i)$对应的$Y_j$即为判断结果。  
#### 2.“朴素”的理解
“朴素”的含义，是各个“证据”$X_i$的发生是相互“条件独立”事件。也就是说，在“条件”事件$Y_j$发生下，各个“证据”$X_i$的发生是相互独立事件。公式为： $$P(X_mX_n|Y_j)=P(X_m|Y_j)\cdot P(X_n|Y_j)$$
这直接决定了给定多个待判断的“证据”$x_1,x_2,\cdots,x_n$时，“后验”$P(Y_j|x_1x_2\cdots x_n)$的计算公式：$$
P(Y_j|x_1x_2\cdots x_n)=P(Y_j)\cdot\frac{\Pi_{k=1}^nP(x_k|Y_j)}{P(x_1\cdots x_n)}
$$
（本文以“多项式”朴素贝叶斯算法为例，其它类别还有“高斯”（“证据”在区间内连续分布）以及“伯努利”（“证据”只有0和1））
实际上只需要计算“联合概率”$P(Y_j)\cdot\Pi_{k=1}^nP(x_k|Y_j)$。  
由于计算机的浮点数精度误差，为了防止过多连乘把上述结果约成0，一般取对数，比较不同$Y_j$下$\ln P(Y_j)+\Sigma_{k=1}^n\ln P(x_k|Y_j)$的大小，来判断给定证据$x_1,x_2,\cdots,x_n$下最可能出现哪个$Y_j$。  
简单来说，“朴素”决定多“证据”下“后验”的计算公式。
#### 3.“似然”的计算讲解
由于“先验”$P(Y_j)$可以直接通过统计得到，“后验”$P(Y_j|X_i)$由上述公式计算而得，因此算法的技术主要在于“似然”$P(X_i|Y_j)$的计算。  
一个比较常用的技术是：**拉普拉斯平滑**。这个技术被用来解决某个$P(X_i|Y_j)=0$的情况，也就是在样本中，某个事件$Y_j$下，某个“证据”$X_i$从未出现过的情况。  
若放任$P(X_i|Y_j)=0$，可能会在给出待判断“证据”$X_i$时，$\ln P(X_i|Y_j)$不存在，以及所有的$P(Y_jX_i)=0$，无法通过比较得出目标$Y_j$。  
为了解决这个问题，在计算“似然”$P(X_i|Y_j)$时，将每个$X_i$的出现频数增加1（被称为$\alpha=1$的拉普拉斯平滑，最为常用），得到新的“似然”计算公式：$$
P(X_i|Y_j)=\frac{N(X_i|Y_j)+1}{N(Y_j)+m}
$$
其中$m$表示所有会出现的“证据”$X_i$的种类数。
#### 4.示例与相关代码
问题：判断一封邮件是**垃圾邮件（Spam）**，还是**正常邮件（Ham）**。
已知的样本数据：
| 邮件 | 类别 | 包含的单词 |
|------|------|-----------|
| 邮件1 | Spam | 免费，优惠 |
| 邮件2 | Spam | 免费 |
| 邮件3 | Ham | 你好 |
| 邮件4 | Ham | 优惠，你好 |

所有“证据”：**免费、优惠、你好**$\to m=3$
1. 计算先验$P(Y_j)$
   根据样本数据：$P(Spam)=\frac{1}{2},P(Ham)=\frac{1}{2}$。
2. 计算似然$P(X_i|Y_j)$（使用$\alpha=1$的拉普拉斯平滑）：
   **Spam**：
$$\begin{align*}
P(免费|Spam)=\frac{2+1}{3+3}&=\frac{1}{2}\\
P(优惠|Spam)=\frac{1+1}{3+3}&=\frac{1}{3}\\
P(你好|Spam)=\frac{0+1}{3+3}&=\frac{1}{6}
\end{align*}
$$
**Ham**：
$$\begin{align*}
P(免费|Ham)=\frac{0+1}{3+3}&=\frac{1}{6}\\
P(优惠|Ham)=\frac{1+1}{3+3}&=\frac{1}{3}\\
P(你好|Ham)=\frac{2+1}{3+3}&=\frac{1}{2}
\end{align*}
$$
1. 用“朴素”条件独立假设计算后验
   1. 示例邮件：包含“证据”：**免费、你好**
    首先计算每个事件对应的“联合概率”$P(Y_j)\cdot\Pi_{k=1}^n(x_k|Y_j)$
    **Spam**事件：$$\begin{align*}
    &P(Spam)P(免费|Spam)P(你好|Spam)\\
    &=\frac{1}{2}\cdot\frac{1}{2}\cdot\frac{1}{6}\\
    &=\frac{1}{24}
    \end{align*}
    $$
    （使用对数：$\ln P(Spam)+\ln P(免费|Spam)+\ln P(你好|Spam)=-\ln24$）  
    **Ham**事件：$$\begin{align*}
    &P(Ham)P(免费|Ham)P(你好|Ham)\\
    &=\frac{1}{2}\cdot\frac{1}{6}\cdot\frac{1}{2}\\
    &=\frac{1}{24}
    \end{align*}
    $$
    （使用对数：$\ln P(Ham)+\ln P(免费|Ham)+\ln P(你好|Ham)=-\ln24$）  
    两者相等，说明有相等把握认为该邮件为Spam或Ham。
   2. 示例邮件：包含“证据”：**免费、优惠**
    首先计算每个事件对应的“联合概率”$P(Y_j)\cdot\Pi_{k=1}^n(x_k|Y_j)$
    **Spam**事件：$$\begin{align*}
    &P(Spam)P(免费|Spam)P(优惠|Spam)\\
    &=\frac{1}{2}\cdot\frac{1}{2}\cdot\frac{1}{3}\\
    &=\frac{1}{12}
    \end{align*}
    $$
    （使用对数：$\ln P(Spam)+\ln P(免费|Spam)+\ln P(优惠|Spam)=-\ln12$）  
    **Ham**事件：$$\begin{align*}
    &P(Ham)P(免费|Ham)P(优惠|Ham)\\
    &=\frac{1}{2}\cdot\frac{1}{6}\cdot\frac{1}{3}\\
    &=\frac{1}{36}
    \end{align*}
    $$
    （使用对数：$\ln P(Ham)+\ln P(免费|Ham)+\ln P(优惠|Ham)=-\ln36$）  
    $\frac{1}{12}>\frac{1}{36}$或$-\ln12>-\ln36$，表明最有可能是Spam。  

示例代码：
```matlab
X_train=[                   % 训练样本（每行代表一封邮件，每列代表一个关键词）
    1,      1,      0;  % Spam
    1,      0,      0;  % Spam
    0,      0,      1;  % Ham
    0,      1,      1;  % Ham
];%“免费”   “优惠”  “你好”
y_train=[1,1,0,0]';         % 标签：1表示垃圾邮件，0表示正常邮件
n_samples=length(y_train);
n_spam=sum(y_train==1);
n_ham=sum(y_train==0);      % 计算先验概率
P_spam=n_spam/n_samples;    % P(Spam)
P_ham=n_ham/n_samples;      % P(Ham)
alpha=1,m=3;                % 拉普拉斯平滑法计算似然概率
% 分别统计 Spam 和 Ham 类中每个特征的出现次数
spam_samples = X_train(y_train == 1, :);  % Spam类样本
ham_samples = X_train(y_train == 0, :);   % Ham类样本

% 计算各类别的总词数（分母 N(Y_j)）
N_spam = sum(sum(spam_samples));   % Spam类总词数 = 3
N_ham = sum(sum(ham_samples));     % Ham类总词数 = 3

% 计算每个特征在各类别中出现的次数（分子 N(X_i|Y_j)）
N_feat_spam = sum(spam_samples, 1);  % [2, 1, 0]
N_feat_ham = sum(ham_samples, 1);    % [0, 1, 2]

% 应用拉普拉斯平滑公式：P(X_i|Y_j) = (N(X_i|Y_j) + alpha) / (N(Y_j) + alpha*m)
P_feat_spam = (N_feat_spam + alpha) / (N_spam + alpha * m);  % [0.5, 0.333, 0.167]
P_feat_ham = (N_feat_ham + alpha) / (N_ham + alpha * m);     % [0.167, 0.333, 0.5]

% 测试邮件1：包含 [免费, 你好]
test_mail_1 = [1, 0, 1];  % 免费=是，优惠=否，你好=是
fprintf('测试邮件1：[免费, 你好]\n');

% 计算联合概率（非对数形式）
joint_spam_1 = P_spam * prod(P_feat_spam(test_mail_1 == 1));
joint_ham_1 = P_ham * prod(P_feat_ham(test_mail_1 == 1));

% 计算对数形式（防止数值下溢）
log_joint_spam_1 = log(P_spam) + sum(log(P_feat_spam(test_mail_1 == 1)));
log_joint_ham_1 = log(P_ham) + sum(log(P_feat_ham(test_mail_1 == 1)));

fprintf('  联合概率: Spam=%.4f, Ham=%.4f\n', joint_spam_1, joint_ham_1);
fprintf('  对数形式: Spam=%.4f, Ham=%.4f\n', log_joint_spam_1, log_joint_ham_1);
if joint_spam_1 > joint_ham_1
    fprintf('  → 预测结果: 垃圾邮件(Spam)\n');
elseif joint_spam_1 < joint_ham_1
    fprintf('  → 预测结果: 正常邮件(Ham)\n');
else
    fprintf('  → 预测结果: 无法判断（概率相等）\n');
end

fprintf('\n');

% 测试邮件2：包含 [免费, 优惠]
test_mail_2 = [1, 1, 0];  % 免费=是，优惠=是，你好=否
fprintf('测试邮件2：[免费, 优惠]\n');

joint_spam_2 = P_spam * prod(P_feat_spam(test_mail_2 == 1));
joint_ham_2 = P_ham * prod(P_feat_ham(test_mail_2 == 1));

log_joint_spam_2 = log(P_spam) + sum(log(P_feat_spam(test_mail_2 == 1)));
log_joint_ham_2 = log(P_ham) + sum(log(P_feat_ham(test_mail_2 == 1)));

fprintf('  联合概率: Spam=%.4f, Ham=%.4f\n', joint_spam_2, joint_ham_2);
fprintf('  对数形式: Spam=%.4f, Ham=%.4f\n', log_joint_spam_2, log_joint_ham_2);
if joint_spam_2 > joint_ham_2
    fprintf('  → 预测结果: 垃圾邮件(Spam)\n');
elseif joint_spam_2 < joint_ham_2
    fprintf('  → 预测结果: 正常邮件(Ham)\n');
else
    fprintf('  → 预测结果: 无法判断（概率相等）\n');
end
```
运行结果：
```
测试邮件1：[免费, 你好]
  联合概率: Spam=0.0417, Ham=0.0417
  对数形式: Spam=-3.1781, Ham=-3.1781
  → 预测结果: 无法判断（概率相等）

测试邮件2：[免费, 优惠]
  联合概率: Spam=0.0833, Ham=0.0278
  对数形式: Spam=-2.4849, Ham=-3.5835
  → 预测结果: 垃圾邮件(Spam)
```
与手动计算相吻合。
#### 5.应用场景
- 文本分类：垃圾邮件识别、情感分析、新闻分类
- 推荐系统：基于用户行为的兴趣分类
- 医疗诊断：根据症状初步判断疾病
- 信用评估：判断用户是否会违约