仅使用点云作为查询点的D维k近邻搜索的C++数据结构

C++ Data Structure for k Nearest Neighbour Search in D dimension using only point cloud as query points

本文关键字:近邻 搜索 数据结构 C++ 查询      更新时间:2023-10-16

在具有周期性边界条件的D维空间中,我有一个由N个点组成的点云,其中N的范围从500到10^8,D的范围从1到20。点的分布变化很大,从完全均匀到非常密集。对于点云中的每个点,我需要找到离该点最近的k个邻居。我还需要找出每个点的距离内有多少点,特别是最大范数距离。我不需要知道半径内有哪些点,只需要知道有多少,但这将是一个很好的补充。

我尝试过kd树,但它们不能处理包装边界,对于较大的树,复制是不可行的。此外,它在更高的维度上会变慢。

我刚刚遇到Vantage Point Trees,并尝试了一些代码,但它比kd树慢。尽管我发现的代码使用递归搜索方法,没有批处理。积极的一面是,它可以原生地处理包装条件,因此不需要复制。

我想看看我是否可以通过转换为迭代方法来从VP树中挤出更多的性能,看看我是否能够批量搜索,但我有一个想法。所有这些数据结构都用于查找任意查询点的最近邻居,而我的查询点仅限于点云中的点。我想这个限制可能会允许一些更高性能的结构(也许是某种导航网格?)。我试着搜索可以处理这个问题的结构,但我的谷歌功能失败了。所以我想知道是否有人知道可以处理以下问题的数据结构:

  • 处理少量和大量的分数,即500-10^8分
  • 最多可处理20个尺寸
  • 使用周期性边界(即平面环面)
  • 使用maxnorm距离(软要求。欧几里得可以给我一个潜在的列表,我可以手动筛选,但maxnorm是首选)
  • 可以找到查询点的k-NN,也可以找到距离查询点有多少点
  • 查询点只是结构中的点,而不是任意点
  • 可以对查询进行批处理。即,我需要为点云中的每个点找到第k个NN。我还需要找到每个点I在d[I]内存在多少点。也就是说,每个点都有不同的搜索半径
  • 不需要支持插入或删除

感谢

我怀疑你这个非常复杂的问题是否有一个完整而明确的答案,所以我只是分享我的想法。您的问题规范将许多不能很好地结合在一起的东西(高维、非欧几里得度量、完全不同类型的查询)。如果一个算法必须假设一般情况,那么它必然是缓慢的。

让我们先来梳理一下已知良好数据结构的特殊情况。

  • 如果尺寸为1,请使用排序后的地图
  • 如果您的维度是2-3(甚至可能是4),则排序查找和地理数据库应该是最佳的。https://en.wikipedia.org/wiki/R-tree
  • 如果你的点具有更高的维度,但相关性非常强,那么降维可能会将你的点云映射到维度如此低的点云,并将问题简化为一个简单的问题。https://en.wikipedia.org/wiki/Dimensionality_reduction
  • 如果你的点数低于10^6,暴力是最便宜的。只需使用所有点的度量计算距离,然后对k个结果进行部分排序。这些简单的缓存一致性计算比使用树结构更快。http://en.cppreference.com/w/cpp/algorithm/partial_sort
  • 如果你的k是有界的,那么说k<=20,并且您针对查询时间进行了优化,预计算一个包含所有结果的表
  • 如果只有少数维度是周期性的,我认为您应该调整kd-tree算法来处理它们(为那些类似于Vantage Point Trees的维度添加更复杂的比较节点)

如果所有这些都不适用(如果你有一个实际的应用,请与我们分享),你的案例是非常通用的。

除了你提到的算法,你还应该尝试几何近邻访问树(GNAT)。http://infolab.stanford.edu/~sergey/near.html它们适用于通用度量(包括您的度量),也处理非均匀分布。

此外,我认为你的期望值很高。您可以将其与良好的kd树实现进行比较(例如,https://github.com/mariusmuja/flann)它仅用欧几里得度量来解决问题。如果这需要很长时间,那么您不应该期望更通用的指标能够更快地解决。

诚然,更通用的方法不能使用查询是云中点的约束。如果有这样的解决方案,我将非常感兴趣。

如果Java是一种选择(现在的性能类似于C++),请查看ELKI库。它提供了许多多维索引的实现,包括降维和空间填充曲线的方法。它还为kNN(欧式/非欧式)、聚类检测、范围查询等提供了许多算法(您通常可以使用自定义距离度量定义自己的查询过滤器)。对于kNN,我可以特别推荐CoverTree和PH Tree(稍微慢一点,但更通用),我测试了这两种树的27个维度。PH树特别适合高度聚类和大型数据集(我测试了超过100000000个点)。(免责声明:PH树是基于我自己的研究,但我认为你的用例非常适合。)

然而,据我所知,这些方法都不允许像你建议的那样进行特殊的优化。