【发布时间】:2023-06-28 13:21:01
【问题描述】:
一般问题
首先让我们更一般地解释一下这个问题。我有一组具有 x,y 坐标的点,并希望找到最佳的唯一邻居对,以使所有对中的邻居之间的距离最小化,但点不能用于一对以上。
一些简单的例子
注意:点不是有序的,x 和 y 坐标都将在 0 到 1000 之间变化,但为了简单起见,在下面的示例中 x==y 并且项目是有序的。
首先,假设我有以下点矩阵:
matrix1 = np.array([[1, 1],[2, 2],[5, 5],[6, 6]])
对于此数据集,输出应为 [0,0,1,1],因为点 1 和 2 彼此最接近,而点 3 和 4 则提供对 0 和 2。
第二,两点不能有相同的伙伴。如果我们有矩阵:
matrix2 = np.array([[1, 1],[2, 2],[4, 4],[6, 6]])
这里pt1和pt3距离pt2最近,但pt1相对更近,所以输出应该还是[0,0,1,1]。
第三,如果我们有矩阵:
matrix3 = np.array([[1, 1],[2, 2],[3, 3],[4, 4]])
现在 pt1 和 pt3 再次最接近 pt2,但现在它们的距离相同。现在输出应该再次是[0,0,1,1],因为 pt4 最接近 pt3。
第四,在点数不均匀的情况下,最远的点应该设为nan,例如
matrix4 = np.array([[1, 1],[2, 2],[4,4]])
应该输出[0,0,nan]
第五,在三个或三个以上点的距离完全相同的情况下,配对可以是随机的,例如
matrix5 = np.array([[1, 1],[2, 2],[3, 3]])
'[0,0,nan]and[nan,0,0]` 的输出都应该没问题。
我的努力
使用 sklearn:
import numpy as np
from sklearn.neighbors import NearestNeighbors
data = matrix3
nbrs = NearestNeighbors(n_neighbors=len(data), algorithm="ball_tree")
nbrs = nbrs.fit(data)
distances,indices = nbrs.kneighbors(data)
这会输出实例:
array([[0, 1, 2, 3],
[1, 2, 0, 3],
[2, 1, 3, 0],
[3, 2, 1, 0]]))
第二列提供最近的点:
nearinds = `indices[:,1]`
接下来如果列表中有重复,我们需要找到最近的距离:
if len(set(nearinds) != len(nearinds):
dupvals = [i for i in set(nearinds) if list(nearinds).count(i) > 1]
for dupval in dupvals:
dupinds = [i for i,j in enumerate(nearinds) if j == dupval]
dupdists = distances[dupinds,1]
使用这些 dupdists,我可以发现一个比另一个更接近 pt:
if len(set(dupdists))==len(dupdists):
duppriority = np.argsort(dupdists)
使用duppriority 值,我们可以提供更接近的 pt 其正确的配对。但是要给另一个点它的配对将取决于它的第二个最近配对以及所有其他点到同一点的距离。此外,如果两个点到它们最近点的距离相同,我也需要去一个更深一层:
if len(set(dupdists))!=len(dupdists):
dupdists2 = [distances[i,2] for i,j in enumerate(inds) if j == dupval]```
if len(set(dupdists2))==len(dupdists2):
duppriority2 = np.argsort(dupdists2)
等等。
我有点卡在这里,也觉得这种方式效率不高,特别是对于比 4 个点更复杂的条件,并且多个点与一个或多个最近的、第二最近的点等距离相似。
我还发现 scipy 有一个类似的单行命令可以用来获取距离和索引:
from scipy.spatial import cKDTree
distances,indices = cKDTree(matrix3).query(matrix3, k=len(matrix3))
所以我想知道一个是否会比另一个更好。
我想解决的更具体的问题
我有一个点列表,需要将它们与之前的点列表进行最佳匹配。点的数量通常是有限的,范围从 2 到 10,但随着时间的推移通常是一致的(即随着时间的推移,它不会在值之间跳跃太多)。数据往往看起来像:
prevdat = {'loc': [(300, 200), (425, 400), (400, 300)], 'contid': [0, 1, 2]}
currlocs = [(435, 390), (405, 295), (290, 215),(440,330)]`
时间点通常比其他人更接近自己。因此,我应该能够随着时间的推移链接点的身份。然而,有一些复杂的问题需要克服:
- 有时当前和以前的点数不相等
- 点通常具有相同的最近邻居,但不应分配相同的标识
- 点有时与最近邻的距离相同(但不太可能与第二、第三最近邻等)。
任何有助于解决我的问题的建议将不胜感激。我希望我上面的例子和努力会有所帮助。谢谢!
【问题讨论】:
-
虽然我不太清楚你在做什么,但我最初的反应是,你为什么不使用cKDTree。一旦你有了这棵树,就会有许多帮助方法可以让你查询邻域、距离等。
-
我已阅读并理解您的操作,但不是问题所在。您是否正在寻找对距离总和的一些全局优化?如果是这样,这听起来像是matching 的变体。
-
FWIW 在我最近的需要最近邻搜索的工作中,我似乎记得
scipy.spatial.cKDTree比sklearn产品快得多。但是你描述的精确匹配问题听起来很困难——可能是背包问题的一个变体,对于精确的解决方案来说至少是NP-Complete。你能容忍近似解吗? -
有一个
O(V^2E)=O(n^3)(网格图的^3,这里可以“有点”,或者一般情况下的^4)。 here. -
@Gulzar 我正在查看问题的最大最小公式,但是你是对的,我不确定这相当于哪一个。 (当您回复时,我正在编辑我的评论,抱歉。)
标签: python numpy scipy pairing neighbours