WARNING
🧪 Beta公测版本提示:教程主体已完成,正在优化细节,欢迎大家提Issue反馈问题或建议。
ml03 朴素贝叶斯与贝叶斯网络 — demo.py 代码详解
运行方式
bash
cd docs/ml/classic/naive-bayes/code
python demo.py代码逐段详解
第1步:GaussianNB — 从对角协方差说起
python
class GaussianNB:
def fit(self, X, y):
for idx, c in enumerate(self.classes_):
X_c = X[y == c]
self.means_[idx] = np.mean(X_c, axis=0)
self.vars_[idx] = np.var(X_c, axis=0) + self.var_smoothing与 ml02 中完整高斯贝叶斯的区别:这里只需要估计各特征独立的均值和方差,而不需要协方差矩阵。
参数数量对比:
- 完整高斯贝叶斯(
cov_type='full'):个均值 + 个协方差元素 - 朴素贝叶斯(GaussianNB):
个均值 + 个方差 = 仅
对于
对数似然计算利用条件独立假设:
python
log_lik = -0.5 * (np.log(2 * np.pi * var) + ((X - mu) ** 2) / var)
log_lik_sum = np.sum(log_lik, axis=1) # sum over features在独立假设下,联合对数似然 = 各特征对数似然之和:
而完整高斯贝叶斯的对数似然需要计算马氏距离
第2步:MultinomialNB — 文本分类的利器
python
class MultinomialNB:
def fit(self, X, y):
count_c = np.sum(X_c, axis=0) # 每个特征的总计数
total_count = np.sum(count_c)
prob_c = (count_c + self.alpha) / (total_count + self.alpha * n_features)
self.feature_log_prob_[idx] = np.log(prob_c)MultinomialNB 的核心估计公式为:
其中:
:类别 中词 出现的总次数 :词汇表大小 :拉普拉斯平滑参数
代码中将特征概率取对数存储(np.log(prob_c)),因为预测时需要的是对数概率的加权和:
python
def predict(self, X):
log_joint = X @ self.feature_log_prob_.T + np.log(self.priors_)
return self.classes_[np.argmax(log_joint, axis=1)]这里 $$X$$ 与 $$\text{feature_log_prob_}^{T}$$ 的矩阵乘法(X @ feature_log_prob_.T)一次性完成了所有样本的加权和计算:
第3步:拉普拉斯平滑的可视化
三种平滑强度的效果对比:
python
alphas = [0.001, 1.0, 5.0](接近 MLE):训练中未出现的特征概率接近 0,过拟合 (拉普拉斯平滑):每个特征至少有 的概率,不过度自信 (强平滑):先验信息过强,所有人的概率都接近均匀分布,欠拟合
第4步:垃圾邮件检测
使用模拟的垃圾邮件/正常邮件数据集(20 个词,500 封邮件),展示 MultinomialNB 的实际效果。自定义实现的结果应与 sklearn MultinomialNB 完全一致(因为两者使用了完全相同的公式)。
第5步:模型对比 — 特征类型决定最佳选择
最后一个实验对比了 GaussianNB 和 MultinomialNB 在两种数据集上的表现:
- 连续特征数据:GaussianNB 占优(因为 MultinomialNB 不适合取负值或小数的特征)
- 计数特征数据:MultinomialNB 占优(因为数据生成过程与多项分布假设吻合)
关键教训:朴素贝叶斯变体的选择应由特征的类型决定,而非算法本身的"好坏"——每个变体各有其适用场景。
关键概念速查表
| 概念 | 数学形式 | 代码位置 | 关键说明 |
|---|---|---|---|
| 条件独立 | _log_prob() | 参数 | |
| GaussianNB 似然 | GaussianNB._log_prob() | 对角协方差 | |
| MultinomialNB 估计 | MultinomialNB.fit() | 拉普拉斯平滑 | |
| 平滑参数 | self.alpha | ||
| 零概率问题 | 避免用 alpha | 平滑是必须的 | |
| 加权和预测 | MultinomialNB.predict() | 矩阵乘法一次完成 |
源码位置
clone 后打开(相对仓库根目录):
docs/ml/classic/naive-bayes/code/demo.py