让我们试着找出这个例子的解决方案:
In [1]: import numpy as np
In [5]: X = np.array([1879, 1731])
In [6]: Y = np.array([1481, 1691, 1586, 1796])
X
我们可以像这样计算值 in和值 in之间的所有距离Y
:
In [7]: dist = np.abs(np.subtract.outer(X,Y))
In [8]: dist
Out[8]:
array([[398, 188, 293, 83],
[250, 40, 145, 65]])
行对应于X
值,列对应于Y
值。
为了找到X
最接近 中某个元素的值Y
,我们正在寻找对应于矩阵列中的X
最小值的值
。每列对应一个特定的,因此一列中的最小距离对应于一些和特定之间的最小值。dist
Y
X
Y
从视觉上讲,我们正在寻找的是它们所在行和dist
所在列的最小值。我们称它们为“行列最小值”。
在上面的dist
数组中,40 是行列最小值。65 是列最小值,但不是行列最小值。
对于每一列,我们可以通过这种方式找到最小化该列的 X-index:
In [6]: idx1 = np.argmin(dist, axis = 0)
In [7]: idx1
Out[7]: array([1, 1, 1, 1])
同样,对于每一行,我们可以通过以下方式找到 Y 索引:
In [8]: idx2 = np.argmin(dist, axis = 1)
In [9]: idx2
Out[9]: array([3, 1])
现在,让我们暂时忘记这个例子,假设idx1
看起来像这样:
0,1,2,3,4,5 # the index value
idx1 = (_,_,_,_,_,2,...)
这就是说在第 5 列中,第 2 行具有最小值。
然后,如果第 2 行、第 5 列对应于行列最小值,则idx2
必须如下所示:
0,1,2 # index value
idx2 = (_,_,5,...)
我们可以用 NumPy 来表达这种关系
idx1[idx2] == np.arange(len(X))
idx2[idx1] == np.arange(len(Y))
因此,对应于行列最小值的 X、Y 值是
X[idx1[idx2] == np.arange(len(X))]
和
Y[idx2[idx1] == np.arange(len(Y))]
import numpy as np
tests = [
(np.array([1879, 1731]),
np.array([1481, 1691, 1586, 1806])),
(np.array([1879, 1731]),
np.array([1481, 1691, 1586, 1796])),
(np.array([ 157, 262, 368, 472, 577, 682, 786, 891, 996, 1100, 1204]),
np.array([ 30, 135, 240, 345, 450, 555, 660, 765, 870, 975])),
(np.array([ 157, 262, 368, 472, 577, 682, 786, 891, 996, 1100, 1204, 1310,
1415, 1520, 1625, 1731, 1879]),
np.array([ 221, 326, 431, 536, 641, 746, 851, 956, 1061, 1166, 1271, 1376,
1481, 1586, 1691, 1796]))]
def find_close(X,Y):
new_list = list()
for i in X:
delta_i = np.abs(Y - i)
# print(delta_i)
delta_reciprocal = np.abs(X - Y[delta_i.argmin()])
if delta_i.min() == delta_reciprocal.min():
new_list += sorted([Y[delta_i.argmin()],
X[delta_reciprocal.argmin()]])
Z = np.array(new_list)
return Z
def alt_find_close(X,Y):
dist = np.abs(np.subtract.outer(X,Y))
idx1 = np.argmin(dist, axis = 0)
idx2 = np.argmin(dist, axis = 1)
Z = np.r_[X[idx1[idx2] == np.arange(len(X))], Y[idx2[idx1] == np.arange(len(Y))]]
return Z
for X, Y in tests:
assert np.allclose(sorted(find_close(X,Y)), sorted(alt_find_close(X,Y)))
时间结果:
% python -mtimeit -s'import test' 'test.find_close(test.X, test.Y)'
1000 loops, best of 3: 454 usec per loop
% python -mtimeit -s'import test' 'test.alt_find_close(test.X, test.Y)'
10000 loops, best of 3: 40.6 usec per loop
所以alt_find_close
明显快于find_close
.