一、简介
k近邻算法,也称为KNN或者是k-NN,它是属于非参数、有监督的学习分类器。它常用于解决分类与回归问题。按照比较通俗的话来说,所谓的k近邻,就是每个样本可以用它最接近的k个相邻样本来表示。如果一个样本,它的k个相邻的样本的大多数都属于类别1,那么这个样本就也会归结到类别1当中。
二、KNN分类算法流程
1.计算目标样本与其他样本之间的距离。
2.统计距离最近的k个样本。
3.统计k个最近的样本的类别分布,哪个类别分布最多,则目标样本归属于哪一类。
三、机器学习常用距离度量方式
Distance | Equation | visuable |
欧式距离 | ||
曼哈顿距离 | ||
切比雪夫距离 | ||
闵可夫斯基距离 | ||
余弦相似度 |
四、常用的KNN算法
4.1 线性扫描法
这也是最简单的KNN的算法,通过把目标样本与其他样本一一对比,挑选出距离最近的K个样本即可。如果样本数比较少的话,这个方法很建单而且稳定有效。但是如果是较大的数据规模,那时间成本极高。
4.2 KD Tree
结构
KD Tree 是二叉树的结构,它的每个节点都需要记录:特征坐标、切分轴、指向左枝的指针、指向右枝的指针。
思想
它的核心思想是对 k 维特征空间不断切分构造的树,切分方式是根据所有的k个维度,对每个维度以中值的方式递归切分。每一个节点都是一个超矩形,小于结点的样本划分到左子树,大于结点的样本划分到右子树。
K近邻检索流程
当KD Tree构造完毕后,最终检索时按下述流程进行:
(1)从根结点出发,递归地向下访问kd树。若目标点 当前维的坐标小于切分点的坐标,移动到左子树,否则移动到右子树,直至到达叶结点;
(2)以此叶结点为“最近点”,递归地向上回退,查找该结点的兄弟结点中是否存在更近的点,若存在则更新“最近点”,否则回退;未到达根结点时继续执行(2);
(3)当回退到根结点,则搜索结束。
适用场景
当在实际的数据集上,数据量远远大于数据的维数时,使用KD Tree是比较适用的。但是如果数据的维度过高,同时数据量又不够大,它的效率就会变得极低,近似于线性扫描法。
4.3 Ball Tree
思想
在4.2 中提到了,当数据的维度过高的情况下,KD Tree的效率会变得很低。因此,提出了 Ball Tree 的算法。KD Tree 是通过在坐标轴上做数据的分割,划分出一个个的超矩形,而 Ball Tree 则是通过使用超球面进行分割。
构建
Ball Tree 的数据结构 construct_balltree 如下所示: input: D, 数据集. output: B, Ball Tree 的根节点. if 还有孤立点存在 then 创建一个包含数据集D中的孤立点的叶子节点 B return B else 设 c 为数据的最快传播维度 设 p 为维度 c 的中心点 设 L, R 为维度 c 的根据中值划分的左集合和右集合 创建有两个子节点的 B: B.pivot := p B.child1 := construct_balltree(L), B.child2 := construct_balltree(R), 设 B 的半径为子节点到p的距离最大值 return B end if end function
五、拓展
KNN确实是很常规的机器学习方法,但是也逐渐在走向淘汰。因为它需要大量的内存或者空间来存储所有的数据,并且使用距离度量方式很可能会导致维度非常高的情况下使性能崩溃,带来极大的负面影响。
而近似最近邻算法(Approximate Nearest Neighbor, ANN)则可以通过牺牲一定的精度来换取时间和空间的方式从大量的样本当中获取最近邻的方法,存储空间少,同时查找效率极高。
下图是ANN和KNN的一个实验对比结果,在最近邻相似度达到99.3%的情况下,ANN比sklearn上的KNN速度要快380倍。
ANN的常用算法有以下几种:
(1)Spotify 的 ANNOY
(2)Google 的 ScaNN
(3)Facebook 的 Faiss
(4)HNSW
后续有空会梳理ANN的相关算法。
参考资料
3.https://imgtec.eetrend.com/blog/2022/100565211.html
4.https://en.wikipedia.org/wiki/Ball_tree
5.https://pub.towardsai.net/knn-k-nearest-neighbors-is-dead-fc16507eb3e
6.K近邻算法哪家强?KDTree、Annoy、HNSW原理和使用方法介绍 - 知乎