朴素贝叶斯¶
朴素贝叶斯(Naive Bayes)法是基于贝叶斯定理和特征条件独立假设的分类方法,实现简单,学习与预测的效率都很高,是一种常用的生成学习方法
分类¶
- 监督学习方法
- 概率模型
- 参数化模型
- 生成学习方法
基本方法¶
设训练数据集为
其中输入空间 \(\mathcal{X}\subseteq R^n\) 为 \(n\) 维空间向量的集合,输出空间为类标记集合 \(\mathcal{Y}=\{c_1,c_2,···,c_K\}\)
令 \(X\) 和 \(Y\) 分别为定义在输入、输出空间上的随机变量,朴素贝叶斯法基于贝叶斯定理首先将最终目标,即条件概率分布 \(P(Y=c_k \mid X=x)\) 转化为求解联合概率分布 \(P(X=x,Y=c_k)\)
为此,朴素贝叶斯需要首先学习到先验概率
以及相应条件概率分布
问题在于朴素贝叶斯对于条件概率分布 \(P(X=x \mid Y=c_k)\) 的估计,在实际的样本中该分布有着指数级数量的参数需要估计
设 \(X^{(i)}\) 可取值有 \(S_i\) 个,\(i=1,2,···,n\) ,\(Y\) 的取值有 \(K\) 个,则所需学习参数个数为 \(K\prod_{i=1}^{n}S_i\)
为此朴素贝叶斯对条件概率作了一个较强的条件独立性假设:
具体而言,该假设认为用于分类的特征在类确定的前提下是条件独立的。这一假设使参数学习变得简单(参数个数变为了 \(K\sum_{i=1}^{n}S_i\) ),但会牺牲一定的准确率
于是,在学习到参数模型后,朴素贝叶斯分类器可表示为:
因为对所有 \(c_k\) 上式分母都相同,所以只需:
参数估计¶
在朴素贝叶斯法中,学习意味着估计 \(P(Y=c_k)\) 和 \(P(X^{(j)}=x^{(j)}\mid Y=c_k)\)
常见的估计方法为极大似然估计与贝叶斯估计,同时基于不同的分布假设(如正态分布),我们还能进一步对所需求得的参数量进行简化,这点将在后面的代码部分进行解释
极大似然估计¶
对先验概率的估计为
对条件概率的估计为
其中第 \(j\) 个特征 \(x^{(i)}\) 可能取值的集合为 \(\{a_{j1},a_{j2},···,a_{jS_j}\}\)
贝叶斯估计¶
用极大似然估计可能会出现所要估计的概率值为0的情况。这会影响到后续概率的计算结果,使分类产生偏差
为此常用贝叶斯估计解决这个问题:
经过上式操作,依然能证明其仍为一种概率分布
当 \(\lambda\) 取 \(1\) 时,被称为拉普拉斯平滑(Laplacian smoothing)
代码实现¶
这里实现的为 GaussianNaiveBayesClassifier
1,具体的,其对 \(P(X^{(j)}=x^{(j)}\mid Y=c_k)\) 的假设为正态分布:
可以看到基于如上假设,我们只需要通过极大似然估计出极少的参数(\(\sigma_{c_k}\) , \(\mu_{c_k}\))便能完成学习
class GaussianNBClassifier:
def __init__(self, eps=1e-6):
self.labels = None
self.hyperparameters = {"eps": eps}
self.parameters = {
"mean": None, # shape: (K, M)
"sigma": None, # shape: (K, M)
"prior": None, # shape: (K,)
}
def fit(self, X, y):
P = self.parameters
H = self.hyperparameters
self.labels = np.unique(y)
K = len(self.labels)
N, M = X.shape
P["mean"] = np.zeros((K, M))
P["sigma"] = np.zeros((K, M))
P["prior"] = np.zeros((K,))
for i, c in enumerate(self.labels):
X_c = X[y == c, :]
P["mean"][i, :] = np.mean(X_c, axis=0)
P["sigma"][i, :] = np.var(X_c, axis=0) + H["eps"]
P["prior"][i] = X_c.shape[0] / N
return self
def predict(self, X):
return self.labels[self._log_posterior(X).argmax(axis=1)]
def _log_posterior(self, X):
K = len(self.labels)
log_posterior = np.zeros((X.shape[0], K))
for i in range(K):
log_posterior[:, i] = self._log_class_posterior(X, i)
return log_posterior
def _log_class_posterior(self, X, class_idx):
P = self.parameters
mu = P["mean"][class_idx]
prior = P["prior"][class_idx]
sigsq = P["sigma"][class_idx]
log_likelihood = -0.5 * np.sum(np.log(2 * np.pi * sigsq))
log_likelihood -= 0.5 * np.sum(((X - mu) ** 2) / sigsq, axis=1)
return log_likelihood + np.log(prior)
完整代码已上传至Repo
参考资料¶
- 《统计学习方法(第二版)》李航
-
https://scikit-learn.org/stable/modules/naive_bayes.html#gaussian-naive-bayes ↩
创建日期: 2023-03-09