精华内容
下载资源
问答
  • kd树详解
    千次阅读
    2019-12-24 14:37:27

    1. 什么是KD树

    Kd-树是K-dimension tree的缩写,是对数据点在k维空间(如二维(x,y),三维(x,y,z),k维(x,y,z..)中划分的一种数据结构,主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)。

    k-d树是一种空间划分树,就是把整个空间划分为特定的几个部分,然后在特定空间的部分内进行相关搜索操作。想像一个三维空间,kd树按照一定的划分规则把这个三维空间划分了多个空间,如下图所示:

                                                    

    1.2 KD树的构建       

    kd树构建的伪代码如下图所示:

                                                         

            再举一个简单直观的实例来介绍k-d树构建算法。假设有6个二维数据点{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},数据点位于二维空间内,如下图所示。为了能有效的找到最近邻,k-d树采用分而治之的思想,即将整个空间划分为几个小部分,首先,粗黑线将空间一分为二,然后在两个子空间中,细黑直线又将整个空间划分为四部分,最后虚黑直线将这四部分进一步划分。

                                          

     1.3 KD树的最近邻搜索算法

     现实生活中有许多问题需要在多维数据的快速分析和快速搜索,对于这个问题最常用的方法是所谓的kd树。在k-d树中进行数据的查找也是特征匹配的重要环节,其目的是检索在k-d树中与查询点距离最近的数据点。在一个N维的笛卡儿空间在两个点之间的距离是由下述公式确定:

    (此公式有误)

     

    下面,以两个简单的实例(例子来自图像局部不变特性特征与描述一书)来描述最邻近查找的基本思路。

    2.5.1、举例:查询点(2.1,3.1)

    星号表示要查询的点(2.1,3.1)。通过二叉搜索,顺着搜索路径很快就能找到最邻近的近似点,也就是叶子节点(2,3)。而找到的叶子节点并不一定就是最邻近的,最邻近肯定距离查询点更近,应该位于以查询点为圆心且通过叶子节点的圆域内。为了找到真正的最近邻,还需要进行相关的‘回溯'操作。也就是说,算法首先沿搜索路径反向查找是否有距离查询点更近的数据点。

    以查询(2.1,3.1)为例:

    1.二叉树搜索:先从(7,2)点开始进行二叉查找,然后到达(5,4),最后到达(2,3),此时搜索路径中的节点为<(7,2),(5,4),(2,3)>,首先以(2,3)作为当前最近邻点,计算其到查询点(2.1,3.1)的距离为0.1414,

    2.回溯查找:在得到(2,3)为查询点的最近点之后,回溯到其父节点(5,4),并判断在该父节点的其他子节点空间中是否有距离查询点更近的数据点。以(2.1,3.1)为圆心,以0.1414为半径画圆,如下图所示。发现该圆并不和超平面y = 4交割,因此不用进入(5,4)节点右子空间中(图中灰色区域)去搜索;

    3.最后,再回溯到(7,2),以(2.1,3.1)为圆心,以0.1414为半径的圆更不会与x = 7超平面交割,因此不用进入(7,2)右子空间进行查找。至此,搜索路径中的节点已经全部回溯完,结束整个搜索,返回最近邻点(2,3),最近距离为0.1414。

     

    2.5.2、举例:查询点(2,4.5)

        一个复杂点了例子如查找点为(2,4.5),具体步骤依次如下:

    1.同样先进行二叉查找,先从(7,2)查找到(5,4)节点,在进行查找时是由y = 4为分割超平面的,由于查找点为y值为4.5,因此进入右子空间查找到(4,7),形成搜索路径<(7,2),(5,4),(4,7)>,但(4,7)与目标查找点的距离为3.202,而(5,4)与查找点之间的距离为3.041,所以(5,4)为查询点的最近点;

    2.以(2,4.5)为圆心,以3.041为半径作圆,如下图所示。可见该圆和y = 4超平面交割,所以需要进入(5,4)左子空间进行查找,也就是将(2,3)节点加入搜索路径中得<(7,2),(2,3)>;于是接着搜索至(2,3)叶子节点,(2,3)距离(2,4.5)比(5,4)要近,所以最近邻点更新为(2,3),最近距离更新为1.5;

    3.回溯查找至(5,4),直到最后回溯到根结点(7,2)的时候,以(2,4.5)为圆心1.5为半径作圆,并不和x = 7分割超平面交割,如下图所示。至此,搜索路径回溯完,返回最近邻点(2,3),最近距离1.5。

     

        上述两次实例表明,当查询点的邻域与分割超平面两侧空间交割时,需要查找另一侧子空间,导致检索过程复杂,效率下降。

    2.4 kd树近邻搜索算法的改进:BBF算法

    详情请看原文链接。(https://blog.csdn.net/App_12062011/article/details/51986805

    更多相关内容
  • KD树详解

    千次阅读 2019-03-05 14:55:24
    k-d(k-dimensional的简称),是一种分割k维数据空间的数据结构。主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)。 应用背景 SIFT算法中做特征点匹配的时候就会利用到k-d。而特征点匹配实际...

    k-d树(k-dimensional树的简称),是一种分割k维数据空间的数据结构。主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)。

    1. 应用背景

    SIFT算法中做特征点匹配的时候就会利用到k-d树。而特征点匹配实际上就是一个通过距离函数在高维矢量之间进行相似性检索的问题。针对如何快速而准确地找到查询点的近邻,现在提出了很多高维空间索引结构和近似查询的算法,k-d树就是其中一种。

    索引结构中相似性查询有两种基本的方式:一种是范围查询(range searches),另一种是K近邻查询(K-neighbor searches)。范围查询就是给定查询点和查询距离的阈值,从数据集中找出所有与查询点距离小于阈值的数据;K近邻查询是给定查询点及正整数K,从数据集中找到距离查询点最近的K个数据,当K=1时,就是最近邻查询(nearest neighbor searches)。

    特征匹配算子大致可以分为两类。一类是线性扫描法,即将数据集中的点与查询点逐一进行距离比较,也就是穷举,缺点很明显,就是没有利用数据集本身蕴含的任何结构信息,搜索效率较低,第二类是建立数据索引,然后再进行快速匹配。因为实际数据一般都会呈现出簇状的聚类形态,通过设计有效的索引结构可以大大加快检索的速度。索引树属于第二类,其基本思想就是对搜索空间进行层次划分。根据划分的空间是否有混叠可以分为Clipping和Overlapping两种。前者划分空间没有重叠,其代表就是k-d树;后者划分空间相互有交叠,其代表为R树。(这里只介绍k-d树)

    实例

    先以一个简单直观的实例来介绍k-d树算法。假设有6个二维数据点{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},数据点位于二维空间内(如图1中黑点所示)。k-d树算法就是要确定图1中这些分割空间的分割线(多维空间即为分割平面,一般为超平面)。下面就要通过一步步展示k-d树是如何确定这些分割线的。

    在这里插入图片描述

    图1 二维数据k-d树空间划分示意图

    k-d树算法可以分为两大部分,一部分是有关k-d树本身这种数据结构建立的算法,另一部分是在建立的k-d树上如何进行最邻近查找的算法。

    k-d树构建算法

    k-d树是一个二叉树,每个节点表示一个空间范围。表1给出的是k-d树每个节点中主要包含的数据结构。

    域名 数据类型 描述
    Node-data 数据矢量 数据集中某个数据点,是n维矢量(这里也就是k维)
    Range 空间矢量 该节点所代表的空间范围
    split 整数 垂直于分割超平面的方向轴序号
    Left k-d树 由位于该节点分割超平面左子空间内所有数据点所构成的k-d树
    Right k-d树 由位于该节点分割超平面右子空间内所有数据点所构成的k-d树
    parent k-d树 父节点
      从上面对k-d树节点的数据类型的描述可以看出构建k-d树是一个逐级展开的递归过程。
      由于此例简单,数据维度只有2维,所以可以简单地给x,y两个方向轴编号为0,1,也即split={0,1}。

    (1)确定split域的首先该取的值。分别计算x,y方向上数据的方差得知x方向上的方差最大,所以split域值首先取0,也就是x轴方向;

    (2)确定Node-data的域值。根据x轴方向的值2,5,9,4,8,7排序选出中值为7,所以Node-data = (7,2)。这样,该节点的分割超平面就是通过(7,2)并垂直于split = 0(x轴)的直线x = 7;

    (3)确定左子空间和右子空间。分割超平面x = 7将整个空间分为两部分,如图2所示。x < = 7的部分为左子空间,包含3个节点{(2,3),(5,4),(4,7)};另一部分为右子空间,包含2个节点{(9,6),(8,1)}。

    在这里插入图片描述
    图2 x=7将整个空间分为两部分

    如算法所述,k-d树的构建是一个递归的过程。然后对左子空间和右子空间内的数据重复根节点的过程就可以得到下一级子节点(5,4)和(9,6)(也就是左右子空间的’根’节点),同时将空间和数据集进一步细分。如此反复直到空间中只包含一个数据点,如图1所示。最后生成的k-d树如图3所示。

    在这里插入图片描述
    图3 上述实例生成的k-d树

    注意:每一级节点旁边的’x’和’y’表示以该节点分割左右子空间时split所取的值。

    k-d树上的最邻近查找算法

    在k-d树中进行数据的查找也是特征匹配的重要环节,其目的是检索在k-d树中与查询点距离最近的数据点。这里先以一个简单的实例来描述最邻近查找的基本思路。

    星号表示要查询的点(2.1,3.1)。通过二叉搜索,顺着搜索路径很快就能找到最邻近的近似点,也就是叶子节点(2,3)。而找到的叶子节点并不一定就是最邻近的,最邻近肯定距离查询点更近,应该位于以查询点为圆心且通过叶子节点的圆域内。为了找到真正的最近邻,还需要进行’回溯’操作:算法沿搜索路径反向查找是否有距离查询点更近的数据点。此例中先从(7,2)点开始进行二叉查找,然后到达(5,4),最后到达(2,3),此时搜索路径中的节点为<(7,2),(5,4),(2,3)>,首先以(2,3)作为当前最近邻点,计算其到查询点(2.1,3.1)的距离为0.1414,然后回溯到其父节点(5,4),并判断在该父节点的其他子节点空间中是否有距离查询点更近的数据点。以(2.1,3.1)为圆心,以0.1414为半径画圆,如图4所示。发现该圆并不和超平面y = 4交割,因此不用进入(5,4)节点右子空间中去搜索。

    在这里插入图片描述

    图4 查找(2.1,3.1)点的两次回溯判断

    再回溯到(7,2),以(2.1,3.1)为圆心,以0.1414为半径的圆更不会与x = 7超平面交割,因此不用进入(7,2)右子空间进行查找。至此,搜索路径中的节点已经全部回溯完,结束整个搜索,返回最近邻点(2,3),最近距离为0.1414。

    一个复杂点了例子如查找点为(2,4.5)。同样先进行二叉查找,先从(7,2)查找到(5,4)节点,在进行查找时是由y = 4为分割超平面的,由于查找点为y值为4.5,因此进入右子空间查找到(4,7),形成搜索路径<(7,2),(5,4),(4,7)>,取(4,7)为当前最近邻点,计算其与目标查找点的距离为3.202。然后回溯到(5,4),计算其与查找点之间的距离为3.041。以(2,4.5)为圆心,以3.041为半径作圆,如图5所示。可见该圆和y = 4超平面交割,所以需要进入(5,4)左子空间进行查找。此时需将(2,3)节点加入搜索路径中得<(7,2),(2,3)>。回溯至(2,3)叶子节点,(2,3)距离(2,4.5)比(5,4)要近,所以最近邻点更新为(2,3),最近距离更新为1.5。回溯至(7,2),以(2,4.5)为圆心1.5为半径作圆,并不和x = 7分割超平面交割,如图6所示。至此,搜索路径回溯完。返回最近邻点(2,3),最近距离1.5。k-d树查询算法的伪代码如表3所示。

    在这里插入图片描述

    图5 查找(2,4.5)点的第一次回溯判断

    在这里插入图片描述

    图6 查找(2,4.5)点的第二次回溯判断

    上述两次实例表明,当查询点的邻域与分割超平面两侧空间交割时,需要查找另一侧子空间,导致检索过程复杂,效率下降。研究表明N个节点的K维k-d树搜索过程时间复杂度为:tworst=O(kN1-1/k)。

    后记

    以上为了介绍方便,讨论的是二维情形。像实际的应用中,如SIFT特征矢量128维,SURF特征矢量64维,维度都比较大,直接利用k-d树快速检索(维数不超过20)的性能急剧下降。假设数据集的维数为D,一般来说要求数据的规模N满足N»2D,才能达到高效的搜索。所以这就引出了一系列对k-d树算法的改进。有待进一步研究学习。

    参考

    1.《图像局部不变特性特征与描述》王永明 王贵锦 编著 国防工业出版社
    2.《统计学习方法》 第三章 k近邻算法的KD树

    展开全文
  • KNN算法和kd树详解(例子+图示)

    万次阅读 多人点赞 2019-03-15 11:19:44
    kd树是二叉树的一种,是对k维空间的一种分割,不断地用垂直于坐标轴的超平面将k维空间切分,形成k维超矩形区域,kd树的每一个结点对应于一个k维超矩形区域。   注意:这里的k 维的k 表示的是数据的维度,上文...

    一、KNN算法

    KNN(K-NearestNeighbor)算法既可以用于分类,也可用于回归。这里介绍他的分类用法。

     

    训练集:一堆拥有标签的m维数据,可以表示为:

                   其中  是标签,即所属类别。

    目标:一个测试数据x,预测其所属类别。

     

    算法:

    1. 计算测试点x与训练集中每一个数据的“距离”
    2. 将所求的距离进行升序排序,选择前K个
    3. 在上一步中所得到的K个数据中,根据决策规则(如多数表决)决定x的类别预测结果

     

    虽然KNN算法用短短的三步就能概括,但是大有文章可做

     

    1、“距离”是啥距离?

    话不多说,先摆个公式压压惊

                                                                             

    上式表示的是:m维数据的距离就是这么求的。

    当p=2时,这个距离就称为欧式距离,是不是很熟悉?

    当p=1时,称为曼哈顿距离

    根据数据特性的不同,我们可以选择不同的距离来度量。

     

    2、K值如何选择

    我们一直在谈KNN,那这个K我们该如何选择呢?

    K值太小,预测结果会对近邻的训练数据十分敏感,模型过于复杂,易发生过拟合

    K值太大,会导致分类结果模糊,模型过于简单。

     

    对于k值的选择有这么几种方法:交叉验证、贝叶斯方法、bootstrap。

    一般是取个较小值,采用交叉验证法来选取最优的K值。

     

    3、决策规则是啥?

    一般是选用多数表决规则,即在K个数据中,哪种类别出现的次数最多,这个类别就是x的预测类别。

     

    二、kd树

    以上说完,我们就要进入实现环节了。那么问题来了,我们上面说的是计算测试点和训练集中的每一个数据的距离,然后进行排序。数据量少的时候完全问题,可是当数据量大的时候,臣妾做不到啊!!!

     

    这时候,我们聪明的前辈就提出了kd树(k-dimensional tree)。这是一颗什么样的树呢?

    kd树可以帮助我们在很快地找到与测试点最邻近的K个训练点。不再需要计算测试点和训练集中的每一个数据的距离。

    kd树是二叉树的一种,是对k维空间的一种分割,不断地用垂直于坐标轴的超平面将k维空间切分,形成k维超矩形区域,kd树的每一个结点对应于一个k维超矩形区域。

     

    注意:这里的k维的k表示的是数据的维度,上文中我们称为m维数据。(不要理解为K个训练点的K,你看我甚至把训练点的K大写,维度的k小写

     

    kd树的构造

     

    首先我们需要构造kd数,构造方法如下:

    1. 选取为坐标轴,以训练集中的所有数据坐标中的中位数作为切分点,将超矩形区域切割成两个子区域。将该切分点作为根结点,由根结点生出深度为1的左右子结点,左节点对应坐标小于切分点,右结点对应坐标大于切分点
    2. 对深度为j的结点,选择为切分坐标轴,,以该结点区域中训练数据坐标的中位数作为切分点,将区域分为两个子区域,且生成深度为j+1的左、右子结点。左节点对应坐标小于切分点,右结点对应坐标大于切分点
    3. 重复2,直到两个子区域没有数据时停止。

     

    是不是现在还是懵懵懂懂的,甚至上面的构造方法只是一眼扫过。

    不慌,有句话叫无图言X,接下来就是关门放图的时候。

    我们用图像来走算法!

     

    我们有二维数据集

    将他们在坐标系中表示如下:

                                             

     

    开始:选择为坐标轴,中位数为6,即(6,5)为切分点,切分整个区域

                                                                   

     

    再次划分区域

    为坐标轴,选择中位数,可知左边区域为-3,右边区域为-12。所以左边区域切分点为(1,-3),右边区域切分点坐标为(17,-12)

     

                                                 

                         

     

     

    再次对区域进行切分,同上步,我们可以得到切分点,切分结果如下:

     

                                                

     

     

     

    最后分割的小区域内只剩下一个点或者没有点。我们得到最终的kd树如下图

     

     

     

    kd树完成K近邻的搜索

    当我们完成了kd树的构造之后,我们就要想怎么利用kd树完成K近邻的搜索呢???

     

    接下来,又是抛出算法的时候了

     

    为了方便说明,我们采用二维数据的栗子。假设现在要寻找p点的K个近邻点(p点坐标为(a,b)),也就是离p点最近的K个点。设S是存放这K个点的一个容器。

     

    新鲜的算法来了:

    1. 根据p的坐标和kd树的结点向下进行搜索(如果树的结点是以来切分的,那么如果p的坐标小于c,则走左子结点,否则走右子结点)
    2. 到达叶子结点时,将其标记为已访问。如果S中不足k个点,则将该结点加入到S中;如果S不空且当前结点与p点的距离小于S中最长的距离,则用当前结点替换S中离p最远的点
    3. 如果当前结点不是根节点,执行(a);否则,结束算法

    (a)回退到当前结点的父结点,此时的结点为当前结点(回退之后的结点)。将当前结点标记为已访问,执行(b)和(c);如果当前结点已经被访过,再次执行(a)。

    (b)如果此时S中不足k个点,则将当前结点加入到S中;如果S中已有k个点,且当前结点与p点的距离小于S中最长距离,则用当前结点替换S中距离最远的点。

    (c)计算p点和当前结点切分线的距离。如果该距离大于等于S中距离p最远的距离并且S中已有k个点,执行3;如果该距离小于S中最远的距离或S中没有k个点,从当前结点的另一子节点开始执行1;如果当前结点没有另一子结点,执行3。

    以上的1,2,3我们会称为算法中的1,算法中的2,算法中的3

    老规矩,上图!

     

    为了方便描述,我对结点进行了命名,如下图。

    蓝色斜线表示该结点标记为已访问,红色下划线表示在此步确定的下一要访问的结点

     

    我们现在就计算p(-1,-5)的3个邻近点。

     

                                             

     

     

    我们拿着(-1,-5)寻找kd树的叶子结点。

     

    执行算法中的1。

    •  p点的-1与结点A的x轴坐标6比较,-1<6,向左走。
    •  p点的-5与结点B的y轴坐标-3比较,较小,往左走。
    •  因为结点C只有一个子结点,所以不需要进行比较,直接走到结点H。

     

    进行算法中的2,标记结点H已访问,将结点H加入到S中。

    此时                                                                          

                                   

     

    执行算法中的3,当前结点H不是根结点

    • 执行(a),回退到父结点C,我们将结点C标记为已访问
    • 执行(b),S中不足3个点,将结点C加入到S中
    • 执行(c)计算p点和结点C切分线的距离,可是结点C没有另一个分支,我们开始执行算法中的3。

                                                                    

                                           

     

    当前结点C不是根结点

    • 执行(a),回退到父结点B,我们将结点B标记为已访问
    • 执行(b),S中不足3个点,将结点B加入到S中
    • 执行(c)计算p点和结点B切分线的距离,两者距离为小于S中的最大距离。(S中的三个点与p的距离分别为)。所以我们需要从结点B的另一子节点D开始算法中的1。

     

                                                                                            

     

                                             

                                              

     

     

    从结点D开始算法中的1

    • p点的-1与结点D的x轴坐标-2比较,-1 >  -2,向右走。
    • 找到了叶子结点J,标记为已访问。

    开始算法中的2

    • S不空,计算当前结点J与p点的距离,为18.2,大于S中的最长距离
    • 所以我们不将结点J放入S中

                                                                                          

     

    执行算法中的3,当前结点J不为根结点

    • 执行(a),回退到父结点D,标记为已访问。
    • 执行(b),S中已经有3个点,当前结点D与p点距离为,小于S中的最长距离(结点H与p点的距离),将结点D替换结点H。
    • 执行(c),计算p点和结点D切分线的距离,两者距离为1,小于S中最长距离,所以我们需要从结点D的另一子节点I开始算法中的1。

                                                                                              

     

                                

                                              

     

    从结点I开始算法中的1,结点I已经是叶子结点

    直接进行到算法中的2

    • 标记结点I为已访问
    • 计算当前结点I和p点的距离为,大于S中最长距离,不进行替换。

     

                                                                                               

     

    执行算法中的3.

    当前结点I不是根结点

    • 执行(a),回退到父结点D,但当前结点D已经被访问过。
    • 再次执行(a),回退到结点D的父结点B,也标记为访问过
    • 再次执行(a),回退到结点B的父结点A,结点A未被访问过,标记为已访问。
    • 执行(b),结点A和p点的距离为,大于S中的最长距离,不进行替换
    • 执行(c),p点和结点A切分线的距离为7,大于S中的最长距离,不进行替换

                                                                                          

                                              

     

    执行算法中的3,发现当前结点A是根结点,结束算法。

    得到p点的3个邻近点,为(-6,-5)、(1,-3)、(-2,-1)

     

    kd树就这么的完成了他的任务。

    总的来说,就是以下几步

    1、找到叶子结点,看能不能加入到S中

    2、回退到父结点,看父结点能不能加入到S中

    3、看目标点和回退到的父结点切分线的距离,判断另一子结点能不能加入到S中

     

    有错误之处还请大家帮忙指正!

     

    参考:

    https://cloud.tencent.com/developer/news/212042

    https://zhuanlan.zhihu.com/p/23966698

    展开全文
  • 1 KD树 1.1什么是KD树 1.2KD树的构建 1.3 KD树的插入 1.4KD树的删除 1.5KD树的最近邻搜索算法 1.5.1举例:查询点(2.1,3.1) 1.5.2 举例:查询点(2,4.5) 2 kd树近邻搜索算法的改进:BBF算法 3 球树、M树...

    目录

    1 KD树

    1.1 什么是KD树

    1.2 KD树的构建

    1.3 KD树的插入

    1.4 KD树的删除

    1.5 KD树的最近邻搜索算法

    1.5.1 举例:查询点(2.1,3.1)

    1.5.2 举例:查询点(2,4.5)

    2 kd树近邻搜索算法的改进:BBF算法

    3 球树、M树、VP树、MVP树

    3.1 球树

    3.2 VP树与MVP树简介


            特征点匹配和数据库查、图像检索本质上是同一个问题,都可以归结为一个通过距离函数在高维矢量之间进行相似性检索的问题,如何快速而准确地找到查询点的近邻,不少人提出了很多高维空间索引结构和近似查询的算法。

            一般说来,索引结构中相似性查询有两种基本的方式:

    • 一种是范围查询,范围查询时给定查询点和查询距离阈值,从数据集中查找所有与查询点距离小于阈值的数据
    • 另一种是K近邻查询,就是给定查询点及正整数K,从数据集中找到距离查询点最近的K个数据,当K=1时,它就是最近邻查询。

        同样,针对特征点匹配也有两种方法:

    1. 最容易的办法就是线性扫描,也就是我们常说的穷举搜索,依次计算样本集E中每个样本到输入实例点的距离,然后抽取出计算出来的最小距离的点即为最近邻点。此种办法简单直白,但当样本集或训练集很大时,它的缺点就立马暴露出来了,举个例子,在物体识别的问题中,可能有数千个甚至数万个SIFT特征点,而去计算这成千上万的特征点与输入实例点的距离,明显是不足取的。
    2. 另外一种,就是构建数据索引,因为实际数据一般都会呈现簇状的聚类形态,因此我们想到建立数据索引,然后再进行快速匹配。索引树是一种树结构索引方法,其基本思想是对搜索空间进行层次划分。根据划分的空间是否有混叠可以分为Clipping和Overlapping两种。前者划分空间没有重叠,其代表就是k-d树;后者划分空间相互有交叠,其代表为R树。

            1975年,来自斯坦福大学的Jon Louis Bentley在ACM杂志上发表的一篇论文:Multidimensional Binary Search Trees Used for Associative Searching 中正式提出和阐述的了如下图形式的把空间划分为多个部分的k-d树。                                     

    1 KD树

    1.1 什么是KD树

       Kd-树是K-dimension tree的缩写,是对数据点在k维空间(如二维(x,y),三维(x,y,z),k维(x1,y,z..))中划分的一种数据结构,主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)。本质上说,Kd-树就是一种平衡二叉树。

        首先必须搞清楚的是,k-d树是一种空间划分树,说白了,就是把整个空间划分为特定的几个部分,然后在特定空间的部分内进行相关搜索操作。想像一个三维(多维有点为难你的想象力了)空间,kd树按照一定的划分规则把这个三维空间划分了多个空间,如下图所示: 

    1.2 KD树的构建

            

            再举一个简单直观的实例来介绍k-d树构建算法。假设有6个二维数据点{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},数据点位于二维空间内,如下图所示。为了能有效的找到最近邻,k-d树采用分而治之的思想,即将整个空间划分为几个小部分,首先,粗黑线将空间一分为二,然后在两个子空间中,细黑实直线又将整个空间划分为四部分,最后虚黑直线将这四部分进一步划分。        

            6个二维数据点{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}构建kd树的具体步骤为:

    1. 确定:split域=x。具体是:6个数据点在x,y维度上的数据方差分别为39,28.63,所以在x轴上方差更大,故split域值为x;
    2. 确定:Node-data = (7,2)。具体是:根据x维上的值将数据排序,6个数据的中值(所谓中值,即中间大小的值)为7,所以Node-data域位数据点(7,2)。这样,该节点的分割超平面就是通过(7,2)并垂直于:split=x轴的直线x=7;
    3. 确定:左子空间和右子空间。具体是:分割超平面x=7将整个空间分为两部分:x<=7的部分为左子空间,包含3个节点={(2,3),(5,4),(4,7)};另一部分为右子空间,包含2个节点={(9,6),(8,1)};

            如上算法所述,kd树的构建是一个递归过程,我们对左子空间和右子空间内的数据重复根节点的过程就可以得到一级子节点(5,4)(9,6),同时将空间和数据集进一步细分,如此往复直到空间中只包含一个数据点。

        与此同时,经过对上面所示的空间划分之后,我们可以看出,点(7,2)可以为根结点,从根结点出发的两条红粗斜线指向的(5,4)和(9,6)则为根结点的左右子结点,而(2,3),(4,7)则为(5,4)的左右孩子(通过两条细红斜线相连),最后,(8,1)为(9,6)的左孩子(通过细红斜线相连)。如此,便形成了下面这样一棵k-d树:

             k-d树的数据结构:

            

    /** a node in a k-d tree */
    struct kd_node
    {
    	int ki;                      /**< partition key index *///关键点直方图方差最大向量系列位置
    	double kv;                   /**< partition key value *///直方图方差最大向量系列中最中间模值
    	int leaf;                    /**< 1 if node is a leaf, 0 otherwise */
    	struct feature* features;    /**< features at this node */
    	int n;                       /**< number of features */
    	struct kd_node* kd_left;     /**< left child */
    	struct kd_node* kd_right;    /**< right child */
    };
    

           也就是说,如之前所述,kd树中,kd代表k-dimension,每个节点即为一个k维的点。每个非叶节点可以想象为一个分割超平面,用垂直于坐标轴的超平面将空间分为两个部分,这样递归的从根节点不停的划分,直到没有实例为止。经典的构造k-d tree的规则如下:

    1. 随着树的深度增加,循环的选取坐标轴,作为分割超平面的法向量。对于3-d tree来说,根节点选取x轴,根节点的孩子选取y轴,根节点的孙子选取z轴,根节点的曾孙子选取x轴,这样循环下去。
    2. 每次均为所有对应实例的中位数的实例作为切分点,切分点作为父节点,左右两侧为划分的作为左右两子树。
       

            对于n个实例的k维数据来说,建立kd-tree的时间复杂度为O(k*n*logn)

            构建完kd树之后,如今进行最近邻搜索呢?从下面的动态gif图中,你是否能看出些许端倪呢?

            

                k-d树算法可以分为两大部分,除了上部分有关k-d树本身这种数据结构建立的算法,另一部分是在建立的k-d树上各种诸如插入,删除,查找(最邻近查找)等操作涉及的算法。下面,咱们依次来看kd树的插入、删除、查找操作。

    1.3 KD树的插入

        元素插入到一个K-D树的方法二叉检索树类似。本质上,在偶数层比较x坐标值,而在奇数层比较y坐标值。当我们到达了树的底部,(也就是当一个空指针出现),我们也就找到了结点将要插入的位置。生成的K-D树的形状依赖于结点插入时的顺序。给定N个点,其中一个结点插入和检索的平均代价是O(log2N)

        下面4副图(来源:中国地质大学电子课件)说明了插入顺序为(a) Chicago, (b) Mobile, (c) Toronto, and (d) Buffalo,建立空间K-D树的示例:

        应该清楚,这里描述的插入过程中,每个结点将其所在的平面分割成两部分。因比,Chicago 将平面上所有结点分成两部分,一部分所有的结点x坐标值小于35,另一部分结点的x坐标值大于或等于35。同样Mobile将所有x坐标值大于35的结点以分成两部分,一部分结点的Y坐标值是小于10,另一部分结点的Y坐标值大于或等于10。后面的Toronto、Buffalo也按照一分为二的规则继续划分。

    1.4 KD树的删除

         KD树的删除可以用递归程序来实现。我们假设希望从K-D树中删除结点(a,b)。如果(a,b)的两个子树都为空,则用空树来代替(a,b)。否则,在(a,b)的子树中寻找一个合适的结点来代替它,譬如(c,d),则递归地从K-D树中删除(c,d)。一旦(c,d)已经被删除,则用(c,d)代替(a,b)。假设(a,b)是一个X识别器,那么,它得替代节点要么是(a,b)左子树中的X坐标最大值的结点,要么是(a,b)右子树中X坐标最小值的结点。

         也就是说,跟普通二叉树(包括如下图所示的红黑树)结点的删除是同样的思想:用被删除节点A的左子树的最右节点或者A的右子树的最左节点作为替代A的节点(比如,下图红黑树中,若要删除根结点26,第一步便是用23或28取代根结点26)。

         当(a,b)的右子树为空时,找到(a,b)左子树中具有x坐标最大的结点,譬如(c,d),将(a,b)的左子树放到(c,d)的右子树中,且在树中从它的上一层递归地应用删除过程(也就是(a,b)的左子树) 。

        下面来举一个实际的例子,如下图所示,原始图像及对应的kd树,现在要删除图中的A结点,请看一系列删除步骤:

         

          (1)要删除上图中结点A,选择结点A的右子树中X坐标值最小的结点,这里是C,C成为根,如下图:

         

          (2) 从C的右子树中找出一个结点代替先前C的位置,

          

                这里是D,并将D的左子树转为它的右子树,D代替先前C的位置,如下图:

          

            (3)在D的新右子树中,找X坐标最小的结点,这里为H,H代替D的位置,

             

            (4)在D的右子树中找到一个Y坐标最小的值,这里是I,将I代替原先H的位置,从而A结点从图中顺利删除,如下图所示:

              

          从一个K-D树中删除结点(a,b)的问题变成了:在(a,b)的子树中寻找x坐标为最小的结点。不幸的是寻找最小x坐标值的结点比二叉检索树中解决类似的问题要复杂得多。特别是虽然最小x坐标值的结点一定在x识别器的左子树中,但它同样可在y识别器的两个子树中。因此关系到检索,且必须注意检索坐标,以使在每个奇数层仅检索2个子树中的一个。
        从K-D树中删除一个结点是代价很高的,很清楚删除子树的根受到子树中结点个数的限制。用TPL(T)表示树T总的路径长度。可看出树中子树大小的总和为TPL(T)+N。 以随机方式插入N个点形成树的TPL是O(N*log2N),这就意味着从一个随机形成的K-D树中删除一个随机选取的结点平均代价的上界是O(log2N)

    1.5 KD树的最近邻搜索算法

           现实生活中有许多问题需要在多维数据的快速分析和快速搜索,对于这个问题最常用的方法是所谓的 kd 树。在 k-d 树中进行数据的查找也是特征匹配的重要环节,其目的是检索在k-d树中与查询点距离最近的数据点。在一个N维的笛卡儿空间在两个点之间的距离是由下述公式确定:  

           

            下面,以两个简单的实例(例子来自图像局部不变特性特征与描述一书)来描述最邻近查找的基本思路。

    1.5.1 举例:查询点(2.1,3.1)

            

        星号表示要查询的点(2.1,3.1)。通过二叉搜索,顺着搜索路径很快就能找到最邻近的近似点,也就是叶子节点(2,3)。而找到的叶子节点并不一定就是最邻近的,最邻近肯定距离查询点更近,应该位于以查询点为圆心且通过叶子节点的圆域内。为了找到真正的最近邻,还需要进行相关的‘回溯'操作。也就是说,算法首先沿搜索路径反向查找是否有距离查询点更近的数据点。

        以查询(2.1,3.1)为例:

    1. 二叉树搜索:先从(7,2)点开始进行二叉查找,然后到达(5,4),最后到达(2,3),此时搜索路径中的节点为<(7,2),(5,4),(2,3)>,首先以(2,3)作为当前最近邻点,计算其到查询点(2.1,3.1)的距离为0.1414,
    2. 回溯查找:在得到(2,3)为查询点的最近点之后,回溯到其父节点(5,4),并判断在该父节点的其他子节点空间中是否有距离查询点更近的数据点。以(2.1,3.1)为圆心,以0.1414为半径画圆,如下图所示。发现该圆并不和超平面y = 4交割,因此不用进入(5,4)节点右子空间中(图中灰色区域)去搜索;
    3. 最后,再回溯到(7,2),以(2.1,3.1)为圆心,以0.1414为半径的圆更不会与x = 7超平面交割,因此不用进入(7,2)右子空间进行查找。至此,搜索路径中的节点已经全部回溯完,结束整个搜索,返回最近邻点(2,3),最近距离为0.1414。

    1.5.2 举例:查询点(2,4.5)

          一个复杂点了例子如查找点为(2,4.5),具体步骤依次如下:

    1. 同样先进行二叉查找,先从(7,2)查找到(5,4)节点,在进行查找时是由y = 4为分割超平面的,由于查找点为y值为4.5,因此进入右子空间查找到(4,7),形成搜索路径<(7,2),(5,4),(4,7)>,但(4,7)与目标查找点的距离为3.202,而(5,4)与查找点之间的距离为3.041,所以(5,4)为查询点的最近点;
    2. 以(2,4.5)为圆心,以3.041为半径作圆,如下图所示。可见该圆和y = 4超平面交割,所以需要进入(5,4)左子空间进行查找,也就是将(2,3)节点加入搜索路径中得<(7,2),(2,3)>;于是接着搜索至(2,3)叶子节点,(2,3)距离(2,4.5)比(5,4)要近,所以最近邻点更新为(2,3),最近距离更新为1.5;
    3. 回溯查找至(5,4),直到最后回溯到根结点(7,2)的时候,以(2,4.5)为圆心1.5为半径作圆,并不和x = 7分割超平面交割,如下图所示。至此,搜索路径回溯完,返回最近邻点(2,3),最近距离1.5。

        上述两次实例表明,当查询点的邻域与分割超平面两侧空间交割时,需要查找另一侧子空间,导致检索过程复杂,效率下降。

        一般来讲,最临近搜索只需要检测几个叶子结点即可,如下图所示:  

               

            但是,如果当实例点的分布比较糟糕时,几乎要遍历所有的结点,如下所示:

              

            研究表明N个节点的K维k-d树搜索过程时间复杂度为:tworst=O(kN1-1/k)。

           参考统计学习方法一书上的内容,再来总结下 kd 树的最近邻搜索算法:

    • 输入:以构造的kd树,目标点x;
    • 输出:x 的最近邻
    • 算法步骤如下:
    1. 在 kd 树种找出包含目标点x的叶结点:从根结点出发,递归地向下搜索kd树。若目标点x当前维的坐标小于切分点的坐标,则移动到左子结点,否则移动到右子结点,直到子结点为叶结点为止。
    2. 以此叶结点为“当前最近点”。
    3. 递归的向上回溯,在每个结点进行以下操作:
      1. (a)如果该结点保存的实例点比当前最近点距离目标点更近,则更新“当前最近点”,也就是说以该实例点为“当前最近点”。
      2. (b)当前最近点一定存在于该结点一个子结点对应的区域,检查子结点的父结点的另一子结点对应的区域是否有更近的点。具体做法是,检查另一子结点对应的区域是否以目标点位球心,以目标点与“当前最近点”间的距离为半径的圆或超球体相交:
    4. 如果相交,可能在另一个子结点对应的区域内存在距目标点更近的点,移动到另一个子结点,接着,继续递归地进行最近邻搜索;
    5. 如果不相交,向上回溯。
    6. 当回退到根结点时,搜索结束,最后的“当前最近点”即为x 的最近邻点。

          如果实例点是随机分布的,那么kd树搜索的平均计算复杂度是O(NlogN),这里的N训练实例树。所以说,kd树更适用于训练实例数远大于空间维数时的k近邻搜索,当空间维数接近训练实例数时,它的效率会迅速下降,一降降到“解放前”:线性扫描的速度。

            同时,以上为了介绍方便,讨论的是二维或三维情形。但在实际的应用中,如SIFT特征矢量128维,SURF特征矢量64维,维度都比较大,直接利用k-d树快速检索(维数不超过20)的性能急剧下降,几乎接近贪婪线性扫描。假设数据集的维数为D,一般来说要求数据的规模N满足N»2D,才能达到高效的搜索。所以这就引出了一系列对k-d树算法的改进:BBF算法,和一系列M树、VP树、MVP树等高维空间索引树(下文kd树近邻搜索算法的改进:BBF算法,与球树、M树、VP树、MVP树)。

    复杂度分析:

     

    操作

    平均复杂度

    最坏复杂度

    新增节点

    O(logn)

    O(n)

    删除节点

    O(logn)

    O(n)

    最近邻搜索

    O(logn)

    O(n)

    2 kd树近邻搜索算法的改进:BBF算法

     

        也正因为上述k最近邻搜索算法的第4个步骤中的所述:“回退到根结点时,搜索结束”,每个最近邻点的查询比较完成过程最终都要回退到根结点而结束,而导致了许多不必要回溯访问和比较到的结点,这些多余的损耗在高维度数据查找的时候,搜索效率将变得相当之地下,那有什么办法可以改进这个原始的kd树最近邻搜索算法呢?

        从上述标准的 kd树 查询过程可以看出其搜索过程中的“回溯”是由“查询路径”决定的,并没有考虑查询路径上一些数据点本身的一些性质。一个简单的改进思路就是将“查询路径”上的结点进行排序,如按各自分割超平面(也称bin)与查询点的距离排序,也就是说,回溯检查总是从优先级最高(Best Bin)的树结点开始。

        针对此BBF机制,读者Feng&书童点评道:

    1. 在某一层,分割面是第ki维,分割值是kv,那么 abs(q[ki]-kv) 就是没有选择的那个分支的优先级,也就是计算的是那一维上的距离;
    2. 同时,从优先队列里面取节点只在某次搜索到叶节点后才发生,计算过距离的节点不会出现在队列的,比如1~10这10个节点,你第一次搜索到叶节点的路径是1-5-7,那么1,5,7是不会出现在优先队列的。换句话说,优先队列里面存的都是查询路径上节点对应的相反子节点,比如:搜索左子树,就把对应这一层的右节点存进队列。

        如此,就引出了本节要讨论的kd树最近邻搜索算法的改进:BBF(Best-Bin-First)查询算法,它是由发明sift算法的David Lowe在1997的一篇文章中针对高维数据提出的一种近似算法,此算法能确保优先检索包含最近邻点可能性较高的空间,此外,BBF机制还设置了一个运行超时限定。采用了BBF查询机制后,kd树便可以有效的扩展到高维数据集上。

    伪代码如下图所示(图取自图像局部不变特性特征与描述一书):

            

            还是以上面的查询(2,4.5)为例,搜索的算法流程为:

    1. 将(7,2)压人优先队列中;
    2. 提取优先队列中的(7,2),由于(2,4.5)位于(7,2)分割超平面的左侧,所以检索其左子结点(5,4)。同时,根据BBF机制”搜索左/右子树,就把对应这一层的兄弟结点即右/左结点存进队列”,将其(5,4)对应的兄弟结点即右子结点(9,6)压人优先队列中,此时优先队列为{(9,6)},最佳点为(7,2);然后一直检索到叶子结点(4,7),此时优先队列为{(2,3),(9,6)},“最佳点”则为(5,4);
    3. 提取优先级最高的结点(2,3),重复步骤2,直到优先队列为空。

        如你在下图所见到的那样:

                 

    3 球树、M树、VP树、MVP树

    3.1 球树

            咱们来针对上文内容总结回顾下,针对下面这样一棵kd树:

            

        现要找它的最近邻。

        通过上文2.5节,总结来说,我们已经知道:

    1、为了找到一个给定目标点的最近邻,需要从树的根结点开始向下沿树找出目标点所在的区域,如下图所示,给定目标点,用星号标示,我们似乎一眼看出,有一个点离目标点最近,因为它落在以目标点为圆心以较小长度为半径的虚线圆内,但为了确定是否可能还存在一个最近的近邻,我们会先检查叶节点的同胞结点,然而叶节点的同胞结点在图中所示的阴影部分,虚线圆并不与之相交,所以确定同胞叶结点不可能包含更近的近邻。           

             

    2、于是我们回溯到父节点,并检查父节点的同胞结点,父节点的同胞结点覆盖了图中所有横线X轴上的区域。因为虚线圆与右上方的矩形(KD树把二维平面划分成一个一个矩形)相交...

        如上,我们看到,KD树是可用于有效寻找最近邻的一个树结构,但这个树结构其实并不完美,当处理不均匀分布的数据集时便会呈现出一个基本冲突:既要求树有完美的平衡结构,又要求待查找的区域近似方形,但不管是近似方形,还是矩形,甚至正方形,都不是最好的使用形状,因为他们都有角。

           

           就是说,在上图中,如果黑色的实例点目标点星点再远一点,那么势必那个虚线圆会如红线所示那样扩大,以致与左上方矩形的右下角相交,既然相交了,那么势必又必须检查这个左上方矩形,而实际上,最近的点离星点的距离很近,检查左上方矩形区域已是多余。于此我们看见,KD树把二维平面划分成一个一个矩形,但矩形区域的角却是个难以处理的问题。

          解决的方案就是使用如下图所示的球树: 

            

            先从球中选择一个离球的中心最远的点,然后选择第二个点离第一个点最远,将球中所有的点分配到离这两个聚类中心最近的一个上,然后计算每个聚类的中心,以及聚类能够包含它所有数据点所需的最小半径。这种方法的优点是分裂一个包含n个殊绝点的球的成本只是随n呈线性增加。

          

        使用球树找出给定目标点的最近邻方法是,首先自上而下贯穿整棵树找出包含目标点所在的叶子,并在这个球里找出与目标点最靠近的点,这将确定出目标点距离它的最近邻点的一个上限值,然后跟KD树查找一样,检查同胞结点,如果目标点到同胞结点中心的距离超过同胞结点的半径与当前的上限值之和,那么同胞结点里不可能存在一个更近的点;否则的话,必须进一步检查位于同胞结点以下的子树。

        如下图,目标点还是用一个星表示,黑色点是当前已知的的目标点的最近邻,灰色球里的所有内容将被排除,因为灰色球的中心点离的太远,所以它不可能包含一个更近的点,像这样,递归的向树的根结点进行回溯处理,检查所有可能包含一个更近于当前上限值的点的球。

               

         球树是自上而下的建立,和KD树一样,根本问题就是要找到一个好的方法将包含数据点集的球分裂成两个,在实践中,不必等到叶子结点只有两个数据点时才停止,可以采用和KD树一样的方法,一旦结点上的数据点打到预先设置的最小数量时,便可提前停止建树过程。

         也就是上面所述,先从球中选择一个离球的中心最远的点,然后选择第二个点离第一个点最远,将球中所有的点分配到离这两个聚类中心最近的一个上,然后计算每个聚类的中心,以及聚类能够包含它所有数据点所需的最小半径。这种方法的优点是分裂一个包含n个殊绝点的球的成本只是随n呈线性增加(注:本小节内容主要来自参考条目19:数据挖掘实用机器学习技术,[新西兰]Ian H.Witten 著,第4章4.7节)。

    3.2 VP树与MVP树简介

        高维特征向量的距离索引问题是基于内容的图像检索的一项关键技术,目前经常采用的解决办法是首先对高维特征空间做降维处理,然后采用包括四叉树kd树R树族等在内的主流多维索引结构,这种方法的出发点是:目前的主流多维索引结构在处理维数较低的情况时具有比较好的效率,但对于维数很高的情况则显得力不从心(即所谓的维数危机) 。

        实验结果表明当特征空间的维数超过20 的时候,效率明显降低,而可视化特征往往采用高维向量描述,一般情况下可以达到10^2的量级,甚至更高。在表示图像可视化特征的高维向量中各维信息的重要程度是不同的,通过降维技术去除属于次要信息的特征向量以及相关性较强的特征向量,从而降低特征空间的维数,这种方法已经得到了一些实际应用。

        然而这种方法存在不足之处采用降维技术可能会导致有效信息的损失,尤其不适合于处理特征空间中的特征向量相关性很小的情况。另外主流的多维索引结构大都针对欧氏空间,设计需要利用到欧氏空间的几何性质,而图像的相似性计算很可能不限于基于欧氏距离。这种情况下人们越来越关注基于距离的度量空间高维索引结构可以直接应用于高维向量相似性查询问题。

        度量空间中对象之间的距离度量只能利用三角不等式性质,而不能利用其他几何性质。向量空间可以看作由实数坐标串组成的特殊度量空间,目前针对度量空间的高维索引问题提出的索引结构有很多种大致可以作如下分类,如下图所示:

            

    其中,VP树和MVP树中特征向量的举例表示为:

    1. UESTC_HN_AY_GUOBO:现在主要是在kdtree的基础上有了mtree或者mvptree,其实关键还是pivot的选择,以及度量空间中算法怎么减少距离计算;
    2. mandycool:mvp-tree,是利用三角形不等式来缩小搜索区域的,不过mvp-tree的目标稍有不同,查询的是到query点的距离小于某个值r的点;另外作者test的数据集只有20维,不知道上百维以后效果如何,而减少距离计算的一个思路是做embedding,通过不等式排除掉一部分点。

        更多内容请参见论文1:DIST ANCE-BASED INDEXING FOR HIGH-DIMENSIONAL METRIC SP ACES,作者:Tolga Bozkaya & Meral Ozsoyoglu,及论文2:基于度量空间高维索引结构VP-tree及MVP-tree的图像检索,王志强,甘国辉,程起敏。

        nearest neighbor algorithms相关的论文:http://scholar.google.com.hk/scholar?q=nearest+neighbor+algorithms&btnG=&hl=zh-CN&as_sdt=0&as_vis=1(其中,这篇可以看下:Spill-Trees,An investigation of practical approximate nearest neighbor algorithms)。
     

    KD树详解:https://blog.csdn.net/Galaxy_yr/article/details/89285069?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_utm_term-1&spm=1001.2101.3001.4242

    KD树:https://www.cnblogs.com/kexinxin/p/11795447.html

    从K近邻算法、距离度量谈到KD树、SIFT+BBF算法:https://blog.csdn.net/v_july_v/article/details/8203674

     

     

    展开全文
  • 最邻近点和kd树详解

    2019-11-30 13:51:50
    1 什么是kd树 kd树的全称是k-dimensional树,是一种用于是对数据点在k维空间中划分的一种数据结构。其实Kd-树是一种平衡二叉树,将多维空间按照一定的规则进行划分,将最终划分的空间部分作为一个子节点,同样的方式...
  • Knn算法 kd树详解

    2019-05-17 10:06:51
    上面我们将kd树构建好了,那如何利用kd树进行k近邻搜索呢? 看看书上对于算法的描述:   哇,反正一开始看,就是云里雾里,说的啥玩意。别慌,依旧是看实例(智商不够,看实例): 实例1   ...
  •  如上算法所述,kd树的构建是一个递归过程,我们对左子空间和右子空间内的数据重复根节点的过程就可以得到一级子节点(5,4)和(9,6),同时将空间和数据集进一步细分,如此往复直到空间中只包含一个数据点。...
  • 关于knn算法,对特征空间进行划分的方法为计算新的输入实例与训练实例之间的距离,因为在特征空间中2个特征实例的相似程度可以用距离来表示。...kd树(k-dimensional树的简称) 是一种对k维空间中的实例点进...
  • kd树算法原理详解及C++实现

    千次阅读 多人点赞 2021-07-29 09:58:03
    kd树算法原理详解及实现1 前言2 kd树基本思路1)问题提出2)切割3)搜寻4)递归3 kd树算法原理1)kd树结构2)构造kd树的例子3)kd树上的kNN算法4 结语   阅读本文之前先阅读kNN(k-Nearest Neighbours)原理...
  • PCL之kd-tree详解

    2022-05-15 08:46:51
    kd,即k-dimension,kd树就是k维树,由于点云所在空间几乎都是三维的,所以最常见的也是3d树。 考虑到演示方便,所以用二维空间中的数据来做一点说明,假设现有六个数据点{(2,3),(5,4),(9,6),(4,7),(8,...
  • 构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分,构成一系列的k维超矩形区域,kd树的每个结点对应一个k维超矩形区域。如图1所示: 特征空间划分   构造平衡kd树的算法如下:    输入:...
  • 5、kd树构建及查询实现 import numpy as np class TreeNode: def __init__(self, s, d): self.vec = s # 特征向量 self.Dimension = d # 即划分空间时的特征维度,这里选取方差最大的维度 self.left = None # 左子...
  • 2.2、构建KD树 2.3、实例 3、程序示例 4、参考链接 1、介绍 kd-tree简称k维树,是一种空间划分的数据结构。常被用于高维空间中的搜索,比如范围搜索和最近邻搜索。kd-tree是二进制空间划分树的一种特殊情况 ...
  • 算法解析:KD树

    2018-09-25 16:38:25
    从概念的角度讲,它是一种高纬数据的快速查询结构,本文首先介绍1维数据的索引查询,然后介绍2维KD树的创建和查询,相关定理和推论也简单列出,本文争取用15分钟的时间,让大家快速理解KD树。 2. 1维数据的查询 ...
  • Kd Tree算法详解

    千次阅读 2020-05-24 21:51:29
    kd树(k-dimensional树的简称),是一种分割k维数据空间的数据结构,主要应用于多维空间关键数据的近邻查找(Nearest Neighbor)和近似最近邻查找(Approximate Nearest Neighbor)。 一、Kd-tree 其实KDTree就是二叉...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,031
精华内容 412
关键字:

kd树详解