本文所用的代码来自sklearn包里MLKNN类,并修改了最终概率的计算方式,得到了符合预期的结果。您在阅读过程中可以对照一下MLKNN的源码方便理解。
MLKNN算法主要用到KNN和贝叶斯估计。在进行未知样本的概率估算的候,需要用到两个已知的概率。
1,先验概率,就是训练集中每个标签下标签值为1的概率。
2,后验概率,就是计算每个标签集下对于所有样本的K个近邻中出现1的11种可能情况的概率。
得到这两个概率计算结果之后,对于测试集中的每个样本,只要知道每个样本的K个近邻的所有标签中出现1的次数,拿对应的标签的先验概率除以该标签的后验概率就可以直接获得该样本标签值为1的概率以及标签值为0的概率,根据两个概率值大小获得对应的预测标签值。
举个栗子:
假设我们要对下面这个数据集进行MLKNN分类:
这个数据集有593个样本,72个特征,6个标签,事先已经做好清洗、切分了。
第一步,计算先验概率:
# self.s是平滑项,是为了防止训练集数量有限的情况下,出现某一个标签为0导致最终计算概率时出现分子为0的情况。
# y 是训练集中的标签集
# self._num_instances是训练集的样本总数
prior_prob_true = np.array((self.s + y.sum(axis=0)) / (self.s * 2 + self._num_instances))[0]
print(prior_prob_true)
prior_prob_false = 1 - prior_prob_true
上面的代码对应这个公式:
输出结果为:
第二步,计算后验概率:
# self.knn_最近邻类的实例化对象,后面计算某个样本的k个最近邻时可以直接调用self.knn_里方法
self.knn_ = NearestNeighbors(self.k).fit(X)
# 使用稀疏矩阵来记录6 x 11的数组,稀疏矩阵是为了减少运算及内存所占资源的消耗,对于存在大量重复的数据的二元数组,直接用数组记录数据会导致大量无用、重复的资源消耗。稀疏矩阵有多种类型,这里的lil(Row-based linked list sparse matrix)是基于行的链表格式。
# 数组第i行第j列记录的是第i个标签出现标签值为1的次数为j的概率。
# c记录的是为1的概率,cn记录的是为0的概率。之所以维度是11,是因为10个近邻中,出现1的次数的可能性有0-10十种。
c = sparse.lil_matrix((self._num_labels, self.k + 1), dtype='i8')
cn &