我用一个 「垃圾邮件分类」 的例子来讲解朴素贝叶斯算法,保证你轻松理解原理和实现!
📧 例子背景
假设你是邮箱系统的开发者,需要自动判断一封邮件是正常邮件还是垃圾邮件。已知以下历史数据:
邮件内容 | 是否垃圾邮件 |
---|---|
"免费领取奖品" | 是 |
"明天开会通知" | 否 |
"赢取百万奖金" | 是 |
"项目进度报告" | 否 |
现在收到一封新邮件:"免费领取百万奖金",如何用朴素贝叶斯判断它是否是垃圾邮件?
📚 朴素贝叶斯原理解析
1. 核心思想
“通过历史数据计算概率,选择概率更高的类别”
朴素贝叶斯会计算:
-
P(垃圾邮件|邮件内容):在已知邮件内容条件下,它是垃圾邮件的概率。
-
P(正常邮件|邮件内容):在已知邮件内容条件下,它是正常邮件的概率。
最终选择概率更高的类别。
2. 关键假设
“朴素” = 特征之间相互独立(实际不一定成立,但简化计算效果好)。
比如假设邮件中“免费”和“奖金”两个词的出现互不影响。
3. 计算步骤(以新邮件“免费领取百万奖金”为例)
-
统计历史数据中的概率
-
P(垃圾邮件) = 2/4 = 0.5
-
P(正常邮件) = 2/4 = 0.5
-
-
计算词的条件概率(拉普拉斯平滑避免零概率)
-
P("免费"|垃圾邮件) = (1+1)/(2+4) = 2/6 ≈ 0.33
(垃圾邮件中“免费”出现1次,总垃圾邮件词数2,总唯一词数4) -
P("百万"|垃圾邮件) = (1+1)/(2+4) = 2/6 ≈ 0.33
-
P("免费"|正常邮件) = (0+1)/(2+4) = 1/6 ≈ 0.17
-
P("百万"|正常邮件) = (0+1)/(2+4) = 1/6 ≈ 0.17
-
-
计算联合概率
-
P(垃圾邮件|内容) ∝ P(垃圾邮件) × P("免费"|垃圾邮件) × P("百万"|垃圾邮件) ≈ 0.5 × 0.33 × 0.33 ≈ 0.054
-
P(正常邮件|内容) ∝ P(正常邮件) × P("免费"|正常邮件) × P("百万"|正常邮件) ≈ 0.5 × 0.17 × 0.17 ≈ 0.014
-
-
判断结果
-
0.054(垃圾邮件) > 0.014(正常邮件) → 判定为垃圾邮件!
-
🛠️ 代码实现(Python)
用 scikit-learn
快速实现:
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
# 1. 准备数据
emails = ["免费 领取 奖品", "明天 开会 通知", "赢取 百万 奖金", "项目 进度 报告"]
labels = np.array([1, 0, 1, 0]) # 1=垃圾邮件, 0=正常邮件
# 2. 文本转词频向量
vectorizer = CountVectorizer(token_pattern=r'\b\w+\b')
X = vectorizer.fit_transform(emails)
print("词表:", vectorizer.get_feature_names_out()) # 输出所有分词
# 3. 训练朴素贝叶斯模型
model = MultinomialNB(alpha=1) # alpha=1是拉普拉斯平滑
model.fit(X, labels)
# 4. 预测新邮件
new_email = ["免费 领取 百万 奖金"]
new_vec = vectorizer.transform(new_email)
prediction = model.predict(new_vec)
print("预测结果:", "垃圾邮件" if prediction[0] == 1 else "正常邮件")
输出结果:
词表: ['开会' '奖品' '免费' '百万' '报告' '明天' '进度' '赢取' '领取'] 预测结果: 垃圾邮件
🌟 关键细节
-
拉普拉斯平滑
-
防止未出现的词导致概率为0(如正常邮件中从未出现“百万”)。
-
代码中
alpha=1
就是平滑参数。
-
-
文本处理
-
中文需分词(示例中用空格分隔,实际可用
jieba
分词)。 -
CountVectorizer
将文本转为词频向量。
-
-
适用场景
-
文本分类(垃圾邮件、情感分析)。
-
小数据集、高维特征(即使特征多也能高效计算)。
-
🤔 为什么叫“朴素”?
因为假设所有词相互独立(实际“免费”和“奖金”常一起出现),但实际效果仍不错!
总结:朴素贝叶斯像一个快速的概率计算器,通过历史数据“猜”新数据的类别。试试用它处理你的文本数据吧! 🚀