NumPy配列から特定の行と列を選択する


96

私はここで私が間違っているどんな愚かなことを理解しようとして夢中になっています。

NumPyを使用していますが、特定の行インデックスと特定の列インデックスから選択したいと考えています。これが私の問題の要点です:

import numpy as np

a = np.arange(20).reshape((5,4))
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11],
#        [12, 13, 14, 15],
#        [16, 17, 18, 19]])

# If I select certain rows, it works
print a[[0, 1, 3], :]
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [12, 13, 14, 15]])

# If I select certain rows and a single column, it works
print a[[0, 1, 3], 2]
# array([ 2,  6, 14])

# But if I select certain rows AND certain columns, it fails
print a[[0,1,3], [0,2]]
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# ValueError: shape mismatch: objects cannot be broadcast to a single shape

なんでこんなことが起こっているの?確かに、1行目、2行目、4行目、1列目と3列目を選択できるはずですか?私が期待している結果は次のとおりです。

a[[0,1,3], [0,2]] => [[0,  2],
                      [4,  6],
                      [12, 14]]

ファインダビリティを向上させるためのタグ付きnumpy-slicing。(また、「スライス」および「スライス」という用語は平文では発生しません。これらの用語を閉じた状態でいくつかの重複を使用できます)
smci 2018年

回答:


86

ファンシーインデックス作成では、各ディメンションのすべてのインデックスを提供する必要があります。最初のインデックスに3つのインデックスを提供し、2番目のインデックスに2つしか提供していないため、エラーが発生します。あなたはこのようなことをしたい:

>>> a[[[0, 0], [1, 1], [3, 3]], [[0,2], [0,2], [0, 2]]]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

それはもちろん書くのが面倒なので、放送があなたを助けることができます:

>>> a[[[0], [1], [3]], [0, 2]]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

リストではなく配列を使用してインデックスを作成する場合、これははるかに簡単です。

>>> row_idx = np.array([0, 1, 3])
>>> col_idx = np.array([0, 2])
>>> a[row_idx[:, None], col_idx]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

4
おかげで、私はあなたがこれを行うことができるとは知りませんでした!放送は奇妙で素晴らしいです... 2年間の厄介な後、私はまだそれに慣れています。
Praveen 2014

2
ありがとう!他の回答は、選択した行列を返すという点で私の質問に正しく答えましたが、この回答は、割り当ての問題([[0,1,3]、[0,2]] = 0の設定方法)にも対処しながら、それに対処しました。 、 例えば)。
マイクC

1
@ Jaime-ちょうど昨日、あなたが提案する放送トリックを正確に実行するためのワンライナーが組み込まれていることを発見しました:np.ix_
Praveen

1
構文がこのように機能する理由について誰かが説明できますか?最初の例では機能するが、3番目の例では機能しない理由は何ですか。また、必要なインデックスを独自のリストにカプセル化すると、これをどのように解決できますか?ありがとう
エートス・

2
行をネストする必要があり、列をネストしないのはなぜですか?
AturSams

86

Toanが示唆しているように、単純なハックは、最初に行を選択してから、その上の列を選択することです。

>>> a[[0,1,3], :]            # Returns the rows you want
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [12, 13, 14, 15]])
>>> a[[0,1,3], :][:, [0,2]]  # Selects the columns you want as well
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

[編集]組み込みメソッド: np.ix_

私は最近、numpyが@Jaimeが提案したことを正確に実行するための組み込みのワンライナーを提供することを発見しましたが、ブロードキャスト構文を使用する必要はありません(読みやすさの欠如に悩まされています)。ドキュメントから:

ix_を使用すると、外積にインデックスを付けるインデックス配列をすばやく作成できます。a[np.ix_([1,3],[2,5])]配列を返します[[a[1,2] a[1,5]], [a[3,2] a[3,5]]]

したがって、次のように使用します。

>>> a = np.arange(20).reshape((5,4))
>>> a[np.ix_([0,1,3], [0,2])]
array([[ 0,  2],
       [ 4,  6],
       [12, 14]])

そして、それが機能する方法は、ブロードキャストが適切に行われるように、Jaimeが提案したように配列の整列を処理することです。

>>> np.ix_([0,1,3], [0,2])
(array([[0],
        [1],
        [3]]), array([[0, 2]]))

また、MikeCがコメントで述べているように、np.ix_私の最初の(編集前の)回答では得られなかったビューを返すという利点があります。これは、インデックス付き配列に割り当てることができることを意味します。

>>> a[np.ix_([0,1,3], [0,2])] = -1
>>> a    
array([[-1,  1, -1,  3],
       [-1,  5, -1,  7],
       [ 8,  9, 10, 11],
       [-1, 13, -1, 15],
       [16, 17, 18, 19]])

4
いくつかのテストでは、np.ix_最初の列を選択してから行を選択する方法よりも高速であることがわかりました(通常、すべての行と列のインデックスを再作成するサイズ1K〜10Kの正方形配列のテストでは約2倍高速です)。
ネイサン

7

使用する:

 >>> a[[0,1,3]][:,[0,2]]
array([[ 0,  2],
   [ 4,  6],
   [12, 14]])

または:

>>> a[[0,1,3],::2]
array([[ 0,  2],
   [ 4,  6],
   [12, 14]])

10
これは正しいですがそれが正しい理由を説明するもう少し情報を投稿することを検討する必要があります。
ebarr 2014

2

使用するのnp.ix_が最も便利な方法です(他の人が答えたように)が、これは別の興味深い方法です:

>>> rows = [0, 1, 3]
>>> cols = [0, 2]

>>> a[rows].T[cols].T

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