最近邻算法

Posted yongfuxue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最近邻算法相关的知识,希望对你有一定的参考价值。

最近邻算法

简介

NearestNeighbors (最近邻)实现了 unsupervised nearest neighbors learning(无监督的最近邻学习)。 它为三种不同的最近邻算法提供统一的接口:BallTree, KDTree, 还有基于 sklearn.metrics.pairwise 的 brute-force 算法。算法的选择可通过关键字 ‘algorithm‘ 来控制, 并必须是 [‘auto‘, ‘ball_tree‘, ‘kd_tree‘, ‘brute‘] 其中的一个。当默认值设置为 ‘auto‘ 时,算法会尝试从训练数据中确定最佳方法。

暴力计算

最简单的近邻搜索的实现涉及数据集中所有成对点之间距离的暴力计算: 对于 D 维度中的 N 个样本来说, 这个方法的复杂度是 O[D N^2]。 对于小数据样本,高效的暴力近邻搜索是非常有竞争力的。 然而,随着样本数 N 的增长,暴力方法很快变得不切实际了。

 

在 sklearn.neighbors 类中, 暴力近邻搜索通过关键字 algorithm = ‘brute‘ 来指定,并通过 sklearn.metrics.pairwise 中的例程来进行计算。

K-D 树

为了解决效率低下的暴力计算方法,已经发明了大量的基于树的数据结构。总的来说, 这些结构试图通过有效地编码样本的 aggregate distance (聚合距离) 信息来减少所需的距离计算量。 基本思想是,若 A 点距离 B 点非常远,B 点距离 C 点非常近, 可知 A 点与 C 点很遥远,不需要明确计算它们的距离。 通过这样的方式,近邻搜索的计算成本可以降低为 O[D N log(N)] 或更低。 这是对于暴力搜索在大样本数 N 中表现的显著改善。

 

利用这种聚合信息的早期方法是 KD tree 数据结构(* K-dimensional tree* 的简写), 它将二维 Quad-trees 和三维 Oct-trees 推广到任意数量的维度. KD 树是一个二叉树结构,它沿着数据轴递归地划分参数空间,将其划分为嵌入数据点的嵌套的各向异性区域。 KD 树的构造非常快:因为只需沿数据轴执行分区, 无需计算 D-dimensional 距离。 一旦构建完成, 查询点的最近邻距离计算复杂度仅为 O[log(N)] 。 虽然 KD 树的方法对于低维度 (D < 20) 近邻搜索非常快, 当 D 增长到很大时, 效率变低: 这就是所谓的 “维度灾难” 的一种体现。 在 scikit-learn 中, KD 树近邻搜索可以使用关键字 algorithm = ‘kd_tree‘ 来指定, 并且使用类 KDTree 来计算。

Ball 树

为了解决 KD 树在高维上效率低下的问题, ball 树 数据结构就被研发出来了. 其中 KD 树沿卡迪尔轴(即坐标轴)分割数据, ball 树在沿着一系列的 hyper-spheres 来分割数据. 通过这种方法构建的树要比 KD 树消耗更多的时间, 但是这种数据结构对于高结构化的数据是非常有效的, 即使在高维度上也是一样.

 

ball 树将数据递归地划分为由质心 C 和半径 r 定义的节点,

使得节点中的每个点位于由 r 和 C 定义的 hyper-sphere 内. 通过使用 triangle inequality(三角不等式) 减少近邻搜索的候选点数:

|x+y| <= |x| + |y|

通过这种设置, 测试点和质心之间的单一距离计算足以确定距节点内所有点的距离的下限和上限. 由于 ball 树节点的球形几何, 它在高维度上的性能超出 KD-tree, 尽管实际的性能高度依赖于训练数据的结构. 在 scikit-learn 中, 基于 ball 树的近邻搜索可以使用关键字 algorithm = ‘ball_tree‘ 来指定, 并且使用类 sklearn.neighbors.BallTree 来计算. 或者, 用户可以直接使用 BallTree 类.

使用

from sklearn.neighbors import NearestNeighbors

import numpy as np

X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])

 

# n_neighbors默认5,algorithm默认‘auto’

nbrs = NearestNeighbors(n_neighbors=3, algorithm=‘ball_tree‘).fit(X) 

 

# indices得到k个最近邻的索引,distances得到与k个最近邻的距离

distances, indices = nbrs.kneighbors(X)

indices

>>> array([[0, 1, 2],

       [1, 0, 2],

       [2, 1, 0],

       [3, 4, 5],

       [4, 3, 5],

       [5, 4, 3]], dtype=int64)

Distances

>>>  array([[ 0.        ,  1.        ,  2.23606798],

       [ 0.        ,  1.        ,  1.41421356],

       [ 0.        ,  1.41421356,  2.23606798],

       [ 0.        ,  1.        ,  2.23606798],

       [ 0.        ,  1.        ,  1.41421356],

       [ 0.        ,  1.41421356,  2.23606798]])

 

也可以直接使用:

from sklearn.neighbors import KDTree

import numpy as np

X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])

kdt = KDTree(X, leaf_size=30, metric=‘euclidean‘)

 

#得到k个最近邻的索引

kdt.query(X, k=2, return_distance=False)  

以上是关于最近邻算法的主要内容,如果未能解决你的问题,请参考以下文章

KNN(最近邻)分类算法

sklearn—无监督最近邻

R语言如何实现K最近邻算法?

10-K最近邻算法

图说十大数据挖掘算法K最近邻算法

使用最近邻算法进行图像模式识别