
scikit-learn 朴素贝叶斯分类器全解五种算法的原理、参数与源码实现【免费下载链接】scikit-learnscikit-learn: machine learning in Python项目地址: https://gitcode.com/gh_mirrors/sc/scikit-learn朴素贝叶斯Naive Bayes是 scikit-learn 中最经典的监督学习算法族之一它以贝叶斯定理为基础借助特征条件独立的朴素假设将复杂的高维联合概率估计拆解为一维分布的独立估计从而在文本分类、垃圾邮件过滤等场景中兼具极快的训练速度与出色的效果。本文以 用户指南 naive_bayes.rst 为骨架结合 naive_bayes.py 的源码实现与 测试用例 的验证逻辑系统讲解 GaussianNB、MultinomialNB、ComplementNB、BernoulliNB、CategoricalNB 五种朴素贝叶斯变体的数学原理、全部核心参数、可运行的代码示例以及利用partial_fit进行大规模流式训练的实战方案帮助读者在真实项目中快速选型并正确使用。朴素贝叶斯从贝叶斯定理到分类规则朴素贝叶斯方法是一组基于贝叶斯定理、同时带有朴素特征独立性假设的监督学习算法。给定类别变量 $y$ 与特征向量 $x_1, \dots, x_n$贝叶斯定理给出如下关系$$P(y \mid x_1, \dots, x_n) \frac{P(y), P(x_1, \dots, x_n \mid y)}{P(x_1, \dots, x_n)}$$直接估计 $P(x_1, \dots, x_n \mid y)$ 在特征维度较高时几乎不可行。朴素假设主张给定类别 $y$ 时任意一对特征之间条件独立即对所有的 $i$ 有$$P(x_i \mid y, x_1, \dots, x_{i-1}, x_{i1}, \dots, x_n) P(x_i \mid y)$$于是上式可以简化为$$P(y \mid x_1, \dots, x_n) \frac{P(y) \prod_{i1}^{n} P(x_i \mid y)}{P(x_1, \dots, x_n)}$$由于给定输入时 $P(x_1, \dots, x_n)$ 是常数分类可以等价地依据如下规则$$P(y \mid x_1, \dots, x_n) \propto P(y) \prod_{i1}^{n} P(x_i \mid y)$$$$\hat{y} \arg\max_y P(y) \prod_{i1}^{n} P(x_i \mid y)$$其中先验 $P(y)$ 与条件概率 $P(x_i \mid y)$ 通过最大后验估计Maximum A Posteriori, MAP得到前者即类别 $y$ 在训练集中的相对频率。尽管朴素假设看上去过于简化朴素贝叶斯分类器在众多真实场景尤其是文档分类与垃圾邮件过滤中表现相当出色且只需要很少的训练数据即可估计所需参数。理论上它为什么有效、对哪些类型的数据有效可参见文档中引用的 H. Zhang (2004) 论文《The optimality of Naive Bayes》Proc. FLAIRS。从算法工程角度看朴素贝叶斯还有两个突出的优点速度快相比更精细的模型朴素贝叶斯学习器与分类器可以做到极快因为类别条件特征分布的解耦使得每个分布可以独立地作为一维分布估计从而缓解了维度灾难curse of dimensionality带来的问题。概率输出不可轻信朴素贝叶斯虽然是合格的分类器但公认是糟糕的概率估计器predict_proba输出的概率值不应过度解读。这一点在源码中也有体现——_BaseDiscreteNB的__sklearn_tags__中显式标注了tags.classifier_tags.poor_score True见 naive_bayes.py告知下游工具链该分类器的分数输出质量有限。五种朴素贝叶斯分类器的主要区别正在于它们对 $P(x_i \mid y)$ 的分布假设不同下面逐一展开。GaussianNB连续特征的高斯朴素贝叶斯GaussianNB 实现了针对连续特征的高斯朴素贝叶斯算法假设特征的似然服从高斯分布$$P(x_i \mid y) \frac{1}{\sqrt{2\pi\sigma^2_y}} \exp\left(-\frac{(x_i - \mu_y)^2}{2\sigma^2_y}\right)$$参数 $\mu_y$ 与 $\sigma_y$ 使用最大似然估计得到。经典使用示例Iris 数据集用户指南给出了一个可直接运行的完整示例 from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.naive_bayes import GaussianNB X, y load_iris(return_X_yTrue) X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.5, random_state0) gnb GaussianNB() y_pred gnb.fit(X_train, y_train).predict(X_test) print(Number of mislabeled points out of a total %d points : %d ... % (X_test.shape[0], (y_test ! y_pred).sum())) Number of mislabeled points out of a total 75 points : 475 个测试点中仅 4 个被误分类展示了高斯朴素贝叶斯在经典小规模数据集上的实用表现。核心参数与数值稳定性从源码的参数约束naive_bayes.py看GaussianNB只有两个构造参数priorsarray-like默认None各类别的先验概率。若指定则先验不再依据数据调整在_partial_fit中会校验先验数量与类别数一致、求和为 1、且非负naive_bayes.py。若为None则用class_count_ / sum(class_count_)计算经验先验naive_bayes.py。var_smoothingfloat默认1e-9自 0.20 版本引入将所有特征中最大方差的一部分加到各特征方差上以保证计算稳定性。源码中对应self.epsilon_ self.var_smoothing * xp.max(xp.var(X, axis0))naive_bayes.py并在训练结束后统一加回var_。该设计用于应对特征间方差比过小导致数值误差的问题。训练完成后可用的属性包括class_count_每类样本数、class_prior_每类概率、classes_类别标签、theta_每类每特征的均值、var_每类每特征的方差、epsilon_方差加性增量、n_features_in_与feature_names_in_。联合对数似然的计算GaussianNB._joint_log_likelihood逐类累加log P(y) log P(x|y)naive_bayes.pyjointi xp.log(self.class_prior_[i]) n_ij -0.5 * xp.sum(xp.log(2.0 * xp.pi * self.var_[i, :])) n_ij n_ij - 0.5 * xp.sum(((X - self.theta_[i, :]) ** 2) / (self.var_[i, :]), axis1)预测时直接对联合对数似然取argmax得到类别naive_bayes.pypredict_proba则通过 softmax 归一化predict_log_proba减去_logsumexp后再取指数见 naive_bayes.py。在线均值和方差更新GaussianNB支持通过partial_fit在线更新模型参数。其静态方法_update_mean_variance实现了 Chan, Golub 与 LeVequeStanford CS 技术报告 STAN-CS-79-773描述的均值/方差在线合并算法naive_bayes.py利用离差平方和ssd合并公式total_mu (n_new * new_mu n_past * mu) / n_total old_ssd n_past * var new_ssd n_new * new_var total_ssd old_ssd new_ssd (n_new * n_past / n_total) * (mu - new_mu) ** 2 total_var total_ssd / n_total实现单遍、数值稳定的增量统计且支持sample_weight带权重时新块的均值与方差改用加权平均计算。对应的测试test_gnb_partial_fit与test_gnb_check_update_with_no_data覆盖了增量拟合与空批次等边界情况test_naive_bayes.py。MultinomialNB文本分类经典的多项式朴素贝叶斯MultinomialNB 针对多项式分布数据实现朴素贝叶斯是文本分类的两大经典朴素贝叶斯变体之一。此时数据通常表示为词向量计数tf-idf 向量在实践中同样效果良好。每个类别 $y$ 由参数向量 $\theta_y (\theta_{y1}, \dots, \theta_{yn})$ 刻画其中 $n$ 是特征数文本场景即词典大小$\theta_{yi}$ 表示类别 $y$ 的样本中出现特征 $i$ 的概率 $P(x_i \mid y)$。$\theta_y$ 通过平滑版最大似然即相对频率计数估计$$\hat{\theta}{yi} \frac{N{yi} \alpha}{N_y \alpha n}$$其中 $N_{yi} \sum_{x \in T} x_i$ 是特征 $i$ 在训练集 $T$ 中所有类别 $y$ 样本里出现的总次数$N_y \sum_{i1}^{n} N_{yi}$ 是类别 $y$ 全部特征的总计数。平滑先验 $\alpha \ge 0$ 用来处理训练样本中未出现的特征避免后续计算出现零概率$\alpha 1$ 称为Laplace 平滑Laplace smoothing$\alpha 1$ 称为Lidstone 平滑Lidstone smoothing。参数详解MultinomialNB继承自_BaseDiscreteNB其参数约束定义在 naive_bayes.py参数默认值含义alpha1.0加性Laplace/Lidstone平滑参数可以是 float 或 shape 为(n_features,)的数组逐特征平滑设置alpha0且force_alphaTrue可关闭平滑force_alphaTrue1.2 引入1.4 起默认改为True若为False且alpha 1e-10则将 alpha 强制置为1e-10以避免数值错误为True时保持原值alpha过小可能引起数值问题fit_priorTrue是否学习类别先验概率为False时使用均匀先验class_priorNone类别先验概率若指定则不再依据数据调整_check_alpha方法的逻辑naive_bayes.py值得注意当alpha是数组时要求其长度等于n_features_in_且所有值必须非负若最小alpha小于1e-10且force_alphaFalse会发出警告并自动抬升到1e-10。对应的参数校验测试见test_alpha与test_alpha_vectortest_naive_bayes.py。源码层面的实现要点输入必须是非负数据_count中调用check_non_negative(X, MultinomialNB (input X))naive_bayes.py与__sklearn_tags__中tags.input_tags.positive_only True的标记一致。统计计数使用safe_sparse_dot(Y.T, X)累加feature_count_支持稀疏输入_check_X中accept_sparsecsr。平滑后的对数概率feature_log_prob_ log(feature_count_ alpha) - log(sum)naive_bayes.py。预测阶段退化为一次稀疏矩阵乘法加先验safe_sparse_dot(X, feature_log_prob_.T) class_log_prior_naive_bayes.py这正是它极快的原因之一。ComplementNB面向不平衡数据的互补朴素贝叶斯ComplementNBCNB0.20 版本引入是标准多项式朴素贝叶斯MNB的改进版特别适合不平衡数据集。其核心思想是使用每个类别补集complement的统计量来计算模型权重。CNB 的提出者Rennie 等人通过实验表明CNB 的参数估计比 MNB 更稳定且在文本分类任务上经常以明显优势胜过 MNB。权重计算过程CNB 权重的计算过程如下公式见用户指南Weights calculation下拉块$$\hat{\theta}{ci} \frac{\alpha_i \sum{j:y_j \neq c} d_{ij}}{\alpha \sum_{j:y_j \neq c} \sum_{k} d_{kj}}$$$$w_{ci} \log \hat{\theta}_{ci}$$$$w_{ci} \frac{w_{ci}}{\sum_{j} |w_{cj}|}$$其中求和遍历所有不属于类别 $c$ 的文档 $j$$d_{ij}$ 是词项 $i$ 在文档 $j$ 中的计数或 tf-idf 值$\alpha_i$ 是与 MNB 类似的平滑超参数$\alpha \sum_i \alpha_i$。第二步归一化用于缓解 MNB 中长文档主导参数估计的倾向。CNB 的分类规则与标准朴素贝叶斯相反使用argmin$$\hat{c} \arg\min_c \sum_{i} t_i w_{ci}$$即文档被分配给补集匹配最差的类别。源码中对此有明确注释_BaseNB.predict使用 argmax而ComplementNB通过取负权重配合 argmin 操作naive_bayes.py。参数差异CNB 除继承alpha、force_alpha、fit_prior、class_prior外多了一个特有参数normbool默认False是否执行权重的第二次归一化。默认行为与 Mahout 和 Weka 中的实现保持一致即不遵循论文 Table 9 的完整算法置为True时按w / sum(|w|)归一化。实现细节上_count额外维护feature_all_所有类别累计的特征计数_update_feature_log_prob计算comp_count feature_all_ alpha - feature_count_后取对数并归一化naive_bayes.py。注意fit_prior与class_prior在 CNB 中仅在训练集只有一个类别的边缘情况下生效。BernoulliNB面向二值特征的伯努利朴素贝叶斯BernoulliNB 实现了针对多元伯努利分布multivariate Bernoulli distributions数据的朴素贝叶斯算法可以有多个特征但每个特征都假定为二元布尔变量。因此它要求样本以二值特征向量表示如果传入其他类型的数据实例可能依据binarize参数自动二值化输入。伯努利朴素贝叶斯的决策规则为$$P(x_i \mid y) P(x_i 1 \mid y), x_i (1 - P(x_i 1 \mid y)), (1 - x_i)$$与多项式朴素贝叶斯的关键区别在于它显式惩罚特征未出现当特征 $i$ 是类别 $y$ 的指示特征却未出现时而多项式变体会直接忽略未出现的特征。参数与使用建议除alpha、force_alpha、fit_prior、class_prior外BernoulliNB的关键参数是binarizefloat 或None默认0.0特征二值化的阈值。为None时假定输入已经是二值向量否则在_check_X/_check_X_y中调用binarize(X, thresholdself.binarize)将大于阈值的特征映射为 1naive_bayes.py。在文本分类场景下可以用词出现向量word occurrence vectors而非词计数向量来训练和使用该分类器。BernoulliNB在某些数据集上尤其是短文档可能表现更好文档建议时间允许时对两种模型都进行评估。相关测试test_bnb与test_bnb_feature_log_prob验证了其拟合与概率输出行为test_naive_bayes.py。从源码看伯努利模型的平滑略有不同smoothed_cc class_count_ alpha * 2每个特征只有出现/不出现两种可能见 naive_bayes.py联合对数似然计算中先算neg_prob log(1 - exp(feature_log_prob_))再通过X · (feature_log_prob_ - neg_prob) class_log_prior_ sum(neg_prob)高效合并出现与未出现两部分的贡献naive_bayes.py。CategoricalNB面向类别型特征的朴素贝叶斯CategoricalNB0.24 版本引入实现了针对类别分布数据的朴素贝叶斯算法假定每个特征以索引 $i$ 标识各自服从一个类别分布。对训练集 $X$ 中的每个特征 $i$算法估计其关于类别 $y$ 的条件类别分布样本索引集记为 $J {1, \dots, m}$$m$ 为样本数。概率计算特征 $i$ 中类别 $t$ 在类别 $c$ 下的概率估计为$$P(x_i t \mid y c\ ;, \alpha) \frac{N_{tic} \alpha}{N_c \alpha n_i}$$其中 $N_{tic} |{j \in J \mid x_{ij} t, y_j c}|$ 是类别 $t$ 在属于类别 $c$ 的样本 $x_i$ 中出现的次数$N_c |{j \in J \mid y_j c}|$ 是类别 $c$ 的样本数$\alpha$ 是平滑参数$n_i$ 是特征 $i$ 的可用类别数。输入编码约定与 min_categoriesCategoricalNB假定样本矩阵 $X$ 已经过编码例如借助 OrdinalEncoder使得每个特征 $i$ 的所有类别都表示为数字 $0, \dots, n_i - 1$$n_i$ 为该特征的类别数。因此输入必须是整数 dtype_check_X中dtypeint、非负check_non_negative、不接受稀疏矩阵accept_sparseFalse见 naive_bayes.py对应__sklearn_tags__中的categorical True、sparse False、positive_only True。min_categoriesint 或 shape 为(n_features,)的数组默认None0.24 引入每特征的最小类别数。为整数时对所有特征统一设置为数组时按特征分别指定为None时依据训练数据自动推断即X.max(axis0) 1。_validate_n_categories会要求数组与特征数形状一致且为整型naive_bayes.py对应错误校验测试见test_categoricalnb_min_categories_errorstest_naive_bayes.py。拟合后category_count_与feature_log_prob_是按特征组织的列表每个元素是 shape 为(n_classes, n_categories)的数组分别记录类别 × 该特征类别的计数与对数概率n_categories_记录每个特征的类别数。预测阶段_joint_log_likelihood通过查表累加feature_log_prob_[i][:, indices]再叠加先验完成naive_bayes.py。大规模训练out-of-core 与 partial_fit朴素贝叶斯模型可以应对完整训练集无法装入内存的大规模分类问题。为此MultinomialNB、BernoulliNB和GaussianNB都暴露了partial_fit方法可以像其他分类器一样增量训练完整演示见示例脚本 plot_out_of_core_classification.py该示例用HashingVectorizer保证批次间特征空间一致配合MultinomialNB实现流式文本分类。另外所有朴素贝叶斯分类器都支持样本加权sample_weight。与fit不同partial_fit的第一次调用必须传入全部预期类别标签列表classes参数其检查逻辑位于_check_partial_fit_first_callnaive_bayes.py 导入配合_BaseDiscreteNB.partial_fit使用。测试test_NB_partial_fit_no_first_classes专门验证了第一次调用不提供 classes 会报错的行为test_naive_bayes.py。from sklearn.naive_bayes import MultinomialNB clf MultinomialNB() classes [ham, spam] for X_batch, y_batch in stream_batches(): # 自定义批次迭代器 clf.partial_fit(X_batch, y_batch, classesclasses) clf.predict(X_test)注意事项用户指南与源码均有强调存在计算开销partial_fit每次调用都带有额外的数值稳定与计数更新开销建议数据块越大越好即尽量取到可用内存允许的上限。类别集合一旦在第一次调用中确定后续批次不应再引入新类别。scikit-learn 中其他可用的 out-of-core 策略概览可参考文档 scaling_strategies.rst。统一的框架_BaseNB 与 _BaseDiscreteNB整个朴素贝叶斯模块共 1571 行全部位于 sklearn/naive_bayes.py以两个抽象基类组织_BaseNBnaive_bayes.py面向所有朴素贝叶斯估计器的公共基类声明两个抽象方法_joint_log_likelihood计算未归一化的后验对数概率shape 为(n_samples, n_classes)与_check_X预测阶段的输入校验。公共 API 包括predict对联合对数似然取argmax后映射回classes_predict_log_proba减去logsumexp完成归一化predict_proba对predict_log_proba取指数predict_joint_log_proba返回log P(x, y)形式的联合对数概率。_BaseDiscreteNBnaive_bayes.py离散数据多项式/互补/伯努利/类别变体的基类统一管理alpha、fit_prior、class_prior、force_alpha四参数并提供fit/partial_fit的通用流程LabelBinarizer二值化标签 →_init_counters初始化计数器 →_count累加充分统计量 →_check_alpha平滑校验 →_update_feature_log_prob计算特征对数概率 →_update_class_log_prior更新先验。各子类只需实现_count、_update_feature_log_prob、_joint_log_likelihood即可获得完整功能这正是模块易于扩展的设计所在。各变体适用的数据类型可总结为下表便于快速选型分类器分布假设适用数据特别适合场景GaussianNB高斯分布连续数值特征数值型特征的小样本分类MultinomialNB多项式分布非负计数/tf-idf文本分类词频、事件计数ComplementNB多项式补集非负计数/tf-idf不平衡数据的文本分类BernoulliNB多元伯努利分布二值特征向量短文档、词出现向量CategoricalNB类别分布0..n-1 编码的整型特征类别型特征配合OrdinalEncoder结语朴素贝叶斯家族以朴素但有效著称它在理论上用条件独立假设换取计算的可分解性与极低的参数估计复杂度在实践中则凭借 naive_bayes.py 中高度优化的稀疏矩阵运算与增量计数成为文本分类、垃圾邮件过滤、大规模流式学习等场景的首选基线模型。理解五种变体的分布假设差异高斯、多项式、补集、伯努利、类别并结合alpha平滑、fit_prior/class_prior先验控制与partial_fit流式训练机制即可在 scikit-learn 中针对不同数据形态快速构建可靠、可扩展的分类系统。关于朴素贝叶斯在文本分类中的理论基础用户指南进一步推荐了 Manning、Raghavan 与 Schütze 的《Introduction to Information Retrieval》pp. 234-265、McCallum 与 Nigam 的事件模型比较研究以及 Metsis 等人在垃圾邮件过滤领域对朴素贝叶斯变体的评测文献可在 naive_bayes.rst 的 References 部分逐一查阅。【免费下载链接】scikit-learnscikit-learn: machine learning in Python项目地址: https://gitcode.com/gh_mirrors/sc/scikit-learn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考