この例の解決策を考えてみましょう。
In [1]: import numpy as np
In [5]: X = np.array([1879, 1731])
In [6]: Y = np.array([1481, 1691, 1586, 1796])
X
内の値と内の値の間のすべての距離を次の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)))
Timeit の結果:
% 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
Soalt_find_close
は よりも大幅に高速ですfind_close
。