NumPy配列のファンシーインデックス参照と代入

[] の中にインデックス1つ書く代わりにインデックスの配列を書くと、その配列に対応して要素をピックアップしたndarrayを新しく作ってくれる。

ndarr1 = np.array([0, 10, 20, 30, 40, 50])

print(ndarr1[[2, 4]])
# 出力結果
# [20 40]

インデックスの順番を守る必要はない。

print(ndarr1[[3, 2, 4]])
# 出力結果
# [30 20 40]

要素が重複しても大丈夫みたい。

print(ndarr1[[3, 2, 2, 4]])
# 出力結果
# [30 20 20 40]

ファンシーインデックスで得た配列はもとの配列から必要な要素をコピーして作成される新しい配列であって、従って新しい配列を書き換えても、もとの配列には影響しない。

sl = ndarr1[[1, 3, 4]]
print(sl)
# 出力結果
# [10 30 40]

sl[0] = 100
print(sl)
# 出力結果
# [100  30  40]

print(ndarr1)
# 出力結果
# [ 0 10 20 30 40 50]

参照だけでなく、代入もできる。ファンシーインデックスでの代入は複数の要素をまとめて書き換えることができる。

# 同じ大きさの配列を代入すれば、それがそのままその位置に代入される
ndarr1[[1, 2]] = [100, 200]

print(ndarr1)
# 出力結果
# [  0 100 200  30  40  50]

ファンシーインデックスに配列ではなく数値を代入すると、ファンシーインデックスで参照されている要素すべてに同一の値が代入される。

ndarr1[[1,2]] = 1000

print(ndarr1)
# 出力結果
# [   0 1000 1000   30   40   50]

多次元配列の場合でも同じ書き方をすれば、最も外側の軸のインデックスを指定することになる。

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

print(ndarr1)
# 出力結果
# [[ 1.  2.  3.]
#  [ 4.  5.  6.]
#  [ 7.  8.  9.]]

print(ndarr1[[0, 1]])
# 出力結果
# [[ 1.  2.  3.]
#  [ 4.  5.  6.]]

コロンを使って [:, [0, 1]] のように書くと、内側の軸のインデックスだけを指定することもできる。これは後述のスライス表記との組み合わせである。

print(ndarr1[:, [0, 1]])
# 出力結果
# [[ 1.  2.]
#  [ 4.  5.]
#  [ 7.  8.]]

[] の中にコンマ区切りで配列を書くと、その組み合わせになる。

print(ndarr1[[0, 1], [0, 1]])
# 出力結果
# [ 1.  5.]

これは ndarr1[0, 0]ndarr1[1, 1] を要素とする配列になる。[] の中に書いた配列を組み合わせるので、 ndarr1[[0, 1], [0, 1, 2]] のように書くとエラーが発生してしまう。

でもこの結果はかなり違和感を感じる。そうでなくて、自分は[[1, 2], [4, 5]] を期待してしまったのだが、そうしたい場合には、以下のようにする。

print(ndarr1[[0, 1]][:, [0, 1]])
# 出力結果
# [[ 1.  2.]
#  [ 4.  5.]]

関連

このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。