用python手写KNN算法+kd树及其BBF优化(原理与实现)(上篇)
初学python和机器学习,突然兴起想动手用python实践一下KNN算法,本来想着这个算法原理很简单明了,应该实现起来没什么大问题,然而真正上手的时候问题频出,花了好一些功夫挨个排除各种奇怪的bug,总算是大功告成。接下来我会介绍一下算法的手写实现和在此过程中亲遇的各种问题,希望能够帮到大家。实验所需数据链接在文章最后。
ps:从学习C语言以来形成了print调试的毛病,所以在代码中保留了一些用于调试的输出重要信息的print语句,放在了后面的完整print信息版代码中,方便理解代码和调试。千万注意在使用time()方法测试程序运行时间时要把这些调试的print语句注释掉。
pps:关于numpy的疑惑建议随时参考https://www.runoob.com/numpy/numpy-dtype.html,很方便
1. KNN算法与kd树简介
1.1 什么是KNN算法?
网上关于KNN的详细介绍很多,简单来说,KNN是一种有监督分类算法,通过计算待分类数据点,与已有数据集中的所有数据点的距离。取距离最小的前K个点,根据“少数服从多数“的原则,将这个数据点划分为出现次数最多的那个类别。如图由KNN得到Xu属于ω1
因此,将分类点输入的过程就是KNN算法的学习过程,将已分类点全部输入后,要完成对未分类点所属类别的预测,重点是找出距离未分类点最近的前K个已分类点
1.2 为什么需要kd树?
前面我们说道,要完成对未分类点所属类别的预测,重点是找出距离未分类点最近的前K个已分类点。那么,对于每个未分类点,一般我们需要求出它与所有以分类点的距离,然后找出前k个距离最小的已分类点。如果已分类点集合中有n个点,那么如果我们要对m个未分类点进行预测,时间复杂度为O(m*n)。当n很大时,我们认为这样不是很高效。
那么,有没有一种方法让上述复杂度变为O(mlogn)呢?这时我们想到了二叉树。类比二叉查找树(BST),Kd-Tree即K-dimensional tree,是一棵二叉树,树中存储的是一些K维数据。在一个K维数据集合上构建一棵Kd-Tree代表了对该K维数据集合构成的K维空间的一个划分。即树中的每一个结点就相应了一个K维的超矩形区域(Hyperrectangle),kd树的详细介绍以及如何构造kd树将在下面介绍。
2. 数据集准备
首先,准备数据集:这里的数据集即指KNN算法的训练集和测试集。对于KNN算法来说,将训练集输入的过程就是KNN算法学习的过程。训练集和测试集由多个样本构成,每个样本由其特征向量和标签构成,也就是由特征和类别构成。举个例子,某样本的特征向量为(唱,跳,rap,篮球),标签为蔡徐坤,将它作为训练集输入后,测试集中我们给出(唱,跳,rap,鸡你太美),由KNN算法我们预测出该测试样本对应标签为蔡徐坤,和测试标签对比发现本次预测成功。为了方便编程,我们将训练集和测试集处理均处理为由(特征1,特征2,… ,特征n,标签)这样的向量组成的集合,称之为数据矩阵。如: