第22篇:朴素贝叶斯------一个看起来很朴素,但在很多场景里 surprisingly 好用的模型
学到这里,你已经接触过不少机器学习模型了。
有的模型喜欢画边界,比如 SVM。
有的模型喜欢一步步分裂,比如决策树。
有的模型喜欢找邻居,比如 KNN。
还有一些模型,是靠很多棵树一起投票或者一棵棵树接力纠错。
那朴素贝叶斯呢?
它的思路和前面这些模型都不太一样。
它不是直接去学一条边界,也不是去找最优分裂规则,而是换了一个角度问问题:
如果一个样本属于某个类别,那么它身上的这些特征,出现的概率大概会是什么样?
再说得更直白一点:
看到一个新样本时,模型会分别站在不同类别的角度去想:
"如果它真属于这一类,那它现在这些特征值,像不像这一类会有的样子?"
最后谁更像,就判给谁。
这就是朴素贝叶斯最核心的味道。
它名字里有"朴素"两个字,不是贬义,而是因为它做了一个非常强、也非常朴素的假设。
正是这个假设,让它简单、快、经常 surprisingly 有用,尤其是在文本分类这种场景里。
1. 先别急着看公式,先看一个"垃圾邮件分类"的直觉例子
假设你现在要做一个最经典的任务:
判断一封邮件是不是垃圾邮件。
你观察了一批历史邮件后,发现一些很常见的现象:
- 垃圾邮件里经常出现"免费""中奖""限时""点击领取"
- 正常邮件里更容易出现"会议""合同""进度""同事""附件"
现在来了一封新邮件,里面出现了这些词:
- 免费
- 点击
- 领取
那你会怎么判断?
很自然的一种想法就是:
- 如果这封邮件是垃圾邮件,那么这些词出现的概率高不高?
- 如果这封邮件是正常邮件,那么这些词出现的概率高不高?
如果站在"垃圾邮件"的角度看,它特别像。
而站在"正常邮件"的角度看,又不太像。
那它大概率就是垃圾邮件。
你看,这就是朴素贝叶斯的基本逻辑:
不是直接问"边界在哪",而是问"这个样本更像哪一类生成出来的"。
2. 朴素贝叶斯到底在算什么
如果稍微正式一点来讲,朴素贝叶斯在比较的是:
给定当前特征,样本属于某个类别的概率。
也就是:
P(y∣x) P(y \mid x) P(y∣x)
这里:
- yyy 表示类别,比如"垃圾邮件"或"正常邮件"
- xxx 表示特征,比如邮件中出现的词、频率、长度等等
也就是说,模型最终想知道的是:
在看到这些特征以后,这个样本属于某个类别的概率到底有多大?
而这一步背后用到的,就是贝叶斯公式。
3. 贝叶斯公式先别怕,它其实就是一种"反过来推"的方法
贝叶斯公式写出来是:
P(y∣x)=P(x∣y)P(y)P(x) P(y \mid x) = \frac{P(x \mid y)P(y)}{P(x)} P(y∣x)=P(x)P(x∣y)P(y)
第一次看到这个式子,很容易有点烦。
但你先不用急着盯符号,先把它翻译成人话。
这个式子在说的是:
后验概率 = 似然 × 先验 / 证据
如果继续翻译成人话:
- P(y∣x)P(y \mid x)P(y∣x):看到这些特征以后,它属于类别 yyy 的概率
- P(x∣y)P(x \mid y)P(x∣y):如果它本来就是类别 yyy,那出现这些特征的概率
- P(y)P(y)P(y):这个类别本来就有多常见
- P(x)P(x)P(x):这些特征本身整体出现的概率
你可以把它理解成:
一个样本像不像某一类,不只取决于它的特征在这一类里常不常见,
还取决于这一类本来是不是常见。
比如"垃圾邮件"本来就特别少,那你不能随便看到一个"免费"就断言它一定是垃圾邮件。
你还得把这个类别本来的基线概率考虑进去。
这就是朴素贝叶斯里的"贝叶斯"部分。
4. 为什么叫"朴素"
到这里,关键来了。
如果你真要严格去算:
P(x∣y) P(x \mid y) P(x∣y)
也就是"在类别 yyy 下,所有这些特征一起出现的概率",
通常会很难。
为什么?
因为多个特征之间往往不是独立的。
比如一封垃圾邮件里:
- "免费"
- "点击"
- "领取"
这几个词往往不是彼此毫无关系地出现,它们常常一起出现。
如果你要完整建模这些相关性,问题会变得很复杂。
这时候朴素贝叶斯做了一件非常大胆、也非常朴素的事:
它假设在给定类别的前提下,各个特征彼此独立。
也就是说:
如果邮件已经确定是垃圾邮件,
那"免费"这个词的出现,和"点击"这个词的出现,就先假设它们互不影响。
于是:
P(x1,x2,...,xn∣y)=P(x1∣y)P(x2∣y)⋯P(xn∣y) P(x_1, x_2, \dots, x_n \mid y)= P(x_1 \mid y)P(x_2 \mid y)\cdots P(x_n \mid y) P(x1,x2,...,xn∣y)=P(x1∣y)P(x2∣y)⋯P(xn∣y)
这就是"朴素"两个字的来源。
这个假设在现实里经常并不完全成立。
但神奇的地方就在于:
虽然这个假设很强、很粗糙,朴素贝叶斯在很多任务里依然很好用。
尤其是文本分类。
5. 为什么这个假设明明不完全对,模型却还能用
这是很多人第一次接触朴素贝叶斯时最想问的一个问题。
既然特征独立这个假设明显不严格,那为什么它还能工作?
原因有几个。
第一,它虽然假设得粗,但方向经常没错
很多时候,即便特征不独立,它依然能大致判断:
- 哪些特征更偏向某一类
- 哪些特征出现时某一类更可能
换句话说,它对"趋势"的捕捉往往是有用的。
第二,它不是在精确模拟世界,而是在做分类
朴素贝叶斯不一定把概率估得特别完美,
但很多时候它只需要把不同类别的相对大小比较出来,就足够做分类了。
第三,它特别适合高维稀疏数据
像文本这种场景:
- 特征特别多
- 大部分特征大部分时候都不出现
- 但每个词对类别都有一点提示作用
这种时候,朴素贝叶斯反而常常很顺手。
所以它很像一种"简单但够用"的模型。
不是每个地方都最强,但在合适的任务里,它非常高效。
6. 朴素贝叶斯最经典的使用场景:文本分类
说到朴素贝叶斯,最经典的应用几乎一定会提到:
- 垃圾邮件识别
- 文本情感分类
- 新闻分类
- 评论分类
为什么它在文本里这么常见?
因为文本天然可以表示成很多"词是否出现"或者"词出现多少次"的特征。
比如一条评论:
这个产品太好用了,物流也很快
你可以把它转成很多词特征:
- "好用"出现了吗
- "物流"出现了吗
- "快"出现了吗
- "差"出现了吗
- "退货"出现了吗
这类表示很适合朴素贝叶斯。
因为模型可以直接统计:
- 在正面评论中,"好用"出现得多不多
- 在负面评论中,"退货"出现得多不多
- 在垃圾邮件里,"免费"出现得多不多
文本一旦转成这种稀疏高维特征,朴素贝叶斯就会显得特别自然。
7. 朴素贝叶斯有哪些常见变体
朴素贝叶斯不是只有一种。
实际里你会经常看到几种常见版本。
1)Gaussian Naive Bayes
适合连续数值特征。
它会假设:
每个特征在某一类下服从高斯分布(正态分布)。
比如:
- 某类样本下,收入大概是一个均值和方差固定的分布
- 另一类样本下,又是另一个均值和方差
所以它适合那种数值型特征比较多的问题。
2)Multinomial Naive Bayes
特别适合词频类特征。
比如一封邮件里,某个词出现了几次,
某篇文章里某个词计数是多少。
文本分类里非常常见。
3)Bernoulli Naive Bayes
适合"出现/不出现"这种二值特征。
比如:
- 某个词是否出现
- 某个按钮是否点击
- 某个行为是否发生
它更关心的是"有没有",而不是"出现了多少次"。
你只需要知道:
朴素贝叶斯不是一个死模型,它会根据特征类型换不同版本。
这就够了。
8. 一个非常小的例子:怎么用"词"来判断邮件类型
假设你现在只有两个类别:
- 垃圾邮件
- 正常邮件
历史统计里你看到:
垃圾邮件中
- "免费"出现概率高
- "中奖"出现概率高
- "点击"出现概率高
正常邮件中
- "会议"出现概率高
- "附件"出现概率高
- "合同"出现概率高
现在来了一封邮件,特征是:
- 免费 = 1
- 点击 = 1
- 附件 = 0
- 会议 = 0
朴素贝叶斯会分别去算:
- 如果它是垃圾邮件,这些特征一起出现的概率大概是多少
- 如果它是正常邮件,这些特征一起出现的概率大概是多少
最后谁更大,就判给谁。
这其实就是一个"根据词的共现习惯来反推类别"的过程。
9. 用一个简单代码例子看看
下面给一个非常典型的朴素贝叶斯文本分类小例子,用 scikit-learn 就能直接跑。
python
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
# 训练文本
texts = [
"免费 中奖 点击 领取",
"限时 优惠 免费",
"会议 通知 附件",
"项目 进度 汇报",
"免费 礼品 点击",
"合同 已发送 请查收"
]
# 标签:1=垃圾邮件,0=正常邮件
labels = [1, 1, 0, 0, 1, 0]
# 文本转词频特征
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(texts)
# 建立模型
model = MultinomialNB()
model.fit(X, labels)
# 预测新文本
new_texts = [
"免费 点击 领取",
"会议 附件 通知"
]
X_new = vectorizer.transform(new_texts)
pred = model.predict(X_new)
print("预测结果:", pred)
这段代码里发生了几件事:
第一步:把文本变成词频特征
CountVectorizer() 会把文本转成"每个词出现了几次"的向量。
第二步:用 MultinomialNB 建模
这就是多项式朴素贝叶斯,很适合处理词频。
第三步:预测新文本
模型会根据训练时统计出来的"不同类别下词的出现规律",来判断新文本更像哪一类。
这个例子虽然小,但非常适合博客读者,因为一下就能看懂它在干嘛。
10. 为什么朴素贝叶斯训练得这么快
这一点也是它很大的优点。
很多模型训练时要反复迭代:
- 算梯度
- 更新参数
- 多轮优化
但朴素贝叶斯通常不太一样。
它做的事情更像是在统计:
- 每个类别出现了多少次
- 每个特征在不同类别下出现得多不多
- 类别先验概率是多少
也就是说,它的"训练"更多是统计而不是复杂优化。
所以它通常:
- 训练快
- 推理快
- 对小数据也比较友好
- 很适合先做 baseline
这也是为什么很多时候你做文本分类,哪怕后面会上更复杂的模型,也很值得先跑一个朴素贝叶斯当基线。
11. 朴素贝叶斯的优点到底在哪
第一,简单
模型结构清楚,思路也清楚。
第二,快
训练和预测都很快。
第三,对高维稀疏数据友好
这点在文本任务里尤其重要。
第四,小数据时也能有不错表现
不像有些模型非常依赖大量样本。
第五,经常适合作为 baseline
它不一定总是最强,但很适合快速验证一个任务是否能学到东西。
12. 但它也有非常明显的局限
朴素贝叶斯不是万金油,它有很明显的短板。
第一,独立性假设太强
现实里很多特征并不独立,这会限制模型表达能力。
第二,概率估计有时比较粗
它能做分类,但输出的概率未必非常可信。
第三,对特征表示方式比较敏感
尤其在文本里,你怎么分词、怎么表示、用词频还是 TF-IDF,都会影响结果。
第四,复杂关系它学不出来
如果任务需要捕捉很复杂的非线性关系,朴素贝叶斯就会显得比较吃力。
所以你可以说:
朴素贝叶斯不是那种"什么都能学"的模型,
但在它擅长的地盘上,它很高效,也经常比你想象中更有竞争力。
13. 它和逻辑回归有什么区别
逻辑回归
是判别模型。
它直接学:
P(y∣x) P(y \mid x) P(y∣x)
也就是直接学"给定特征,类别概率是多少"。
朴素贝叶斯
更偏生成式思路。
它会先看:
P(x∣y) P(x \mid y) P(x∣y)
再通过贝叶斯公式去反推:
P(y∣x) P(y \mid x) P(y∣x)
所以它们不只是"两个分类器",而是代表了两种不同建模角度。
逻辑回归更像是在直接学"怎么分";
朴素贝叶斯更像是在学"每一类通常长什么样"。
15. 这一篇真正想让读者记住的,不是公式,而是这个"判断方式"
如果你让我压缩成最值得带走的一句话,我会说:
朴素贝叶斯的核心不是复杂,而是它会站在每个类别的角度,去问"这个样本像不像这一类会生成出来的样子"。
然后它为了把这件事算得简单,做了一个很强但很实用的假设:
给定类别后,特征彼此独立。
这个假设不完美,但很多时候够用。
尤其在文本分类里,它依然是一个很经典的模型。