对于最近邻搜索问题有很多工作,所以我想知道我是否想做fixed radius range search,我可以利用这些算法进行最近邻搜索吗?
也许我可以一遍又一遍地进行第k次最近邻搜索,直到找到超出半径范围的点,但我想这可能会造成很多浪费。
答案 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)
所以,你已经拥有了实现对超球内点的有效搜索所需的一切:
使用包含它们的超立方体的索引元组将输入点推入空间哈希。
给定一个点p
,搜索的方法是确定它所在的超立方体A
,然后使用index-deltas集合,获取邻居超立方体集{{ 1}}可能包含比N
更近的点。
从空间哈希中检索属于超立方体r
的点,并检查哪些点接近N
。
可以执行一些额外的优化,因为不检查A中的点,因为它们保证足够接近。可以根据p
相对于p
的位置执行N的预过滤。
请注意,选择A
可以在拥有小超立方体和不太大的集s = r / sqrt(d)
之间提供一个很好的折衷方案。
每次在树上向下一级时,检查它所代表的空间是否与查询超球相交。如果确实如此,你会继续关注它,否则你会完全从搜索中丢弃它。
答案 3 :(得分:0)
一个简单的解决方案是在sklearn.neighbors.KDTree中使用query_radius函数:
格式为:
query_radius(X, r, return_distance=False, count_only=False, sort_results=False)