NumPy多次元配列のi番目の列にアクセスする方法は?


463

私が持っていると仮定します:

test = numpy.array([[1, 2], [3, 4], [5, 6]])

test[i]配列のi番目の行を取得します(例:)[1, 2]i番目の列にアクセスするにはどうすればよいですか?(例[1, 3, 5])。また、これは高価な操作でしょうか?

回答:


687
>>> test[:,0]
array([1, 3, 5])

同様に、

>>> test[1,:]
array([3, 4])

行にアクセスできます。これについては、NumPyリファレンスのセクション1.4(インデックス)で説明しています。これは、少なくとも私の経験では速いです。ループ内の各要素にアクセスするよりもはるかに高速です。


11
これはコピーを作成します。列への参照を取得するように、参照を取得することは可能です。この参照の変更はすべて元の配列に反映されます。
2016年

@harmandsこれはコピーを作成せず、ビューを作成します。
11:27のrinspy

69

また、一度に複数の列にアクセスする場合は、次のようにします。

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

もちろん、この場合、データにアクセスするだけではありません。コピー(ファンシーインデックス)を返します
John Greenall 2014

14
test[:,[0,2]]データにアクセスするだけです。たとえば、test[:, [0,2]] = somethingテストを変更し、別の配列を作成しません。しかしcopy_test = test[:, [0,2]]、実際にはあなたが言うようにコピーを作成します。
Akavall 14

3
これはコピーを作成します。いくつかの列への参照を取得するように、参照を取得することは可能ですか?この参照の変更は元の配列に反映されますか?
2016年

@ harman786変更した配列を古い配列に再割り当てできます。
Tamoghna Chowdhury

なぜtest[:,[0,2]]データにアクセスするのにアクセスtest[:, [0, 2]][:, [0, 1]]しないのですか?同じことをもう一度行うと結果が異なることは非常に直感的ではないようです。
mapf

65
>>> test[:,0]
array([1, 3, 5])

このコマンドは、行ベクトルを提供します。ループするだけの場合は問題ありませんが、3xNの次元を持つ他の配列とhstackする場合は、

ValueError: all the input arrays must have same number of dimensions

ながら

>>> test[:,[0]]
array([[1],
       [3],
       [5]])

列ベクトルを提供するため、連結またはhstack操作を実行できます。

例えば

>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
       [3, 4, 3],
       [5, 6, 5]])

1
インデックス作成は一度に1列以上でも機能するため、最後の例はtest [:、[0,1,0]]またはtest [:、[range(test.shape [1])+ [0]]になります。 ]
lib

5
[:、[0]]対[:、0]を指定して、行ベクトルではなく列ベクトルを取得するための+1。まさに私が探していた行動。また、追加の索引付けメモ用にlibに+1。この答えは、トップの答えのすぐ上にあります。
dhj 2015年

1
この答えは、選びましなければなりません
グセフスラバ

22

行を転置して返すこともできます。

In [4]: test.T[0]
Out[4]: array([1, 3, 5])

私は遅く、これが高速である場合、私は疑問に思う、アクセス列への最速の方法を探して前にしばらくの間、これを行うこと、またはテストとしてちょうど同じしてきた[:[0]]
ホセ・チャモロ


5

質問への回答はありますが、いくつかのニュアンスについて触れさせてください。

配列の最初の列に興味があるとしましょう

arr = numpy.array([[1, 2],
                   [3, 4],
                   [5, 6]])

他の回答からすでに知っているように、「行ベクトル」(形状の配列(3,))の形式で取得するには、スライスを使用します。

arr_c1_ref = arr[:, 1]  # creates a reference to the 1st column of the arr
arr_c1_copy = arr[:, 1].copy()  # creates a copy of the 1st column of the arr

配列がビューであるか別の配列のコピーであるかを確認するには、次のようにします。

arr_c1_ref.base is arr  # True
arr_c1_copy.base is arr  # False

ndarray.baseを参照してください

2つの間の明らかな違い(変更arr_c1_refはに影響しますarr)に加えて、それぞれを走査するためのバイトステップ数は異なります。

arr_c1_ref.strides[0]  # 8 bytes
arr_c1_copy.strides[0]  # 4 bytes

ストライドを参照してください。何でこれが大切ですか?あなたがのA代わりに非常に大きな配列を持っていると想像してくださいarr

A = np.random.randint(2, size=(10000,10000), dtype='int32')
A_c1_ref = A[:, 1] 
A_c1_copy = A[:, 1].copy()

そして、あなたは最初の列のすべての要素の合計を計算したい、すなわち、A_c1_ref.sum()またはA_c1_copy.sum()。コピーしたバージョンを使用すると、はるかに高速になります。

%timeit A_c1_ref.sum()  # ~248 µs
%timeit A_c1_copy.sum()  # ~12.8 µs

これは、前述のストライドの数が異なるためです。

A_c1_ref.strides[0]  # 40000 bytes
A_c1_copy.strides[0]  # 4 bytes

カラムコピーを使用する方が良いように見えるかもしれませんが、コピーの作成には時間がかかり、より多くのメモリを使用するという理由から、常にそうであるとは限りません(この場合、作成に約200 µsかかりました A_c1_copy)。ただし、最初にコピーが必要な場合、または配列の特定の列に対して多くの異なる操作を実行する必要があり、速度を上げるためにメモリを犠牲にしても問題ない場合は、コピーを作成する方法です。

主に列を操作することに関心がある場合は、行優先( 'C')順(デフォルト)ではなく、列優先( 'F')順に配列を作成することをお勧めします。 )、前と同じようにスライスして、コピーせずに列を取得します。

A = np.asfortranarray(A)  # or np.array(A, order='F')
A_c1_ref = A[:, 1]
A_c1_ref.strides[0]  # 4 bytes
%timeit A_c1_ref.sum()  # ~12.6 µs vs ~248 µs

これで、列ビューで合計操作(またはその他の操作)を実行する方がはるかに高速になりました。

最後に、配列を転置して行スライスを使用することは、元の配列で列スライスを使用することと同じです。転置は、元の配列の形状とストライドを交換するだけで行われるためです。

A.T[1,:].strides[0]  # 40000

3
>>> test
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> ncol = test.shape[1]
>>> ncol
5L

次に、この方法で2番目から4番目の列を選択できます。

>>> test[0:, 1:(ncol - 1)]
array([[1, 2, 3],
       [6, 7, 8]])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.