朴素贝叶斯分类器公式推导与实现教程

朴素贝叶斯分类器公式推导与实现教程

一、朴素贝叶斯分类器基本概念

朴素贝叶斯分类器是一种基于贝叶斯定理与特征条件独立假设的分类方法。它之所以被称为”朴素”,是因为其假设特征之间是相互条件独立的,这一假设大大简化了计算复杂度。

朴素贝叶斯法通过训练数据集学习联合概率分布P(X, Y),然后基于此模型,对给定的输入x,利用贝叶斯定理求出后验概率最大的输出y

二、公式推导过程

2.1 条件概率与贝叶斯定理

首先回顾条件概率公式: $$P(B|A) = \frac{P(AB)}{P(A)}$$

由此可推导出贝叶斯定理: $$P(A|B) = \frac{P(B|A)P(A)}{P(B)}$$

成分 符号 名称 意义解释
更新后的信念 P(AB) 后验概率 在观察到新证据 B 之后,假设 A 为真的概率。这是我们最终想要求得的结果,它综合了我们先前的知识和新的证据。
当前证据的强度 P(BA) 似然概率 在假设 A 为真的条件下,观察到当前证据 B 的可能性有多大。它反映了证据与假设的匹配程度。
初始信念 P(A) 先验概率 在尚未观察到新证据 B 之前,我们对假设 A 为真的初始概率估计。这通常基于历史数据或领域知识。
证据的总体概率 P(B) 边缘概率/证据 证据 B 发生的总概率,通常通过考虑所有可能的情况(A 发生和 A 不发生)计算得出。它的作用是归一化,确保后验概率是一个有效的概率值(在0到1之间)。

在分类问题中,我们关心的是给定特征X情况下样本属于类别ck的概率: $$P(Y=c_k|X=x) = \frac{P(X=x|Y=c_k)P(Y=c_k)}{P(X=x)}$$

2.2 后验概率最大化准则

贝叶斯分类器的目标是最小化期望风险(做出平均损失最小的决策)。采用0-1损失函数时,对某个样本 x 进行分类的条件风险,就是将其误分类的概率: $$R(c_i | x) = \sum_{k=1}^{K} \lambda(c_i, c_k) P(c_k | x) = 1 - P(c_i | x)$$ 其中,λ(ci, ck)i=k 时为0,否则为1。

为了使总体风险最小化,我们需要对每个样本 x 逐个最小化其条件风险。这等价于最大化该样本属于正确类别的后验概率f(x) = arg minciR(ci|x) = arg minci[1 − P(ci|x)] = arg maxciP(ci|x) 因此,后验概率最大化准则实质上就是在0-1损失函数下的最优决策,它保证了期望风险最小化。这一深刻的等价关系奠定了该准则在分类问题中的理论基础。

2.3 特征条件独立性假设

直接计算P(X = x|Y = ck)面临组合爆炸问题(参数个数为$K\prod_{j=1}^{n}S_j$,K为类别数,Sj为第j个特征的可能的取值数)。为解决此问题,朴素贝叶斯引入了特征条件独立性假设

$$P(X=x|Y=c_k) = P(X^{(1)}=x^{(1)},...,X^{(n)}=x^{(n)}|Y=c_k) = \prod_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)$$

2.4 完整的朴素贝叶斯公式

将独立性假设代入贝叶斯公式: $$P(Y=c_k|X=x) = \frac{P(Y=c_k) \prod_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)}{\sum_{k} P(Y=c_k) \prod_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)}$$

由于分母对所有ck相同,朴素贝叶斯分类器可简化为: $$y = f(x) = argmax_{c_k} P(Y=c_k) \prod_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)$$

三、参数估计与平滑技术

3.1 极大似然估计

使用极大似然估计法估计先验概率和条件概率:

  • 先验概率:$P(Y=c_k) = \frac{\sum_{i=1}^{N} I(y_i=c_k)}{N}$,即用频率来估计概率
  • 条件概率:$P(X^{(j)}=a_{jl}|Y=c_k) = \frac{\sum_{i=1}^{N} I(x_i^{(j)}=a_{jl},y_i=c_k)}{\sum_{i=1}^{N} I(y_i=c_k)}$

3.2 拉普拉斯平滑

极大似然估计可能出现概率值为0的情况,解决方案是使用贝叶斯估计(拉普拉斯平滑)

$$P(Y=c_k) = \frac{\sum_{i=1}^{N} I(y_i=c_k) + \lambda}{N + K\lambda}$$

$$P(X^{(j)}=a_{jl}|Y=c_k) = \frac{\sum_{i=1}^{N} I(x_i^{(j)}=a_{jl},y_i=c_k) + \lambda}{\sum_{i=1}^{N} I(y_i=c_k) + S_j\lambda}$$

其中λ ≥ 0,常取λ = 1

四、Python实现示例

4.1 文本分类示例

下面是一个简单的朴素贝叶斯文本分类实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import numpy as np
from collections import defaultdict

class NaiveBayesClassifier:
def __init__(self, lambda_param=1):
self.lambda_param = lambda_param # 拉普拉斯平滑参数
self.prior_prob = {} # 先验概率 P(c)
self.cond_prob = {} # 条件概率 P(x|c)
self.classes = [] # 类别列表
self.feature_total = {} # 每个类别下的特征总数
self.vocabulary = set() # 所有出现过的特征集合

def fit(self, X, y):
"""训练模型"""
self.classes = list(set(y))
n_samples = len(y)
n_classes = len(self.classes)

# 计算先验概率(使用拉普拉斯平滑)
for c in self.classes:
count_c = sum(1 for label in y if label == c)
self.prior_prob[c] = (count_c + self.lambda_param) / (n_samples + n_classes * self.lambda_param)

# 统计特征频率
feature_counts = {c: defaultdict(int) for c in self.classes}
self.feature_total = {c: 0 for c in self.classes}

for i in range(n_samples):
features = X[i]
label = y[i]
for feature in features:
feature_counts[label][feature] += 1
self.feature_total[label] += 1
self.vocabulary.add(feature)

# 计算条件概率(使用拉普拉斯平滑)
vocab_size = len(self.vocabulary)
for c in self.classes:
self.cond_prob[c] = {}
total_features_c = self.feature_total[c]
for feature in self.vocabulary:
count_feature = feature_counts[c][feature] # 如果feature没出现过,count_feature为0
self.cond_prob[c][feature] = (count_feature + self.lambda_param) / \
(total_features_c + vocab_size * self.lambda_param)

def predict(self, X):
"""预测新样本"""
predictions = []
vocab_size = len(self.vocabulary)

for sample in X:
max_prob = -float('inf')
predicted_class = None

for c in self.classes:
log_prob = np.log(self.prior_prob[c])

for feature in sample:
if feature in self.cond_prob[c]:
log_prob += np.log(self.cond_prob[c][feature])
else:
# 处理未出现的特征(使用拉普拉斯平滑)
total_features_c = self.feature_total[c]
prob = self.lambda_param / (total_features_c + vocab_size * self.lambda_param)
log_prob += np.log(prob)

if log_prob > max_prob:
max_prob = log_prob
predicted_class = c

predictions.append(predicted_class)
return predictions

# 示例数据集
def create_dataset():
"""创建简单的文本分类数据集"""
X = [
['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
['stop', 'posting', 'stupid', 'worthless', 'garbage'],
['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']
]
y = [0, 1, 0, 1, 0, 1]
return X, y

# 使用示例
X_train, y_train = create_dataset()
nb_classifier = NaiveBayesClassifier(lambda_param=1)
nb_classifier.fit(X_train, y_train)

# 测试新样本
test_sample = [['love', 'my', 'dalmation']]
prediction = nb_classifier.predict(test_sample)
print(f"预测结果: {prediction[0]}") # 输出0(非侮辱性)

4.2 使用scikit-learn实现

对于实际应用,推荐使用scikit-learn库中的朴素贝叶斯实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from sklearn.naive_bayes import MultinomialNB, GaussianNB, BernoulliNB
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report

# 创建文本数据向量化表示
vectorizer = CountVectorizer()
X_vectorized = vectorizer.fit_transform([' '.join(doc) for doc in X_train])

# 使用多项式朴素贝叶斯(适用于文本数据)
mnb = MultinomialNB(alpha=1.0) # alpha对应拉普拉斯平滑参数
mnb.fit(X_vectorized, y_train)

# 预测
test_text = [' '.join(['love', 'my', 'dalmation'])]
test_vectorized = vectorizer.transform(test_text)
prediction = mnb.predict(test_vectorized)
print(f"Scikit-learn预测结果: {prediction[0]}")

# 评估模型
y_pred = mnb.predict(X_vectorized)
accuracy = accuracy_score(y_train, y_pred)
print(f"模型准确率: {accuracy:.2f}")

五、不同数据类型的处理

朴素贝叶斯有多种变体,适用于不同类型的数据:

  1. 高斯朴素贝叶斯:假设特征服从正态分布,适用于连续特征
  2. 多项式朴素贝叶斯:适用于离散特征(如文本分类中的词频)
  3. 伯努利朴素贝叶斯:适用于二值特征

六、特征条件独立性的影响

6.1 假设的合理性

特征条件独立性假设在现实中往往不成立,例如在文本分类中,词语之间通常存在关联。但这假设带来了两个重要好处:

  1. 计算简化:将O(2n)的参数空间减少到O(n)
  2. 数据效率:减少了对大量训练数据的需求

6.2 实际影响

尽管有关联性假设,朴素贝叶斯在实践中的表现却经常出人意料地好,原因包括:

  • 分类决策只依赖于概率的排序而非精确值
  • 当特征相关性较小时,性能接近最优贝叶斯分类器
  • 对文本分类等许多实际任务效果良好

七、总结

朴素贝叶斯分类器通过以下步骤实现: 1. 基于训练数据估计先验概率P(Y = ck)和条件概率P(X(j)|Y = ck) 2. 对给定的新实例x,计算每个类别的后验概率分子$P(Y=c_k) \prod_{j=1}^{n} P(X^{(j)}=x^{(j)}|Y=c_k)$ 3. 选择使后验概率最大的类别作为预测结果

虽然其”朴素”的独立性假设在现实中往往不成立,但朴素贝叶斯仍因其简单高效、需要少量训练数据、对缺失数据不敏感等优点,在实践中得到广泛应用,特别是在文本分类和垃圾邮件过滤等领域。

通过本教程,您应该能够完整理解朴素贝叶斯的数学原理、推导过程和实践应用。建议结合具体数据集进一步练习,以加深理解。