交叉匹配两个2D数组并返回匹配的索引

时间:2020-08-06 15:19:45

标签: python arrays numpy distance

我有两个分别为AB且形状为(m, 2)的数组(n, 2)n >> m。就我而言,n = 8013m = 71。每个阵列的每一行(x, y)代表天文图像中点源的坐标,以像素为单位。 A中的所有行的值与B中的某些行的值非常接近,但并不完全相同。在某些情况下,差异是一些小数,在其他情况下,可能是一或两个整数,例如A中的一行是(1158, 1304.8974),B中相应的行是(1160, 1304.6578)

我的问题是:如何找到B中元素最接近A中元素的索引?

我的第一次尝试是:

matched = []
indexes = []
for k in np.arange(0, len(A)):
    idx = np.where((B[:, 0].astype(int) == A[k, 0].astype(int)) & 
                   (B[:, 1].astype(int) == A[k, 1].astype(int)))
    matched.append(B[idx])
    indexes.append(idx)

但是它仅返回A中行的索引,其整数与B中的元素完全相同,因此并不匹配所有项目。如果删除astype(int),则匹配项更少。

我尝试过的第二次尝试是:

value = A[0]
X = np.abs(B - value)
idx = np.where(X == X.min())
B[idx[0]]

但是它只计算xy列中的最接近值,而不是两者都计算。这意味着如果我要匹配的A中有一行,例如(1230, 980),而B中有两行,例如(3450, 981)和{{1} },后者是正确的匹配项和预期的输出,第二个实现返回元素(1233, 975)作为与(3450, 981)的正确匹配项,因为点(1230, 980)更接近y = 980而不是y = 981

2 个答案:

答案 0 :(得分:0)

您可以将idx定义的大小写更改为可接受的范围,如下所示:

idx = np.where((B[:, 0].astype(int) >= A[k, 0].astype(int) - 3) & (B[:, 0].astype(int) <= a(k,0].astype(int + 3)) & (B[:, 1].astype(int) == A[k, 1].astype(int)))

答案 1 :(得分:0)

您正在寻找最常规的距离:欧几里得。

由于您的数字大约是1万乘100,因此在任何合理的现代硬件上,计算时间之间的距离或内存都不会特别昂贵。如果价格昂贵,我会推荐scipy.spatial.KDTree之类的东西,它可以有效地实现适当的空间排序。

获取每组点之间距离的最简单方法是使用scipy.spatial.distance.cdist。这并不总是和“手动”计算距离一样快,但是足够快:

dist = cdist(A, B)

dist是一个(m, n)数组。您可以使用np.argmin在每一行中找到最小距离的索引:

idx = np.argmin(dist, axis=1)

B的对应元素是

matches = B[idx, :]

这假设您的输入数组AB是开始的numpy数组。如果不是这种情况,请先将它们分成数组:

A = np.array(A)
B = np.array(B)

如果要“手动”实现距离,这会更快,则可以使用broadcasting来计算平方差之和的平方根:

dist = np.sqrt(sum((A.reshape(-1, 1, 2) - B.reshape(1, -1, 2))**2, axis=-1))

如果只想找到最小值,则不需要最终的平方根,因为平方根单调增加,并且平方距离的最小值出现在最小距离上。