個人的神殿

プログラミング

NumPy 要素の参照

リストと同じようにスライスできる。

x = np.arange(10)
x
x[3]

x[1:4]

x[4:-1:2]
[0 1 2 3 4 5 6 7 8 9]

3

[1 2 3]

[4 6 8]


多次元配列も多次元リストと同様

x = np.random.randint(1, 10, size=(4, 5))

x

x[3]

x[3][0]
[[4 6 5 7 6]
 [4 5 8 2 5]
 [9 3 8 5 7]
 [8 2 9 8 1]]

[8 2 9 8 1]

8


配列はリストと異なり、,で区切って要素を参照できる。

x = np.random.randint(1, 10, size=(4, 5))

x

x[0][1]
x[0, 1] # 0行1列目

x[:, 1]  # 1列目

x[0, :]  # 0行目

x[0:3, 1:4] # 0~2行目まで取り出し、そのあと1~3列目まで

x[::2,::2] # 各次元を1つ飛ばして参照
[[4 5 1 4 7]
 [4 5 6 7 4]
 [9 3 3 1 7]
 [6 8 5 5 2]]

5
5

[5 5 3 8]
[4 5 1 4 7]

[[5 1 4]
 [5 6 7]
 [3 3 1]]

[[4 1 7]
 [9 3 7]]

スライスで取得したものはビューと呼ばれ、、元の配列と同じメモリ上のデータを参照している。気をつけなければいけないのは、ビューの要素を変更した場合、同じメモリ上のデータを参照している配列も変更されることになる。

x = np.random.randint(1, 10, size=(4, 5))

x

y = x[:3, :3]

y

y[:, :] = 0 # yの要素を全て0にする

y

x
[[7 2 8 6 2]
 [4 3 6 2 7]
 [9 5 2 4 5]
 [5 4 7 7 9]]

[[7 2 8]
 [4 3 6]
 [9 5 2]]

[[0 0 0]
 [0 0 0]
 [0 0 0]]

# ↓!?
[[0 0 0 6 2]
 [0 0 0 2 7]
 [0 0 0 4 5]
 [5 4 7 7 9]]


これを解決するにはcopyメソッドを使用。
この返り値は部分配列のデータは新しくメモリ上にコピーされる。

z = x[:3, :3].copy()

z

z[:, :] = -5

z

x
[[7 2 8]
 [4 3 6]
 [9 5 2]]

[[-5 -5 -5]
 [-5 -5 -5]
 [-5 -5 -5]]

# ↓影響無し
[[0 0 0 6 2]
 [0 0 0 2 7]
 [0 0 0 4 5]
 [5 4 7 7 9]]


ファンシーインデックス参照という、整数要素のリストや配列を
インデックスに使う参照方法がある。
これははじめからコピーとして切り出すのでもとの配列に影響は無い。

x = np.random.randint(1, 10, size=(4, 4))

x

# xの0番目と3行目の行から成る配列は
x[[0, 3]]

# 0行2列めと2行3列目の要素から成る配列は
x[[0, 2], [2, 3]]
[[6 9 8 5]
 [2 9 5 5]
 [6 4 2 2]
 [5 2 3 1]]

[[6 9 8 5]
 [5 2 3 1]]

[8 2]