2013-11-26 23 views
10

は、以下のようにIは、2つの2次元アレイを有していると仮定して下さい:2つの2次元アレイに一致する行のインデックス

array([[3, 3, 1, 0], 
     [2, 3, 1, 3], 
     [0, 2, 3, 1], 
     [1, 0, 2, 3], 
     [3, 1, 0, 2]], dtype=int8) 

array([[0, 3, 3, 1], 
     [0, 2, 3, 1], 
     [1, 0, 2, 3], 
     [3, 1, 0, 2], 
     [3, 3, 1, 0]], dtype=int8) 

各アレイ内の一部の行は、値により一致する対応する行を持って(必ずしもそうではありませんインデックスによって)、他の配列にはありません。

私は、一致する行に対応する2つの配列のインデックスのペアを返す効率的な方法を見つけたいと思います。彼らはタプルなるとしたら、私はそれを行うにはnumpyの具体的な方法を考えることはできません

(0,4) 
(2,1) 
(3,2) 
(4,3) 

答えて

6

これをすべてnumpy解決策です - それは必ずしも反復的なPythonより優れているわけではありません。すべての組み合わせを見なければなりません。

In [53]: np.array(np.all((x[:,None,:]==y[None,:,:]),axis=-1).nonzero()).T.tolist() 
Out[53]: [[0, 4], [2, 1], [3, 2], [4, 3]] 

中間配列は(5,5,4)です。残りはちょうど47.8たちで、この回、これは、粗テストでTrue

ある指標を抽出している

array([[False, False, False, False, True], 
     [False, False, False, False, False], 
     [False, True, False, False, False], 
     [False, False, True, False, False], 
     [False, False, False, True, False]], dtype=bool) 

;:np.allはそれを減少させ他の答えはL1辞書38.3 usで、 496 usでダブルループを持つ3番手。

5

を返すことを期待するが、ここで私は定期的にリストを行うだろう何だろう:

>>> L1= [[3, 3, 1, 0], 
...  [2, 3, 1, 3], 
...  [0, 2, 3, 1], 
...  [1, 0, 2, 3], 
...  [3, 1, 0, 2]] 
>>> L2 = [[0, 3, 3, 1], 
...  [0, 2, 3, 1], 
...  [1, 0, 2, 3], 
...  [3, 1, 0, 2], 
...  [3, 3, 1, 0]] 
>>> L1 = {tuple(row):i for i,row in enumerate(L1)} 
>>> answer = [] 
>>> for i,row in enumerate(L2): 
... if tuple(row) in L1: 
...  answer.append((L1[tuple(row)], i)) 
... 
>>> answer 
[(2, 1), (3, 2), (4, 3), (0, 4)] 
+0

O(n)!ニース。しかし、それを行うにはnumpyの方法はありませんか? – slider

+0

@slider:私はnumpyをそれほど使わないので、主にnumpyの方法を考えることはできません。(これは私のtodoリストには私が認めてくれることを誇りに思っています) – inspectorG4dget

+0

'L2'が一行しかない場合に一般化され、' L1'の行が一意であるとは限らないので、 'L1'で一致する行の '行インデックス'を取得したいのですか? – sodiumnitrate

4

voidデータ型トリックを使用すると、2つの配列の行に1D関数を使用できます。 a_viewおよびb_viewは1Dベクトルであり、各エントリは完全な行を表します。私は次に、配列をソートし、np.searchsortedを使って、その配列内の他の配列の項目を探しました。並べ替える配列の長さがmで、もう1つの長さがnの場合、ソートにはの時間がかかり、np.searchsortedのバイナリ検索にはn * log(m)という合計で(n + m) * log(m)が必要です。あなたのテストのための辞書のアプローチクロック速く約22私たちに私のシステムでは

In [14]: find_rows(a, b) 
Out[14]: 
array([[0, 4], 
     [2, 1], 
     [3, 2], 
     [4, 3]], dtype=int64) 

In [15]: %timeit find_rows(a, b) 
10000 loops, best of 3: 29.7 us per loop 

abあなたの2つのサンプルアレイと

def find_rows(a, b): 
    dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1])) 

    a_view = np.ascontiguousarray(a).view(dt).ravel() 
    b_view = np.ascontiguousarray(b).view(dt).ravel() 

    sort_b = np.argsort(b_view) 
    where_in_b = np.searchsorted(b_view, a_view, 
           sorter=sort_b) 
    where_in_b = np.take(sort_b, where_in_b) 
    which_in_a = np.take(b_view, where_in_b) == a_view 
    where_in_b = where_in_b[which_in_a] 
    which_in_a = np.nonzero(which_in_a)[0] 
    return np.column_stack((which_in_a, where_in_b)) 

:あなたはそのため2つの配列の最短をソートしたいですデータであるが、1000x4の配列では、このnumpyのアプローチは純粋なPythonのものより約6倍高速です(483 us vs 2.54 ms)。

+0

これは素晴らしいです。あなたがやっていることが何であるかを理解するのに一時間かかりました。 searchsortedは、索引の範囲外のエラーを引き起こす項目を最後に挿入する必要があることを戻す可能性があるため、わずかなバグがあります。 – Dalupus

+0

の例では、配列の最後の行を[3,3,3,3]に変更するだけで、 'IndexError:インデックス5はサイズ5の範囲外です' – Dalupus

関連する問題