KD树是用于一种分割k维数据空间的数据结构。它是由最基本的二叉树发展而来的。采用递归的方法对数据进行分割。在计算机视觉进行特征匹配,寻找近邻时通常会用到KD树。
在具体介绍KD树。我们先来了解一下二叉树。对于一维数据的划分我们通常使用它。二叉树具有如下的性质:
- 若它的左子树不为空,则它的左子树节点上的值皆小于它的根节点。
- 若它的右子树不为空,则它的右子树节点上的值皆大于它的根节点。
- 它的左右子树也分别是二叉查找树
如何构造二叉树呢?
首先把数据进行排序,选取中位数作为根节点的值。然后对小于根节点值得数据放在进行同样的操作,选取的中值做为根节点的左子树 。右子树的操作同样如此。对所有节点都进行如此递归的操作,直到分完全部的数据。
下面简单介绍一下KD树,既然是由二叉树发展而来的,那么就面临着两个问题:
1. 根据哪个维度对数据进行划分?
2. 划分是根节点是如何选取的?
我们通常是先计算每个维度数据的方差,选取方差最大的方向作为我们划分的维度(这是为了保证我们的数据可以尽快的分开)。选取好划分的维度后我们队这一维度的数据进行从小到大循序进行排序。选取中位数作为我们的根节点。我们选取好根节点后,对剩下的数据小与根节点数据也进行上述操作,选取左子树。同样的选取右子树。递归的分完所有的数据。
下面举个例子。假设有6个二维数据点{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},数据点位于二维空间内(如图1中黑点所示)。k-d树算法就是要确定图1中这些分割空间的分割线(多维空间即为分割平面,一般为超平面)。下面就要通过一步步展示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)}。
如算法所述,k-d树的构建是一个递归的过程。然后对左子空间和右子空间内的数据重复根节点的过程就可以得到下一级子节点(5,4)和(9,6)(也就是左右子空间的'根'节点),同时将空间和数据集进一步细分。如此反复直到空间中只包含一个数据点,如图1所示。最后生成的k-d树如图3所示。