NumPyは、インデックスのリストを使用して、行ごとに特定の列インデックスを選択します


93

NumPyマトリックスの行ごとに特定の列を選択するのに苦労しています。

私が呼ぶ次の行列があるとしましょうX

[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

私はまた、list私が呼ぶすべての行ごとに列インデックスのを持っていますY

[1, 0, 2]

値を取得する必要があります:

[2]
[4]
[9]

listインデックス付きのaの代わりに、すべての列が0〜1の範囲の/であるYのと同じ形状の行列を作成して、これが必須の列であるかどうかを示すこともできます。Xboolint

[0, 1, 0]
[1, 0, 0]
[0, 0, 1]

これは、配列を反復処理し、必要な列値を選択することで実行できることを知っています。ただし、これはデータの大きな配列で頻繁に実行されるため、できるだけ高速に実行する必要があります。

したがって、私はより良い解決策があるかどうか疑問に思いましたか?


答えはあなたにとってより良いですか?stackoverflow.com/a/17081678/5046896
GoingMyWay

回答:


104

ブール配列がある場合は、次のようにそれに基づいて直接選択を行うことができます。

>>> a = np.array([True, True, True, False, False])
>>> b = np.array([1,2,3,4,5])
>>> b[a]
array([1, 2, 3])

最初の例に沿って進むには、次のようにします。

>>> a = np.array([[1,2,3], [4,5,6], [7,8,9]])
>>> b = np.array([[False,True,False],[True,False,False],[False,False,True]])
>>> a[b]
array([2, 4, 9])

arangeブール配列を生成する方法やコードがYMMVのように見えるかどうかにもよりますが、を追加して直接選択することもできます。

>>> a = np.array([[1,2,3], [4,5,6], [7,8,9]])
>>> a[np.arange(len(a)), [1,0,2]]
array([2, 4, 9])

お役に立てば幸いです。他にご不明な点がありましたらお知らせください。


13
を使用した例では+1 arange。これは、複数のマトリックスから異なるブロックを取得する場合に特に役立ちました(したがって、基本的にこの例の3Dの場合)
Griddo 2016年

1
こんにちは、arange代わりに使用する必要がある理由を説明できます:か?私はあなたのやり方がうまくいくことを知っていますが、私のやり方はうまくいきませんが、その理由を理解したいと思います。
marcotama 2016年

@tamzordは、バニラpythonリストではなく、numpy配列であるため、:構文は同じようには機能しません。
Slater Victoroff 2016年

1
@SlaterTyranus、返信ありがとうございます。私の理解では、ある程度読んだ後:、高度なインデックス付けと混合すると、「に沿ったすべてのサブスペース:に対して、指定された高度なインデックス付けを適用する」という意味になります。私の理解は正しいですか?
marcotama 2016年

@tamzordは、「サブスペース」の意味を説明します
Slater Victoroff 2016年

36

あなたはこのようなことをすることができます:

In [7]: a = np.array([[1, 2, 3],
   ...: [4, 5, 6],
   ...: [7, 8, 9]])

In [8]: lst = [1, 0, 2]

In [9]: a[np.arange(len(a)), lst]
Out[9]: array([2, 4, 9])

多次元配列のインデックス作成の詳細:http//docs.scipy.org/doc/numpy/user/basics.indexing.html#indexing-multi-dimensional-arrays


2
単に「:」または範囲ではなく、範囲が必要な理由を理解するのに苦労しています。
MadmanLee

@MadmanLeeこんにちは、を使用:するlen(a)と、結果が複数回出力されます。代わりに、各行のインデックスが予想される結果を出力することを示します。
GoingMyWay

1
これが、この問題を解決するための正確でエレガントな方法だと思います。
GoingMyWay

6

簡単な方法は次のようになります。

In [1]: a = np.array([[1, 2, 3],
   ...: [4, 5, 6],
   ...: [7, 8, 9]])

In [2]: y = [1, 0, 2]  #list of indices we want to select from matrix 'a'

range(a.shape[0]) 戻ります array([0, 1, 2])

In [3]: a[range(a.shape[0]), y] #we're selecting y indices from every row
Out[3]: array([2, 4, 9])

1
説明を追加することを検討してください。
souki 2018年

@souki説明を追加しました。ありがとう
DhavalMayatra18年

6

最近のnumpyバージョンでは、このインデックス作成をクリーンに行うtake_along_axis(およびput_along_axis)が追加されています。

In [101]: a = np.arange(1,10).reshape(3,3)                                                             
In [102]: b = np.array([1,0,2])                                                                        
In [103]: np.take_along_axis(a, b[:,None], axis=1)                                                     
Out[103]: 
array([[2],
       [4],
       [9]])

次のように動作します。

In [104]: a[np.arange(3), b]                                                                           
Out[104]: array([2, 4, 9])

ただし、軸の処理は異なります。これは、特に結果を適用を目指していますargsortargmax


3

イテレータを使用してそれを行うことができます。このような:

np.fromiter((row[index] for row, index in zip(X, Y)), dtype=int)

時間:

N = 1000
X = np.zeros(shape=(N, N))
Y = np.arange(N)

#@Aशwini चhaudhary
%timeit X[np.arange(len(X)), Y]
10000 loops, best of 3: 30.7 us per loop

#mine
%timeit np.fromiter((row[index] for row, index in zip(X, Y)), dtype=int)
1000 loops, best of 3: 1.15 ms per loop

#mine
%timeit np.diag(X.T[Y])
10 loops, best of 3: 20.8 ms per loop

1
OPは、大規模なアレイで高速に実行する必要があると述べたため、ベンチマークはあまり代表的ではありません。あなたの最後のメソッドが(はるかに)大きな配列に対してどのように機能するのか興味があります!

@moarningsun:更新されました。np.diag(X.T[Y])とても遅いです...しかしnp.diag(X.T)とても速いです(10us)。理由はわかりません。
南川圭2014

0

もう1つの賢い方法は、最初に配列を転置し、その後インデックスを付けることです。最後に、対角線を取ります。常に正しい答えです。

X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
Y = np.array([1, 0, 2, 2])

np.diag(X.T[Y])

ステップバイステップ:

元の配列:

>>> X
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

>>> Y
array([1, 0, 2, 2])

正しくインデックスを付けることができるように転置します。

>>> X.T
array([[ 1,  4,  7, 10],
       [ 2,  5,  8, 11],
       [ 3,  6,  9, 12]])

Y順に行を取得します。

>>> X.T[Y]
array([[ 2,  5,  8, 11],
       [ 1,  4,  7, 10],
       [ 3,  6,  9, 12],
       [ 3,  6,  9, 12]])

これで対角線が明確になります。

>>> np.diag(X.T[Y])
array([ 2,  4,  9, 12]

1
これは技術的に機能し、非常にエレガントに見えます。ただし、大きな配列を扱う場合、このアプローチは完全に爆発することがわかりました。私の場合、NumPyは30GBのスワップを飲み込み、SSDをいっぱいにしました。代わりに、高度なインデックス作成アプローチを使用することをお勧めします。
5nefarious 2010年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.