Kd-Tree,即K-dimensional tree,是一棵二叉树,树中存储的是一些K维数据。在一个K维数据集合上构建一棵Kd-Tree代表了对该K维数据集合构成的K维空间的一个划分,即树中的每个结点就对应了一个K维的超矩形区域(Hyperrectangle)。

在介绍Kd-tree的相关算法前,我们先回顾一下二叉查找树(Binary Search Tree)的相关概念和算法。k=1就是BST!

例如,图1中是一棵二叉查找树,其满足BST的性质。

图1 二叉查找树(来源:Wiki)

KD树的构建

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树:

问题1: 每次对子空间的划分时,怎样确定在哪个维度上进行划分?

最简单的方法就是轮着来,即如果这次选择了在第i维上进行数据划分,那下一次就在第j(j≠i)维上进行划分,例如:j = (i mod k) + 1。想象一下我们切豆腐时,先是竖着切一刀,切成两半后,再横着来一刀,就得到了很小的方块豆腐。

可是“轮着来”的方法是否可以很好地解决问题呢?再次想象一下,我们现在要切的是一根木条,按照“轮着来”的方法先是竖着切一刀,木条一分为二,干净利落,接下来就是再横着切一刀,这个时候就有点考验刀法了,如果木条的直径(横截面)较大,还可以下手,如果直径较小,就没法往下切了。因此,如果K维数据的分布像上面的豆腐一样,“轮着来”的切分方法是可以奏效,但是如果K维度上数据的分布像木条一样,“轮着来”就不好用了。因此,还需要想想其他的切法。

如果一个K维数据集合的分布像木条一样,那就是说明这K维数据在木条较长方向代表的维度上,这些数据的分布散得比较开,数学上来说,就是这些数据在该维度上的方差(invariance)比较大,换句话说,正因为这些数据在该维度上分散的比较开,我们就更容易在这个维度上将它们划分开,因此,这就引出了我们选择维度的另一种方法:最大方差法(max invarince),即每次我们选择维度进行划分时,都选择具有最大方差维度。

摘自:http://blog.csdn.net/junshen1314/article/details/51121582

KD树——k=1时就是BST,里面的数学原理还是有不明白的地方,为啥方差划分?的更多相关文章

  1. KD树的极简单笔记(待后续更新)

    今天(18.5.4)室友A突然问我算法怎么入门,兴奋之下给他安利了邓公的<数据结构>,然而他接着又问我能不能两周内快速入门,毕竟打算搞Machine Learning,然后掏出手机看了下他 ...

  2. 02-17 kd树

    目录 kd树 一.kd树学习目标 二.kd树引入 三.kd树详解 3.1 构造kd树 3.1.1 示例 3.2 kd树搜索 3.2.1 示例 四.kd树流程 4.1 输入 4.2 输出 4.3 流程 ...

  3. k临近法的实现:kd树

    # coding:utf-8 import numpy as np import matplotlib.pyplot as plt T = [[2, 3], [5, 4], [9, 6], [4, 7 ...

  4. 从K近邻算法谈到KD树、SIFT+BBF算法

    转自 http://blog.csdn.net/v_july_v/article/details/8203674 ,感谢july的辛勤劳动 前言 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章 ...

  5. k近邻法的C++实现:kd树

    1.k近邻算法的思想 给定一个训练集,对于新的输入实例,在训练集中找到与该实例最近的k个实例,这k个实例中的多数属于某个类,就把该输入实例分为这个类. 因为要找到最近的k个实例,所以计算输入实例与训练 ...

  6. <转>从K近邻算法、距离度量谈到KD树、SIFT+BBF算法

    转自 http://blog.csdn.net/likika2012/article/details/39619687 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章待写:1.KD树:2.神经 ...

  7. kd树 求k近邻 python 代码

      之前两篇随笔介绍了kd树的原理,并用python实现了kd树的构建和搜索,具体可以参考 kd树的原理 python kd树 搜索 代码 kd树常与knn算法联系在一起,knn算法通常要搜索k近邻, ...

  8. 从K近邻算法、距离度量谈到KD树、SIFT+BBF算法

    转载自:http://blog.csdn.net/v_july_v/article/details/8203674/ 从K近邻算法.距离度量谈到KD树.SIFT+BBF算法 前言 前两日,在微博上说: ...

  9. 一看就懂的K近邻算法(KNN),K-D树,并实现手写数字识别!

    1. 什么是KNN 1.1 KNN的通俗解释 何谓K近邻算法,即K-Nearest Neighbor algorithm,简称KNN算法,单从名字来猜想,可以简单粗暴的认为是:K个最近的邻居,当K=1 ...

随机推荐

  1. Android项目实战_手机安全卫士软件管家

    ###1.应用程序信息的flags 1. int flags = packageInfo.applicationInfo.flags2. 0000 0000 0000 0000 0000 0000 0 ...

  2. java 向上,向下转型

    在对Java学习的过程中,对于转型这种操作比较迷茫,特总结出了此文.例子参考了<Java编程思想>. 目录 几个同义词 向上转型与向下转型 例一:向上转型,调用指定的父类方法 例二:向上转 ...

  3. 关于在win7旗舰版32位上 安装 net4.0 的闪退问题研究 和安装sqlserver2008问题

    1.配置文件客户端[目标x86x64]的 可以安装 2.配置文件完全的目标x86x64的 出现闪退. 3.服务器核心的出现无法安装 安装 sqlserver 2008R2数据库 报错 \最后留下了它, ...

  4. H5 应用程序缓存(离线缓存)

    离线缓存这个功能的实现有以下步骤: 1,以nginx做web服务器为例,在mime.types文件中添加一行:text/cache-manifest     manifest,作用是为了让服务器识别该 ...

  5. Bomb HDU - 3555

    Bomb HDU - 3555 求1~n中含有49数的个数 #include<bits/stdc++.h> #define LL long long using namespace std ...

  6. [Luogu] P1233 木棍加工

    题目描述 一堆木头棍子共有n根,每根棍子的长度和宽度都是已知的.棍子可以被一台机器一个接一个地加工.机器处理一根棍子之前需要准备时间.准备时间是这样定义的: 第一根棍子的准备时间为1分钟: 如果刚处理 ...

  7. HDU 4027(线段树)

    HDU4027 题意:操作指令为0时,对区间[x,y]之间的数字进行开平方:指令为1的时候,对区间[x,y]之间的数字求和并输出: 思路:线段树处理就OK了,但是64位内的数最多开8次平方就为1了(开 ...

  8. Centos 7中,防火墙配置端口规则

    注意:firewalld服务有两份规则策略配置记录,配置永久生效的策略记录时,需要执行"reload"参数后才能立即生效: Permanent:永久生效的 RunTime:现在正在 ...

  9. Flask - 路由系统

    目录 Flask - 路由系统 @app.route()装饰器中的常用参数 methods : 当前 url 地址,允许访问的请求方式 endpoint:反向url地址,默认为视图函数名(url_fo ...

  10. spring boot.定时任务问题记录(TaskScheduler/ScheduledExecutorService异常)

    一.背景 spring boot的定时任务非常简单,只需要在启动类中加上@EnableScheduling注解,然后在对应的方法上配置@Scheduled就可以了,系统会自动处理并按照Schedule ...