Files
Home-of-CS/content/post/temp_20260412/index.md
T
2026-04-23 13:39:28 +08:00

195 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "朴素贝叶斯算法 讲解及示例(课程作业)"
description:
date: 2026-04-12T22:10:40+08:00
image:
math:
license:
rooms:
- '书房'
hidden: false
comments: false
draft: false
---
### 朴素贝叶斯算法
#### 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.应用场景
- 文本分类:垃圾邮件识别、情感分析、新闻分类
- 推荐系统:基于用户行为的兴趣分类
- 医疗诊断:根据症状初步判断疾病
- 信用评估:判断用户是否会违约