我有一个巨大的向量列表(~100k)(表示单词并使用随机索引计算)并且必须找到给定1个输入单词的前N个最接近的向量。我现在这样做的方法是按距离进行完整排序,然后提取前N个结果,但这需要太多时间才能使用,因为我必须计算100k距离。有更有效的方法吗?向量已经标准化,因此我只需在计算距离时计算点积。
向量存储在Java HashMap<String, Vector>
中,其中Vector是稀疏向量的la4j类。
答案 0 :(得分:3)
您可以将矢量放入空间感知容器中,例如R-tree或k-d tree或PK-Tree。
通过这种方式,您只需查看几个相邻的单元格,就可以在不迭代所有数据集的情况下找到这些点。不要忘记你不仅要在一个单元格中搜索,还要在相邻的单元格中进行搜索,而在多维空间中则需要搜索很多邻居。
更新:您仍需要手动测量距离。但是,您不需要遍历所有向量。
一个简单的解决方案 - 定义最大距离,迭代该距离内单元格内的所有向量,排序,选择前N个。
最优解决方案(更难开发) - 迭代搜索过程。例如,从输入向量vX所在的单个单元格开始,在此单元格中找到N个最接近的向量。如果vX与第N个找到的向量(最远的向量)之间的距离小于vX与尚未搜索的任何单元格的最近点之间的距离,则得到N个结果。否则,从最近的尚未搜索的单元格中添加矢量,然后重复该过程。这里最复杂的事情 - 跟踪已经搜索过的单元格以及接下来要做什么(特别是树的高度可变的PK树)。
权衡解决方案(不是很难开发,对你来说可能是合理的最佳选择) - 迭代搜索过程,你一直在树上。你从包含vX的叶子节点开始,如果它没有N个向量,或者如果vX更靠近单元格的边界,那么第N个找到的向量,你向上一级,并添加完整的子树从父节点开始。这样算法更简单,因为搜索区域总是矩形的。然而,最糟糕的情况(即,如果vX位于2个根单元格之间的边界上),则更糟糕 - 您将不得不迭代所有100k点。
答案 1 :(得分:0)
如果你知道你的向量在你的N维空间中或多或少地均匀分布,你就不需要空间树的所有复杂性。
相反,您可以将空间拆分为常规超立方网格,以便平均网格单元包含不到20个向量,并将单元格存储在HashMap<List<Integer>, List<Vector>>
中,其中键是网格单元格的整数坐标,值是列表相应单元格内的矢量。