KD tree算法是KNN(K-nearest neighbor)实现的重要算法之一,下面我们先简单介绍一些KNN的知识,然后开始我们KD tree的讲解。
KNN分类算法
KNN是一种简单的分类方法:
分类时,对新的实例,根据k个最近邻的训练实例的类别,通过多数表决等方式进行预测。
以上是《统计学习方法》中对KNN的解释,简单明了。那么问题就在于如何快速有效找到K个近邻就是该算法的关键了。关于KNN算法的详细知识,请看另一篇文章《统计学习方法之K近邻法》,下面我们来简单学习一下如何快速找到K个近邻的样本。
KD Tree
为了对训练数据进行快速k近邻搜索,我们使用特殊的数据结构存储训练数据-kd Tree方法。
kd Tree是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是二叉树,表示对k维空间的一个划分(partition),构造kd Tree相当于奖k维空间划分,构成一系列的k维超矩形区域。
以上是《统计学习方法》对KD Tree的解释,同样简单明了。
KD Tree方法即将空间根据坐标不断划分,划分成k块,如下图所示:
构建 KD-Tree
以上是《统计学习方法》书中对构造平衡kd Tree的算法描述。我们进行分析。
1.1 为什么要构造“平衡“kd Tree?
学过快速排序的读者们都知道,当我们取得的K值刚好保证左右两边的数的个数相等时,快排算法的时间复杂度最低,而当K值取到最大或最小时算法时间复杂度最高。为此提出了随机快速排序算法。以此为基础,我们可以分析知道为什么要构造“平衡“kd Tree了。很简单,为了提高搜索效率。
为了更加简单明了的解释,我们据如下例子:
1 2 3 4 5 6 7 8 9
我们将以上数字分为两部分:
1) >=5;
2) <5;
为了找到数字3,如果我们知道3比5小,那么我们只需要搜索5左边的四个数字即可。
如果我们将以上数字分成以下两部分:
1) >=9;
2) <9;
我们知道3比9小,那么我们需要搜索9左边的8个数字,这样的效率明显没有上一种的效率高。
2.2 如何构造平衡kd Tree?
中位数法。中位数:将一组数据按大小顺序排列,处在最中间位置的一个数叫做这组数据的中位数 。
这就是中位数的定义,初中的知识了。那么如何快速找到中位数呢?先排序后查找?还是找到前n/2个数然后得到中位数呢?显然效率不高。我们利用快速排序 的思想进行求解。先给出代码:
private KDNode findMiD(int begin, int end, int flag) {
if (begin >= end) {
return null;}
KDNode lastNode = set.get(end-1);//得到该树节点样本节点集最后一个节点
int dia = flag%(KDNode.dimension);//得到该树节点分割的维数
float keyValue = lastNode.get(dia);//得到分割点
//一趟快排算法中的交换部分
int LastSmall = begin-1;
for (int i=begin; i<end-1; i++) {
if (set.get(i).get(dia) < keyValue) {
exchange(++LastSmall, i);
}
}
exchange(end-1, ++LastSmall);
//快排算法中的交换部分结束
//如果该分割点正好为中位数,则返回该位置的样本节点,如果中位数点小于分割点,则说明中位数在前半部分,故递归搜索前半部分,否则搜索后半部分。
if (midPos == LastSmall)
return set.get