[NumPy] ブール配列とマスキング操作

[NumPy] ブール配列とマスキング操作

NumPy の比較演算子

 NumPy の配列オブジェクトに対して比較演算子を用いると、ブール配列 (Boolean array) が生成されます。

# NumPyをインポート
import numpy as np

# 1次元配列を定義
x = np.array([1, 2, 3, 4, 5])

print(x > 3)
[False False False True True]

 このコードでは、1 次元配列 x の各要素について、3 より大きい場合は True, そうでない場合は False という要素で対応付けしたブール配列を生成しています。NumPy の配列に対する比較演算子は(ブール配列を生成する)ユニバーサル関数 (ufunc) として実装されています。たとえば x > 3 と記述した場合、内部で numpy.greater(x, 3) という関数を使用します。x == 1 と記述した場合は numpy.equal(x, 1) という関数を適用します。
 

マスキング操作

 ブール配列で配列の要素を参照すると、True に対応する要素のみを抽出することができます。

# 1次元配列を定義
x = np.array([1, 2, 3, 4, 5])

print(x[x > 3])
[4 5]

 このように、ブール配列をマスクとして利用して対象配列のサブセットを作成する手法をマスキング操作とよびます。
 

条件を満たす要素を数える

 numpy.count_nonzero()関数を使うと、True に対応する要素 (Trueエントリ) の数を数えることができます。

# 2次元配列を定義
x = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])

# 5より大きな要素を数える
ct = np.count_nonzero(x > 5)

print(ct)
4

 

ビット単位論理演算子

 NumPy では "&", "|", "^" のようなビット単位論理演算子もユニバーサル関数 (ufunc) として実装されています。これらの演算子を比較演算子と併用することで、より複雑な条件で要素を抽出することができます。

# 1~99の自然数
x = np.arange(1, 100)

# 2と3で割り切れる数を抽出
y = x[(x % 2 == 0) & (x % 3 == 0)]

print(y)
[6 12 18 24 30 36 42 48 54 60 66 72 78 84 90 96]

 この種のコードを Python の for文、あるいは内包表記で書いたことのある人ならば、NumPy の記法が簡潔で直感的に分かりやすいことを実感できるはずです。
 

いちばんやさしいPythonの教本 人気講師が教える基礎からサーバサイド開発まで 「いちばんやさしい教本」シリーズ

numpy.all()

 numpy.all() を使うと、ある条件に対して、すべての要素が True かどうかを素早く判定することができます。axis を指定すれば特定の軸に沿った真偽のリストを得ることもできます。

# 3×3の2次元配列を定義
x = np.array([[7, 5, 3],
              [2, 7, 8],
              [4, 1, 3]])

# 要素はすべて奇数?
b1 = np.all(x % 2 == 1)

# 列ごとに要素は奇数?
b2 = np.all(x % 2 == 1, axis = 0)

# 行ごとに要素は奇数?
b3 = np.all(x % 2 == 1, axis = 1)

print("要素はすべて奇数?", b1)
print("列ごとに要素はすべて奇数?", b2)
print("行ごとに要素はすべて奇数?", b3)
要素はすべて奇数? False
列ごとに要素はすべて奇数? [False  True False]
行ごとに要素はすべて奇数? [ True False False]

 

numpy.any()

 numpy.any() は、配列の要素の中に引数として与えた条件を満たすものが1個でもあれば True, 1個もないときには False() を返す関数です。

# 3×3の2次元配列を定義
x = np.array([[8, 8, 4],
              [1, 5, 1],
              [2, 6, 8]])

# 要素の中に奇数は存在する?
b1 = np.any(x % 2 == 1)

# 列ごとに奇数は存在する?
b2 = np.any(x % 2 == 1, axis = 0)

# 行ごとに奇数は存在する?
b3 = np.any(x % 2 == 1, axis = 1)

print("要素の中に奇数は存在する?", b1)
print("列ごとに奇数は存在する?", b2)
print("行ごとに奇数は存在する?", b3)
要素の中に奇数は存在する? True
列ごとに奇数は存在する? [ True  True  True]
行ごとに奇数は存在する? [False  True False]