如何利用最近邻搜索算法进行固定半径搜索?

时间:2015-04-23 03:30:12

标签: algorithm nearest-neighbor range-query

对于最近邻搜索问题有很多工作,所以我想知道我是否想做fixed radius range search,我可以利用这些算法进行最近邻搜索吗?

也许我可以一遍又一遍地进行第k次最近邻搜索,直到找到超出半径范围的点,但我想这可能会造成很多浪费。

4 个答案:

答案 0 :(得分:3)

不仅“有最近邻居搜索问题的工作很多”,但有很多问题要问你的问题。最重要的是尺寸数量。

如果您不确定维度的重要性,请务必检查我的answer

高维空间

假设你的点位于高维空间,你应该去Locality-Sensitive Hashing (LSH) 。该算法的一个很好的实现是E²LSH。如果您想自己实现它或者更好地了解发生的情况,它们还会提供slides。注意,E²LSH解决了R近邻问题的随机化版本,他们称之为(R,1 - δ) - 近邻问题,其中δ与近似有关,正如他们在manual中提到的那样。

您还可以查看我关于LSH here的答案。我在C ++中使用它,我强烈推荐它用于你想要执行的固定半径搜索!

低维空间

使用CGAL的spatial searching。在C ++中,我已经多次使用过它。同样,如果你想自己实现,你可以在他们拥有的漂亮文档中找到大量信息,并进行相对的谷歌查询。

顺便说一句,答案很好,所以你得到了+1。 :)

答案 1 :(得分:1)

如果你只有一个查询,那么这个问题是固定的O(n),其中n是点的数量,无论如何。

如果您有多个查询,那么这个问题是很好的探索问题,但它的解决方案比最近邻搜索更复杂。请参阅此文:http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.95.3191&rep=rep1&type=pdf

答案 2 :(得分:1)

d作为维数,r作为半径,我知道至少可以使用两种不同的方法:

使用空间哈希:

想象一下,问题空间按大小为s的网格划分为超立方体,以便s = r / sqrt(d)

关于s = r / sqrt(d)的有趣之处在于,该大小的超立方体内的任何两个点都保证距离等于或小于r

您可以对网格划分进行计算,以便每个超立方体都可以通过其一个角的索引形成的元组来识别。这些索引元组可以用作哈希结构的密钥(空间哈希)。

现在,这是困难的部分,您必须注意到,对于网格A的任何超立方体,都有一组相邻超立方体N = (N1, N2, ...),它们与给定超立方体的最小距离相等或者小于给定半径,几何上它们看起来像一个超球面。您可以将集合N的元素表示为网格索引相对于A的增量。请注意,这些索引增量仅取决于d

例如,在二维情况下,您具有以下几何结构:

   NNN    index deltas:    (-1,  2) ( 0,  2) ( 1,  2)
  NNNNN           (-2,  1) (-1,  1) ( 0,  1) ( 1,  1) ( 2,  1)
  NNANN           (-2,  0) (-1,  0) ( 0,  0) ( 1,  0) ( 2,  0)
  NNNNN           (-2, -1) (-1, -1) ( 0, -1) ( 1, -1) ( 2, -1)
   NNN                     (-1, -2) ( 0, -2) ( 1, -2)

所以,你已经拥有了实现对超球内点的有效搜索所需的一切:

  1. 使用包含它们的超立方体的索引元组将输入点推入空间哈希。

  2. 给定一个点p,搜索的方法是确定它所在的超立方体A,然后使用index-deltas集合,获取邻居超立方体集{{ 1}}可能包含比N更近的点。

  3. 从空间哈希中检索属于超立方体r的点,并检查哪些点接近N

  4. 可以执行一些额外的优化,因为不检查A中的点,因为它们保证足够接近。可以根据p相对于p的位置执行N的预过滤。

    请注意,选择A可以在拥有小超立方体和不太大的集s = r / sqrt(d)之间提供一个很好的折衷方案。

    使用k-d树或quad / octo /...-树:

    每次在树上向下一级时,检查它所代表的空间是否与查询超球相交。如果确实如此,你会继续关注它,否则你会完全从搜索中丢弃它。

答案 3 :(得分:0)

一个简单的解决方案是在sklearn.neighbors.KDTree中使用query_radius函数:

https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KDTree.html#sklearn.neighbors.KDTree.query_radius

格式为:

query_radius(X, r, return_distance=False, count_only=False, sort_results=False)