NumPy配列のブールインデックス参照

[] の中にインデックスを書く代わりに論理値(True/False)の配列を書くとその論理値がTrueに該当する箇所の要素をピックアップしたndarrayを新しく作ってくれる。

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

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

print(ndarr1[np.array([False, True, False, False, False, True])])
# 出力結果
# [10 50]

これの何が便利かというと、まず ndarr1 % 20 == 0 のように書くと ベクトル計算により論理値の配列が生成されるので、それをそのまま [] の中に書くことによってフィルタ処理のようなことができるのである。

print(ndarr1 % 20 == 0)
# 出力結果
# [ True False  True False  True False]

print(ndarr1[ndarr1 % 20 == 0])
# 出力結果
# [ 0 20 40]

論理値の配列同士で論理和演算子 |、論理積演算子 & も使える。

print(ndarr1[(ndarr1 % 20 == 0) | (ndarr1 % 30 == 0)])
# 出力結果
# [ 0 20 30 40]

print(ndarr1[(ndarr1 % 20 == 0) & (ndarr1 % 30 == 0)])
# 出力結果
# [0]

[] に論理型のndarrayではなく普通の配列を渡すと意図した動作にならない。将来のバージョンでは変わるかもしれないが、自分が試した Python 2.7.8, NumPy 1.9.0 の環境ではダメだった。

print(ndarr1[[False, True, False, False, False, True]])
# 出力結果
# FutureWarning: in the future, boolean array-likes will be handled as a boolean array index
# [ 0 10  0  0  0 10]

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

bi = ndarr1[ndarr1 % 20 == 0]
print(bi)
# 出力結果
# [ 0 20 40]

bi[0] = 100
print(bi)
# 出力結果
# [100  20  40]

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

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

ndarr1[ndarr1 % 20 == 0] = [100, 120, 140]

print(ndarr1)
# 出力結果
# [100  10 120  30 140  50]

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

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

関連

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