我有大约16,000个75维数据点,对于每个点,我想找到它的k个最近邻居(使用欧几里得距离,目前k=2以使问题简化)。
我的第一个想法是使用kd树实现,但是随着维数增长,它们变得相当低效。在我的示例实现中,它只比穷举搜索略快一些。
我的下一个想法是使用PCA(主成分分析)来减少维数,但我想知道:是否有聪明的算法或数据结构可以在合理的时间内精确解决这个问题?
我有大约16,000个75维数据点,对于每个点,我想找到它的k个最近邻居(使用欧几里得距离,目前k=2以使问题简化)。
我的第一个想法是使用kd树实现,但是随着维数增长,它们变得相当低效。在我的示例实现中,它只比穷举搜索略快一些。
我的下一个想法是使用PCA(主成分分析)来减少维数,但我想知道:是否有聪明的算法或数据结构可以在合理的时间内精确解决这个问题?
使用kd-tree
不幸的是,在高维度下,这种数据结构受到维数灾难的严重影响,导致其搜索时间与暴力搜索相当。
减少维数
降维 是一个不错的方法,它在准确性和速度之间提供了公平的权衡。当您减少维数时,会失去一些信息,但会获得一些速度。
准确性指的是找到精确的最近邻(NN)。
当您想要减少数据所在的维度空间时,主成分分析(PCA)是一个不错的选择。
近似最近邻搜索(ANNS)是一种方法,您可以通过查找可能不是精确最近邻,而是它的良好近似值(例如,对于您正在寻找第一个NN,其为第四个NN)来满足自己。有没有一些聪明的算法或数据结构可以在合理的时间内完全解决这个问题?
这种方法会牺牲准确性,但显著提高性能。此外,找到良好的NN(接近查询)的概率相对较高。
您可以在我们的kd-GeRaF paper中介绍更多关于ANNS的内容。
将ANNS与降维结合起来是一个好主意。
局部敏感哈希(LSH)是解决高维最近邻问题的现代方法。其关键思想是将彼此靠近的点哈希到同一个桶中。因此,当查询到达时,它将被哈希到一个桶中,该桶(通常还有其相邻的桶)包含良好的NN候选项。
FALCONN 是一个很好的 C++ 实现,专注于余弦相似度。另一个很好的实现是我们的 DOLPHINN,它是一个更通用的库。
BK-Tree 不是一个坏的想法。看一下Nick's Blog on Levenshtein Automata。虽然他的重点是字符串,但它应该为其他方法提供了一个跳板。我能想到的另一件事是R-Trees,但我不知道它们是否已经被推广到大维度。我不能再多说了,因为我既没有直接使用过它们,也没有自己实现过它们。
一个非常常见的实现方法是对计算出的每个数据点的最近邻数组进行排序。 由于对整个数组进行排序可能非常昂贵,因此可以使用间接排序的方法,例如Python Numpy库中的Numpy.argpartition,只对您感兴趣的最接近的K个值进行排序。无需对整个数组进行排序。
上面@Grembo的答案应该大幅减少,因为您只需要K个最近的值,并且没有必要对每个点之间的距离进行排序。
如果您只需要K个邻居,这种方法将非常有效地降低计算成本和时间复杂度。
如果您需要排序后的K个邻居,请再次对输出进行排序。
请参阅