朴素贝叶斯分类算法预测流程详解:从数学原理到工程实现

1次阅读
没有评论

共计 2634 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

在文本分类和垃圾邮件过滤等场景中,朴素贝叶斯算法因其高效和简单而广受欢迎。它的核心优势在于计算速度快、对少量训练数据表现良好,并且容易实现。特别是在处理高维稀疏数据时,朴素贝叶斯能够快速给出预测结果,这使得它成为许多实际应用中的首选算法。

朴素贝叶斯分类算法预测流程详解:从数学原理到工程实现

数学原理

朴素贝叶斯基于贝叶斯定理,假设特征之间条件独立。后验概率计算公式如下:

$$ P(y|x_1, x_2, …, x_n) = \frac{P(y)\prod_{i=1}^{n}P(x_i|y)}{P(x_1, x_2, …, x_n)} $$

其中,$P(y)$ 是类别的先验概率,$P(x_i|y)$ 是特征 $x_i$ 在类别 $y$ 下的条件概率。条件独立性假设虽然简化了计算,但也可能影响模型的表现,特别是在特征间存在强相关性的情况下。

工程实现

下面是一个 Python 实现的示例,包含了平滑处理和对数空间计算:

from typing import Dict, List
import numpy as np
from scipy.sparse import csr_matrix

class NaiveBayesClassifier:
    def __init__(self, alpha: float = 1.0):
        self.alpha = alpha  # Laplace smoothing parameter
        self.class_priors: Dict[int, float] = {}
        self.feature_probs: Dict[int, Dict[int, float]] = {}

    def fit(self, X: csr_matrix, y: List[int]) -> None:
        """Fit the model using sparse matrix X and labels y."""
        n_samples, n_features = X.shape
        classes = np.unique(y)

        # Calculate class priors with Laplace smoothing
        for c in classes:
            self.class_priors[c] = (np.sum(y == c) + self.alpha) / (n_samples + len(classes) * self.alpha)

        # Calculate feature probabilities in log space
        for c in classes:
            class_mask = (y == c)
            class_count = np.sum(class_mask)

            # Sum features for current class
            if isinstance(X, csr_matrix):
                feature_counts = X[class_mask].sum(axis=0).A1
            else:
                feature_counts = X[class_mask].sum(axis=0)

            # Apply smoothing and convert to log probabilities
            total_count = class_count + 2 * self.alpha
            self.feature_probs[c] = {f: np.log((feature_counts[f] + self.alpha) / total_count)
                for f in range(n_features)
            }

    def predict_proba(self, X: csr_matrix) -> np.ndarray:
        """Predict class probabilities for samples in X."""
        n_samples = X.shape[0]
        classes = sorted(self.class_priors.keys())
        probs = np.zeros((n_samples, len(classes)))

        for i, c in enumerate(classes):
            # Start with log of class prior
            log_prob = np.log(self.class_priors[c])

            # Add log probabilities of features
            if isinstance(X, csr_matrix):
                for row in range(n_samples):
                    _, cols = X[row].nonzero()
                    log_prob_row = log_prob + sum(self.feature_probs[c].get(f, np.log(self.alpha / (np.exp(self.class_priors[c]) + 2 * self.alpha)))
                        for f in cols
                    )
                    probs[row, i] = np.exp(log_prob_row)
            else:
                for row in range(n_samples):
                    log_prob_row = log_prob + sum(self.feature_probs[c].get(f, np.log(self.alpha / (np.exp(self.class_priors[c]) + 2 * self.alpha))) * val
                        for f, val in enumerate(X[row]) if val != 0
                    )
                    probs[row, i] = np.exp(log_prob_row)

        # Normalize probabilities
        probs = probs / probs.sum(axis=1, keepdims=True)
        return probs

性能优化

  1. 稀疏矩阵存储 :对于文本数据,使用 CSR 格式比哈希表更高效,因为 CSR 格式在矩阵运算中表现更好,内存占用也更少。

  2. 并行化预测 :预测阶段可以很容易地并行化,因为每个样本的预测是独立的。可以使用 Python 的 multiprocessing 库或 joblib 来实现。

避坑指南

  1. 零概率问题 :使用拉普拉斯平滑(add-k smoothing)避免零概率问题,确保模型能够处理未见过的特征。

  2. 类别不平衡 :在类别不平衡的数据集上,可以通过调整类别的先验概率来改善模型表现。

  3. 在线学习 :朴素贝叶斯支持增量学习,可以通过更新特征计数和类别计数来实现在线学习。

开放式问题

  1. 当特征之间存在强相关性时,朴素贝叶斯的条件独立性假设会如何影响模型性能?
  2. 在实际应用中,如何评估和选择最适合的平滑参数 alpha?
  3. 对于高维稀疏数据,有哪些特征选择方法可以进一步提升朴素贝叶斯的性能?

通过本文的讲解和示例代码,希望读者能够更好地理解朴素贝叶斯分类算法的预测流程,并在实际项目中灵活应用。朴素贝叶斯虽然简单,但在许多场景下仍然是一个非常有效的工具,特别是在需要快速实现和部署的情况下。

正文完
 0
评论(没有评论)