webdevqa.jp.net

NumPy多次元配列のi番目の列にアクセスするにはどうすればいいですか?

私が持っているとします。

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

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

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

同様に

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

行にアクセスできます。これは NumPyリファレンス の1.4節(索引付け)でカバーされています。少なくとも私の経験上、これは迅速です。ループ内の各要素にアクセスするよりも、はるかに高速です。

554
mtrw

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

>>> 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]])
58
Akavall
>>> test[:,0]
array([1, 3, 5])

このコマンドを実行すると、行ベクトルが得られます。これをループしたい場合は問題ありませんが、3×Nの他の配列とスタックしたい場合は、

ValueError:すべての入力配列は同じ次元数でなければなりません

しながら

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

列ベクトルを与えるので、連結演算やhstack演算を実行できます。

例えば.

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

行を入れ替えて返すこともできます。

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

質問は答えられましたが、いくつかの微妙な違いについてお話しましょう。

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

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 を参照してください。

両者の明らかな違い(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

列コピーを使用する方が良いように思われるかもしれませんが、コピーを作成するのに時間がかかり、より多くのメモリを使用するため、必ずしもそうとは限りません(この場合、A_c1_copyの作成に約200μsかかりました)。しかし、そもそもコピーが必要な場合、または配列の特定の列に対してさまざまな操作を実行する必要がある場合、速度を上げるためにメモリを犠牲にしても問題ない場合は、コピーを作成することをお勧めします。

私たちが主に列を扱うことに興味がある場合は、配列を行優先( '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
AndyK

複数の独立した列を取得するには、次のようにします。

> test[:,[0,2]]

あなたは列0と2を取得します

3
Alberto Perez
>>> 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]])
2
mac