实现机器学习的分步指南 III - 朴素贝叶斯
易于实现的机器学习
引言
朴素贝叶斯是一种基于贝叶斯决策理论和特征条件独立性的分类方法,它基于训练集上关于条件独立性的概率分布来计算作为检测模型。对于给定的测试对象,后验概率最大的标签就是该测试对象的预测结果。最大化后验概率意味着最小化期望风险。那么另一个问题是为什么称它为“朴素”贝叶斯?这是因为朴素贝叶斯遵循这样一个朴素的假设:当标签确定时,所有用于分类的特征都是相互独立的,它由下式给出:
其中x(j)是第i个特征,ck是第k
个标签。然后,贝叶斯分类器可以定义为:
那么为什么最大化后验概率意味着最小化期望风险呢?假设损失函数是0-1损失函数:
其中f(x)
是决策函数。然后,期望风险是:
它由联合分布P(X,Y)
计算得出。因此,条件期望是:
为了最小化期望风险,需要最小化每个X = x
,即:
朴素贝叶斯模型
朴素贝叶斯模型包括参数估计和分类。
参数估计
在训练过程中,学习意味着估计先验概率和条件概率。最大似然估计 (MLE) 是获得上述参数的一种常用方法。先验概率的 MLE 由下式给出:
假设第j
个特征集为
{aj1,aj2,...,ajsi}。则条件概率的 MLE 由下式给出:
在朴素贝叶斯训练过程中,会计算先验概率和条件概率。但是,如果某个特征的值在训练集中从未出现过,则其概率等于零,这将影响后验概率的结果。为了解决这个问题,我们引入拉普拉斯平滑:向每个随机变量的频率添加一个整数。
然后,先验概率的贝叶斯估计为:
其中N
是唯一标签的数量,K
是样本数量。先验概率的代码如下所示:
prior_probability = {}
for key in range(len(label_value)):
prior_probability[label_value[key][0]] =
(label_value[key][1] + self.laplace) / (N + K * self.laplace) # laplace smooth
self.prior_probability = prior_probability
其中 label_value
是 (label, label_num)
的元组。
类似地,条件概率的贝叶斯估计为:
条件概率的代码如下所示。使用矩阵来保存条件概率, S[j]
是第j
个特征的唯一标签数量。
# calculate the conditional probability
prob = []
# calculate the count (x = a & y = c)
for j in range(feature_dim):
count = np.zeros([S[j], len(label_count)]) # the range of label start with 1
feature_temp = train_data[:, j]
feature_value_temp = feature_value[j]
for i in range(len(feature_temp)):
for k in range(len(feature_value_temp)):
for t in range(len(label_count)):
if feature_temp[i] == feature_value_temp[k]
and train_label[i] == label_value[t][0]:
count[k][t] += 1 # x = value and y = label
# calculate the conditional probability
for m in range(len(label_value)):
count[:, m] = (count[:, m] + self.laplace) /
(label_value[m][1] + self.laplace*S[j]) # laplace smoothing
# print(count)
prob.append(count)
self.conditional_probability = prob
分类
计算出先验概率和条件概率后,贝叶斯分类模型为:
分类代码如下所示。predict
是一个字典,包含每个标签的概率。然后我们只需要对predict
进行排序,预测结果就是排序后字典的第一个元素。
def classify(self, sample):
predict = {}
for m in range(len(self.label_value)):
temp = self.prior_probability
[self.label_value[m][0]] # get the prior_probability of m-th label in label_value
for n in range(len(sample)):
if sample[n] in self.feature_value[n]:
# print(m, n)
index = np.where(self.feature_value[n] == sample[n])[0][0]
temp = temp * self.conditional_probability[n][index][m]
else:
temp = self.laplace /
(self.S[n] * self.laplace) # if the value of feature is
# not in training set, return the laplace smoothing
predict[self.label_value[m][0]] = temp
return predict
结论与分析
本文中的贝叶斯模型是伯努利贝叶斯模型。除此之外,还有其他贝叶斯模型,例如高斯贝叶斯模型、多项式贝叶斯模型。最后,让我们将我们的贝叶斯模型与 Sklearn 中的贝叶斯模型进行比较,检测性能如下所示:
结果发现,两种方法的检测结果都不理想。此外,我们的贝叶斯模型运行时间更长,这可能是因为条件概率算法包含了太多的循环。
本文相关的代码和数据集可以在 MachineLearning 中找到。