Python,NumPyの基礎⑤ ~ndarrayにおけるファンシーインデックス参照~

記事内に広告が含まれています。

どうも!僕です!
つか〇です!

「ファンシーインデックスってなんや?」
「ndarrayで狙った配列を取り出したいんやけど,どうすんの?」

といった疑問に答えていきたいと思います.

結論をいうと,ファンシーインデックス参照は,整数配列をインデックス参照に用いることで,元の配列から配列を抽出することです.

大丈夫です!これからわかりやすく説明します.

基本操作

まず,実際に配列を作成して,いじってみましょう!
今回は,以下のような配列でやってみます.

import numpy as np
arr = np.arange(50).reshape(10, 5)

print(arr)

以下の通り,0 ~ 49 までの要素が格納された配列ができます.

[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]
 [15 16 17 18 19]
 [20 21 22 23 24]
 [25 26 27 28 29]
 [30 31 32 33 34]
 [35 36 37 38 39]
 [40 41 42 43 44]
 [45 46 47 48 49]]

この配列に対して,リストあるいは,ndarray配列を使ってインデックス参照してみましょう.
ここでやることとしては,上記の配列から「7行目→3行目→0行目→9行目」の順番でインデックス参照してみます.

arr[[7, 3, 0, 9]]

このように,配列を使ってインデックス参照をしています.
抽出したい行を順番に指示するだけで,狙った通りに抽出することができます.

array([[35, 36, 37, 38, 39],
       [15, 16, 17, 18, 19],
       [ 0,  1,  2,  3,  4],
       [45, 46, 47, 48, 49]])

ちゃんと参照した順番,値になっていることがわかりますね.
基本的にndarrayでの配列を使ったインデックス参照,ファンシーインデックス参照はこのようにして参照していけばいいことがわかりましたね.

負の値のインデックス参照

リストを勉強したことがある人ならわかると思いますが,リストでは負の値でインデックス参照,スライシングができます.
少し脱線しますが,リストだと以下の通りです.

l = range(10)
list_1 = list(l)
print(list_1)
print("list_1[-3] = ", list_1[-3])
print("list_1[-9] = ", list_1[-9])
print("list_1[-7:-3] = ", list_1[-7:-3])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list_1[-3] =  7
list_1[-9] =  1
list_1[-7:-3] =  [3, 4, 5, 6]

負の値のインデックス参照は下図のように割り当てられます.

少しややこしいですが,一つの要素のインデックス参照は,配列末尾から「-1 → -2 →・・・→ -10」となります.
スライスについては,スタートは負のインデックスの要素であり,最後は負のインデックス+1の要素までを選択しています.
スライスの指示も「小さい値:大きい値」とします.
考え方としては,インデックスの値が負になっただけで選択の仕方は同じよ考えた方がいいですかね.
(ややこしくしてしまっていたら申し訳ございません!!)

以上のように,リストでは負のインデックス参照,負のスライスを使います.

では,本題のndarrayにおける負のインデックス参照をしてみましょう.
前項で参照した順番,配列を負のインデックス参照で取り出しましょう.
考え方はリストと同じで,一番最後の行から「-1 → -2 →・・・→ -10」となります.

arr[[-3, -7, -10, -1]]

上記のように,参照すると前項と同様の結果が得られます.

array([[35, 36, 37, 38, 39],
       [15, 16, 17, 18, 19],
       [ 0,  1,  2,  3,  4],
       [45, 46, 47, 48, 49]])

このように最後の行,配列を基準に参照することができます.

複数の配列によるインデックス参照

これまでは一次元の配列を取り出していました.
では,複数の配列でインデックス参照をしてみたらどうなるでしょうか?

適当にやってみましょう.

arr[[6, 3, 7, 2], [1, 4, 2, 3]]
array([31, 19, 37, 13])

一次元の配列が取り出されました.
これはどうなっているかというと,配列を座標として考えたときに(6, 1),(3, 4),(7, 2),(2, 3)の座標にあるものを取り出してきたっていう感じですね.

「あれ?思ってたのと違う...」

って方もいるかもしれません.

「[6, 3, 7, 2]行目の[1, 4, 2, 3]列目,全部の要素を取り出してくるんじゃないの?」
って思うかもしれませんね.
こんな感じです.

[[31, 34, 32, 33],
[16, 19, 17, 18],
[36, 39, 37, 38],
[11, 14, 12, 13]]

実際は,一次元の配列が取り出されました.
これはこういうもんだと覚えておきましょう.

ちなみに上記のような配列を取り出すには以下のようにします.

arr[[6, 3, 7, 2]][:, [1, 4, 2, 3]]
array([[31, 34, 32, 33],
       [16, 19, 17, 18],
       [36, 39, 37, 38],
       [11, 14, 12, 13]])

これもこんなもんだと覚えておきましょう.

詳しくわかるためには,一緒に詳しくなっていきましょう!

最後にちょろっと注意点として,スライシングと異なり,ファンシーインデックス参照は元データのコピーを返すことに注意してください.
コピーとビューについては.「Python,NumPyの基礎② ~インデックス参照とスライシング~」の番外編で解説していますので,ぜひ参考にしてください.

まとめ

配列でインデックス参照をするファンシーインデックス参照について解説しました.
これで配列ごと取り出したり,狙った要素で配列で取り出したり出来ますね.

インデックス参照やスライスについては,
Python,NumPyの基礎② ~インデックス参照とスライシング~
Python,NumPyの基礎③ ~ndarray多次元配列のインデックス参照とスライス~
NumPyの基礎④ ~ndarrayにおけるブールインデックス参照~
でも紹介していますので,参考にしてください.

また,いつも通りこの記事は「Pythonによるデータ分析入門」を参考にしています.
気になる方はお手に取って確かめてください.

一緒に,Pythonを学んで,使いこなせるようにしていきましょう!!

コメント

タイトルとURLをコピーしました