`
grunt1223
  • 浏览: 422904 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

K Nearest Neighbor问题的解决——KD-TREE Implementation

阅读更多
命题一:
已知的1000个整数的数组,给定一个整数,要求查证是否在数组中出现?

命题二:
已知1000个整数的数组,给定一个整数,要求查找数组中与之最接近的数字?

命题三:
已知1000个Point(包含X与Y坐标)结构的数组,给定一个Point,要求查找数组中与之最接近(比如:欧氏距离最短)的点。

命题四:
已知1,000,000个向量,每个向量为128维;给定一个向量,要求查找数组中与之最接近的K个向量

  • 对于命题一,如果不考虑桶式、哈希等方式,常用的方法应该是排序后,使用折半查找。
  • 对于命题二,与命题一类似,比较折半查找得出的结果,以及附近的各一个元素,即可。整个过程相当于是把这个包含1000个数组的数据结构做成一颗二叉树,最后只需比较叶子节点与其父节点即可。
  • 对于命题三、四其中命题三和四就是所谓的Nearest Neighbor问题。一种近似解决的方法就是KD-TREE


高维向量的KNN检索问题,在图像等多媒体内容搜索中是相当关键的。关于高维向量的讨论,网上资料比较少;在此,我将一些心得分享给大家。
与二叉树相比,KD-TREE也采用类似的划分方式,只不过树中的各节点均是高维向量,因此划分的方式,采用随机或指定的方式选取一个维度,在该指定维度上进行划分;整体的思想就是采用多个超平面对数据集空间进行两两切分,这一点,有点类似于数据挖掘中的决策树。

一个运用KD-TREE分割二维平面的DEMO如下:



KD-Tree build的代码如下:
private ClusterKDTree(Clusterable[] points, int height, boolean randomSplit){
    if ( points.length == 1 ){
        cluster = points[0];
    }
    else {
        splitIndex = chooseSplitDimension//选取切分维度
            (points[0].getLocation().length,height,randomSplit);
        splitValue = chooseSplit(points,splitIndex);//选取切分值
			
        Vector<Clusterable> left = new Vector<Clusterable>();
        Vector<Clusterable> right = new Vector<Clusterable>();
        for ( int i = 0; i < points.length; i++ ){
            double val = points[i].getLocation()[splitIndex];
            if ( val == splitValue && cluster == null ){
                cluster = points[i];
            }
            else if ( val >= splitValue ){
                right.add(points[i]);
            } else {
                left.add(points[i]);
            }
        }
			
        if ( right.size() > 0 ){
            this.right = new ClusterKDTree(right.toArray(new
            Clusterable[right.size()]),
            randomSplit ? splitIndex : height+1, randomSplit);
        }
        if ( left.size() > 0 ){
            this.left = new ClusterKDTree(left.toArray(new
            Clusterable[left.size()]),randomSplit ? splitIndex : height+1,
            randomSplit);
        }
    }
}

private int chooseSplitDimension(int dimensionality,int height,boolean random){
    if ( !random ) return height % dimensionality;
    int rand = r.nextInt(dimensionality);
    while ( rand == height ){
        rand = r.nextInt(dimensionality);
    }
    return rand;
}
	
private double chooseSplit(Clusterable points[],int splitIdx){
    double[] values = new double[points.length];
    for ( int i = 0; i < points.length; i++ ){
	values[i] = points[i].getLocation()[splitIdx];
    }
    Arrays.sort(values);
    return values[values.length/2];//选取中间值以保持树的平衡
}


构建完一颗KD-TREE之后,如何使用它来做KNN检索呢?我用下面的图来表示(20s的GIF动画):



使用KD-TREE,经过一次二分查找可以获得Query的KNN(最近邻)贪心解,代码如下:
private Clusterable restrictedNearestNeighbor(Clusterable point, SizedPriorityQueue<ClusterKDTree> values){
    if ( splitIndex == -1 ) {
        return cluster; //已近到叶子节点
    }
		
    double val = point.getLocation()[splitIndex];
    Clusterable closest = null;
    if ( val >= splitValue && right != null || left == null ){
        //沿右边路径遍历,并将左边子树放进队列
        if ( left != null ){
            double dist = val - splitValue;
            values.add(left,dist);
        }
        closest = right.restrictedNearestNeighbor(point,values);
    }
    else if ( val < splitValue && left != null || right == null ) {
        //沿左边路径遍历,并将右边子树放进队列
        if ( right != null ){
            double dist = splitValue - val;
            values.add(right,dist);
        }
        closest = left.restrictedNearestNeighbor(point,values);
    }
    //current distance of the 'ideal' node
    double currMinDistance = ClusterUtils.getEuclideanDistance(closest,point);
    //check to see if the current node we've backtracked to is closer
    double currClusterDistance = ClusterUtils.getEuclideanDistance(cluster,point);
    if ( closest == null || currMinDistance > currClusterDistance ){
        closest = cluster;
        currMinDistance = currClusterDistance;
    }
    return closest;
}


事实上,仅仅一次的遍历会有不小的误差,因此采用了一个优先级队列来存放每次决定遍历走向时,另一方向的节点。SizedPriorityQueue代码的实现,可参考我的另一篇文章:
http://grunt1223.iteye.com/blog/909739

一种减少误差的方法(BBF:Best Bin First)是回溯一定数量的节点:
public Clusterable restrictedNearestNeighbor(Clusterable point, int numMaxBinsChecked){
    SizedPriorityQueue<ClusterKDTree> bins = new SizedPriorityQueue<ClusterKDTree>(50,true);
    Clusterable closest = restrictedNearestNeighbor(point,bins);
    double closestDist = ClusterUtils.getEuclideanDistance(point,closest);
    //System.out.println("retrieved point: " + closest + ", dist: " + closestDist);
    int count = 0;
    while ( count < numMaxBinsChecked && bins.size() > 0 ){
        ClusterKDTree nextBin = bins.pop();
	//System.out.println("Popping of next bin: " + nextBin);
	Clusterable possibleClosest = nextBin.restrictedNearestNeighbor(point,bins);
        double dist = ClusterUtils.getEuclideanDistance(point,possibleClosest);
        if ( dist < closestDist ){
	    closest = possibleClosest;
	    closestDist = dist;
	}
	count++;
    }
    return closest;
}


可以用如下代码进行测试:
public static void main(String args[]){
    Clusterable clusters[] = new Clusterable[10];
    clusters[0] = new Point(0,0);
    clusters[1] = new Point(1,2);
    clusters[2] = new Point(2,3);
    clusters[3] = new Point(1,5);
    clusters[4] = new Point(2,5);
    clusters[5] = new Point(1,1);
    clusters[6] = new Point(3,3);
    clusters[7] = new Point(0,2);
    clusters[8] = new Point(4,4);
    clusters[9] = new Point(5,5);
    ClusterKDTree tree = new ClusterKDTree(clusters,true);
    //tree.print();
    Clusterable c = tree.restrictedNearestNeighbor(new Point(4,4),1000);
    System.out.println(c);
}
  • 大小: 24.5 KB
  • 大小: 112.3 KB
2
1
分享到:
评论
1 楼 timedcy 2013-10-13  
Hi, 你这个20s的gif图是自己画的吗?

相关推荐

    kd-tree c语言代码

    kd树(kd-Tree)是一种在高维空间中进行数据索引的数据结构,它是一种特殊的二叉树,常用于多维空间中的数据搜索、分割和近邻查找等问题。C语言作为底层编程语言,适合实现这样的数据结构,因为它高效且直接。下面...

    kdtree.zip_kd-tree_kdtree_opencv KDtr

    【kd-tree】是一种数据结构,全称为“k-dimension tree”,是计算机科学中用于多维空间数据搜索的一种高效工具。它的设计目标是为了快速...通过对kd-tree的理解和熟练运用,我们可以解决很多复杂的高维数据处理问题。

    kd-Tree c++实现(kd树)

    **kd-Tree(k-d树)**是一种在高维空间中进行近似最近邻搜索(Approximate Nearest Neighbor Search)的高效数据结构。在计算机图形学、机器学习、数据挖掘等领域,kd-Tree广泛用于存储和检索几何对象,如点、线段、...

    基于c的kd-tree实现方法.zip

    -kdtree_nearest_neighbor:最近的邻居查询(一个或多个点) -kdtree_k_nearest_neighbors:单个查询点的kNN -kdtree_range_query:矩形范围查询 -kdtree_ball_query:查询距离某点有距离增量的样本

    matlab实现kd_tree

    这种结构使得kd-tree在高维空间中的近似最近邻搜索(Approximate Nearest Neighbor, ANN)和范围查询等操作变得高效。 在MATLAB中实现kd-tree,我们需要遵循以下步骤: 1. **构建kd-tree**: 首先,我们需要一个...

    KNN.zip_K._k nearest neighbor_knn kd tree_邻域

    为了解决这一问题,引入了数据结构——K-d树(k-dimensional tree),它是一种针对高维空间数据的分层数据结构,用于加速近邻搜索。 K-d树是二叉树的一种变体,专门用于处理多维空间中的数据。在构建K-d树的过程中...

    k近邻_kd-tree_kd树_vs2008_C++代码

    《k近邻算法与kd树在C++中的实现——基于VS2008》 k近邻(k-Nearest Neighbors, k-NN)算法是一种简单而有效的非参数机器学习方法,它属于实例驱动的学习策略,即通过查找训练集中与新样本最接近的k个样本来预测其...

    flann-1.7.1-src.zip_flann kd_kd tree_kd-tree_site:www.pudn.com_三

    标题中的“flann-1.7.1-src.zip”指的是该库的源代码版本1.7.1,而“kd_kd_tree_kd-tree”则涉及到FLANN中的一种关键数据结构——kd树。 **kd树**是基于二叉树的数据结构,专门用于多维空间中的数据索引和搜索。在...

    kd-tree-rcpp:使用Rcpp编写的KD树实现最邻近算法

    KD树(K-Dimensional Tree)是一种在高维空间中用于数据索引的数据结构,它特别适用于执行最近邻搜索(Nearest Neighbor Search)等任务。在机器学习和计算机图形学等领域,这种数据结构被广泛应用于快速查找与给...

    kdtree.rar_K._k-dimension_kdtree_kdtree的缺点_thisobi

    在高维数据处理中,K-d Tree是解决K最近邻(K-Nearest Neighbors, KNN)问题的有效工具,尤其是在大数据集上。 K-d Tree的概念基于二叉搜索树,但扩展到了多维空间。在构建K-d Tree时,数据集按照每一维轮流作为...

    基于KDtree的三维点云算法

    KD-tree的优势在于能够快速进行近邻搜索,例如K近邻(K-Nearest Neighbors, KNN)查询,这对于点云数据的处理至关重要,如点云滤波、特征提取和目标识别等任务。 在点云数据处理中,选择合适的数据结构对于处理效率...

    k-Nearest Neighbor Classification

    of the k nearest neighbors is then pooled by means of Dempster's rule of combination. This approach provides a global treatment of such issues as ambiguity and distance rejection, and imperfect ...

    4.2 最邻近规则分类(K-Nearest Neighbor)KNN算法应用_files.zip

    最邻近规则分类(K-Nearest Neighbor,简称KNN)是机器学习领域中最基础的算法之一,尤其在监督学习中扮演着重要角色。KNN算法应用广泛,尤其是在分类问题中,例如图像识别、文本分类等。这个压缩包文件可能包含了...

    Python机器学习k-近邻算法(K Nearest Neighbor)实例详解

    K-近邻算法(K Nearest Neighbor,KNN)是一种基本分类与回归方法。在机器学习领域,KNN算法的核心思想是通过测量不同特征值之间的距离来进行分类。基于输入样本与样本集中已知类别的样本之间的距离,将其归类于最近...

    ataiya/kdtree:一个 kd-tree mex lib,允许最近邻、k-最近邻、范围和球查询-matlab开发

    网站上的图片带有“ fulltest.m”字样此实现提供以下功能: - kdtree_build: kd 树构造 O( n log^2(n) ) - kdtree_delete:释放由 kdtree 分配的内存- kdtree_nearest_neighbor:最近邻查询(针对一个或多个点) - ...

    knn.rar_k-means matlab_k-nearest neighbor _k-近邻法分类器_knn matlab_m

    k-近邻法(k-Nearest Neighbor,简称k-NN)是一种基于实例的学习方法,属于监督学习的范畴,广泛应用于分类任务中。其核心思想是:给定一个未知类别的数据点,我们通过寻找已知类别数据集中与其最接近的k个邻居,...

    Nearest Neighbor Pattern Classification-1967

    在机器学习领域,有一种简单而直观的算法,被誉为“开山之作”,那就是由Cover T和Hart P于1967年提出的最近邻模式分类(Nearest Neighbor Pattern Classification),简称KNN(K-Nearest Neighbors)。KNN是一种...

    基于K-Nearest Neighbor和神经网络的糖尿病分类研究.pdf

    研究采用两种机器学习算法——K-Nearest Neighbor (KNN) 和神经网络进行糖尿病分类。KNN是一种基于实例的学习方法,通过寻找最近邻的样本进行分类。神经网络则模拟人脑神经元结构,通过学习和调整权重来实现复杂任务...

Global site tag (gtag.js) - Google Analytics