Python - 根据距离关联两个点列表
Posted
技术标签:
【中文标题】Python - 根据距离关联两个点列表【英文标题】:Python - Associate two list of points based on distance 【发布时间】:2021-12-01 17:33:51 【问题描述】:我有两组 n 点,作为 Numpy 数组,以随机顺序排列。我必须根据距离 (L2) 将两个列表之间的点关联起来,以便 list1 中的每个点都获得一个且唯一的对应点,即距离 list2 最接近的点。
我的问题:就计算时间而言,最快的方法是什么?
现在,我计算对称交叉范数矩阵(使用 scipy.spatial.distance_matrix)并通过循环从那里对点进行排序,以找到整个矩阵中的最低范数。然后删除相应的行和列并迭代直到矩阵为空。我想知道是否有已知的更快的方法来做到这一点。
[编辑]:这是我得到的代码和示例
import numpy as np
import numpy.ma as ma
import matplotlib.pyplot as plt
from scipy.spatial import distance_matrix
rng = np.random.default_rng()
lst1 = rng.random((10, 2))
lst2 = lst1 + 0.1 * rng.standard_normal(lst1.shape) # rng.random((10, 2))
mask = np.zeros((len(lst1), len(lst2)), dtype=bool)
dst = ma.array(distance_matrix(lst1, lst2), mask=mask)
ord_lst1 = []
ord_lst2 = []
for i in range(min(len(lst1), len(lst2))):
index = np.unravel_index(np.argmin(dst), shape=dst.shape)
ord_lst1.append(lst1[index[0], :])
ord_lst2.append(lst2[index[1], :])
dst[index[0], :] = ma.masked
dst[:, index[1]] = ma.masked
fig = plt.figure()
plt.grid(True)
plt.scatter(x=lst1[:, 0], y=lst1[:, 1], label="list1")
plt.scatter(x=lst2[:, 0], y=lst2[:, 1], label="list2")
for p1, p2 in zip(ord_lst1, ord_lst2):
plt.plot((p1[0], p2[0]), (p1[1], p2[1]), "--", color="black")
plt.legend()
输出如下:
如您所见,两个非常间隔的点之间的巨大关联可能会令人不安。但是,list1 在 (0.4, 0.6) 中的点与右上角的 list2 最接近,因此建立了关联并排除了这两个点的进一步关联。
谢谢:)
【问题讨论】:
请添加一些数据 如果 list2 中的某个点与某些 list1 点最接近怎么办? (您的图片没有显示这种模棱两可的情况)。在这种情况下,您似乎需要某种加权匹配。 @DaniMesejo:此处的数据是使用以下方法生成的:rng = np.random.default_rng() lst1 = rng.random((10, 2)) lst2 = lst1 + 0.03 * rng.standard_normal(lst1.形状) @MBo:当我寻找一个一对一的关联表时,对于 list1 中的给定点,list2 中的最近点应与其关联,因此无法将这些点与其他点关联.就好像我们首先关联最接近的,然后他们将它们从关联过程中取出。 list1: [1,0],[0,0] list2: [0,1], [1,2]。如果我们从左到右遍历 list1,我们有 0-1、1-0 索引对应,如果我们从右到左遍历,我们有 0-0、1-1 对应(看起来更直观) 【参考方案1】:查看 scipy.spatial.KDTree https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.KDTree.html
从列表 2 构建 kdTree,并在列表 1 中的每个点查询它
以下 sn-p 未测试,因此可能需要调试。这应该是您自己设计的开始
#L1 is numpy array with shape (N,2)
#L2 is numpy array with shape (N,2)
import scipy.spatial
tree=scipy.spatial.KDTree(L2)
assoc=[]
for I1,point in enumerate(L1):
_,I2 = tree.query(point,k=1)
assoc.append((I1,I2))
assoc
变量包含作为索引元组列表的最终关联
编辑:为了帮助解决非唯一关联问题,第一步可能是运行 KDtree 算法两次,一次使用“主列表”L1,一次使用“主列表”L2,然后只保留两者之间的共同关联。然后您可以将剩余点作为特殊情况处理。
【讨论】:
如果 list1 中的两个点在 list2 中得到相同的结果会怎样? 这个答案真的很巧妙。我不知道 KDTrees。但是,正如@Stef 指出的那样,它不能保证排他性。它也不能保证它是最接近的匹配。当我们遍历 L1 中的点以找到 L2 中的最近点时,它将给出这个 L1 点与其最近的 L2 点之间的关联,但不能保证没有另一个 L1 点更接近这个 L2 点,这会使这个无效协会。 它可能最终会变慢,但是您可以记录之前匹配的每个点,然后在最近的点已经被占用时查询更多的点。要查询多个邻居,您可以在query
函数调用中更改k
的值。这将返回k
最近邻居的列表。您需要遍历这些结果以排除已经“采取”的邻居。这解决了@Stef 提到的情况,但基于遍历 L1 的顺序存在偏差。如果你想最小化基于顺序的偏差,你可以随机化你对 L1 的遍历。
如果您发布您的原始 python 实现,可能会找到在不更改算法的情况下加快代码速度的方法。已知某些 python 和 NumPy 方法比其他方法慢
@MichaelSohnen:我建议你用你最后的评论更新你的答案,只是验证它。谢谢你的手!以上是关于Python - 根据距离关联两个点列表的主要内容,如果未能解决你的问题,请参考以下文章