import numpy as np
import matplotlib.pyplot as plt
arr = np.arange(16).reshape(4, 4)
arr
# スライスした部分配列(行1, 2)の要素に全て-1を代入する
arr[1:3] = 0
# オリジナルの配列
arr
# 全て0に初期化(配列を再生成せず、要素のみ書き換えている)
arr[:] = 0
arr
使い道としては、各軸の値をなんらかの計算をしたあと、再び代入するのに使います。
# 一様乱数
arr = np.random.rand(3, 4)
arr
# 3行目を書き換える
arr[2] = arr[2] - 1
arr
# 2列めを書き換える
arr[:, 1] = arr[:, 1] + arr[:, 2]
arr
オリジナルの配列が変わってほしくないときは、copy関数で同じ配列を複製できます。
arr_copied = arr.copy()
arr_copied
配列に値や配列を代入するときには、意識的にスライスを使うようにした方がいいです。
例えばスカラーを配列の全要素に代入しようとしたとき、スライスを使わないといけません。
a = np.arange(10)
a
# ↓-100をaの全要素に代入するつもりで書いたら
# 配列ですらなくなっている!?
a = -100
a
# 正しくは
a = np.arange(10)
a[:] = -100
a
配列として扱いたい場合は、スライスを使った代入を心がけましょう。
スライスよりも柔軟に部分配列を取り出せるインデックス参照がファンシーインデックス参照です。
配列(ndarrayやリスト、タプルなど)をインデックスに入れると、部分配列(コピー)を返すという機能です。
Numpyの使いやすさを格段に上げる機能であり、使う機会も多くなると思います。
インデックスに配列を入れることで、対応する軸を抜き出すということをしてくれます。
a = np.arange(12).reshape(4, 3)
a
# ファンシーインデックス参照の一例(行1, 3を抜き出す)
a[[1, 3]]
# ファンシーインデックス参照の一例(列0, 1を抜き出す)
a[:, [0, 1]]
# ファンシーインデックス参照を使った代入の例(列0, 1をそれぞれ10倍する)
a[:, [0, 1]] = a[:, [0, 1]] * 10
a
ファンシーインデックス参照は直接代入するときは上のようにビューとして振る舞いますが、変数に格納するときはコピーされます。
a
# 列0, 1を抜き出す(コピーになる)
b = a[:, [0, 1]]
b
# 全要素を0
b[:] = 0
b
# もともとの配列は書き換わらない(コピーされている!)
a
ある条件の値だけを抜き出すといったとき、boolによるインデクシングが利用できます。
# 10個の正規分布乱数
rand_values = np.random.randn(15)
rand_values
1より大きい値を抜き出したい場合、以下のような真偽値の配列を作り、それをインデックスにわたすことでTrueの場所だけを抜き出すことができます。
rand_values >= 1
# 1より大きい値を抜き出す
rand_values[rand_values >= 1]
これを応用すると、2次元配列で特定の条件の列(行)を抜き出すといったことが簡単にできます。
rand_2d = rand_values.reshape(3, 5)
rand_2d
# 1より大きい値を少なくとも1つ含む列を抜き出す
rand_2d[:, (rand_2d > 1).any(axis=0)]
any関数は、一つでもTrueがあればTrueを返す関数です。
これにaxis=0を指定すると、列にTrueが含まれているかを真偽値で返す関数になります。
(rand_2d > 1).any(axis=0)