NumPy配列ndarrayの条件を満たす要素数をカウント

Modified: | Tags: Python, NumPy

NumPy配列ndarrayの条件を満たす要素数をカウントする方法について説明する。

条件を満たす要素数ではなく、配列のサイズ(全要素数)はsize属性で取得できる。

条件を満たす要素・行・列の抽出や削除、置換については以下の記事を参照。

本記事のサンプルコードのNumPyのバージョンは以下の通り。バージョンによって仕様が異なる可能性があるので注意。

import numpy as np

print(np.__version__)
# 1.26.1

ndarrayの条件を満たす要素数をカウント: np.count_nonzero()

np.count_nonzero()は配列ndarrayの0でない要素の個数をカウントして返す。

a = np.arange(12).reshape((3, 4))
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print(np.count_nonzero(a))
# 11

ndarrayをスカラー値と比較すると、bool値(True, False)を要素とするndarrayが返される。<==, !=などで比較できる。

print(a < 4)
# [[ True  True  True  True]
#  [False False False False]
#  [False False False False]]

print(a % 2 == 0)
# [[ True False  True False]
#  [ True False  True False]
#  [ True False  True False]]

True1, False0とみなされるので、これらのndarraynp.count_nonzero()に渡すと、Trueの数、すなわち、条件を満たす要素の個数が得られる。

print(np.count_nonzero(a < 4))
# 4

print(np.count_nonzero(a % 2 == 0))
# 6

np.sum()でも同じ結果となるが、np.count_nonzero()のほうが高速。

print(np.sum(a < 4))
# 4

print(np.sum(a % 2 == 0))
# 6

ndarrayの行・列ごとに条件を満たす要素数をカウント

多次元配列に対するnp.count_nonzero()は、第二引数axisを指定することで各軸(各次元)に対する処理となる。デフォルトはaxis=Noneで、ndarray全体に対する処理。

二次元配列の場合、axis=0で列ごと、axis=1で行ごとの処理となる。行・列ごとに条件を満たす要素数をカウントできる。

a = np.arange(12).reshape((3, 4))
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print(np.count_nonzero(a < 4))
# 4

print(np.count_nonzero(a < 4, axis=0))
# [1 1 1 1]

print(np.count_nonzero(a < 4, axis=1))
# [4 0 0]

引数keepdimsTrueとすると、結果も元のndarrayと同じ次元数となる。

print(np.count_nonzero(a < 4, keepdims=True))
# [[4]]

print(np.count_nonzero(a < 4, axis=0, keepdims=True))
# [[1 1 1 1]]

print(np.count_nonzero(a < 4, axis=1, keepdims=True))
# [[4]
#  [0]
#  [0]]

なお、np.count_nonzero()の引数axisはバージョン1.12、引数keepdimsはバージョン1.19で追加された。np.sum()ではどちらもバージョン1.7で追加されたので、古いバージョンではnp.sum()を使えばよい。

np.any()で条件を満たす要素が一つでもあるか確認(全体、行・列ごと)

np.any()は、第一引数のndarrayTrueの要素が一つでもあるときにTrueを返し、そうでないときはFalseを返す。

ndarrayに条件を満たす要素が一つでもあるかを確認できる。

a = np.arange(12).reshape((3, 4))
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print(np.any(a < 4))
# True

print(np.any(a > 100))
# False

np.any()np.count_nonzero()と同じように、第二引数axisを指定すると行・列ごとの処理となる。

print(np.any(a < 4, axis=0))
# [ True  True  True  True]

print(np.any(a < 4, axis=1))
# [ True False False]

例は省略するが、引数keepdimsも指定可能。

np.all()ですべての要素が条件を満たすか確認(全体、行・列ごと)

np.all()は、第一引数のndarrayの要素がすべてTrueのときにTrueを返し、そうでないときはFalseを返す。

ndarrayのすべての要素が条件を満たすかを確認できる。

a = np.arange(12).reshape((3, 4))
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print(np.all(a < 4))
# False

print(np.all(a < 100))
# True

np.all()np.count_nonzero()と同じように、第二引数axisを指定すると行・列ごとの処理となる。

print(np.all(a < 4, axis=0))
# [False False False False]

print(np.all(a < 4, axis=1))
# [ True False False]

例は省略するが、引数keepdimsも指定可能。

複数条件を適用

複数の条件を組み合わせたい場合は、各条件式を括弧()で囲んで&(AND)や|(OR)でつなぐ。否定~(NOT)も使用可能。

a = np.arange(12).reshape((3, 4))
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print((a < 4) | (a % 2 == 0))
# [[ True  True  True  True]
#  [ True False  True False]
#  [ True False  True False]]

print(np.count_nonzero((a < 4) | (a % 2 == 0)))
# 8

print(np.count_nonzero((a < 4) | (a % 2 == 0), axis=0))
# [3 1 3 1]

print(np.count_nonzero((a < 4) | (a % 2 == 0), axis=1))
# [4 2 2]

&, |ではなくand, orを使ったり、括弧を省略したりするとエラーになるので注意。

欠損値NaNをカウント

例えば、以下のようなデータが欠落したCSVファイルをndarrayとして読み込むと欠損値NaNが発生する。

a_nan = np.genfromtxt('data/src/sample_nan.csv', delimiter=',')
print(a_nan)
# [[11. 12. nan 14.]
#  [21. nan nan 24.]
#  [31. 32. 33. 34.]]

欠損値NaN同士は==で比較してもFalseになってしまうため、欠損値をカウントするにはnp.isnan()を使う。

print(np.nan == np.nan)
# False

print(a_nan == np.nan)
# [[False False False False]
#  [False False False False]
#  [False False False False]]

print(np.isnan(a_nan))
# [[False False  True False]
#  [False  True  True False]
#  [False False False False]]

あとはこれまでの例と同じ。np.count_nonzero()np.sum()Trueの数をカウントすればよい。

print(np.count_nonzero(np.isnan(a_nan)))
# 3

print(np.count_nonzero(np.isnan(a_nan), axis=0))
# [0 1 2 0]

print(np.count_nonzero(np.isnan(a_nan), axis=1))
# [1 2 0]

欠損値ではない要素をカウントしたい場合は否定~を使う。

print(~np.isnan(a_nan))
# [[ True  True False  True]
#  [ True False False  True]
#  [ True  True  True  True]]

欠損値の置換や削除については以下の記事を参照。

無限大infをカウント

要素が無限大infかどうかを判定する関数はnp.isinf()。正負どちらの無限大もTrueとなる。

a_inf = np.array([-np.inf, 0, np.inf])
print(a_inf)
# [-inf   0.  inf]

print(np.isinf(a_inf))
# [ True False  True]

正の無限大に対してTrueを返すnp.isposinf()、負の無限大に対してTrueを返すnp.isneginf()もある。

print(np.isposinf(a_inf))
# [False False  True]

print(np.isneginf(a_inf))
# [ True False False]

無限大は==で比較できるので、正負どちらかのみを判定したい場合は==を使ってもよい。

print(a_inf == np.inf)
# [False False  True]

print(a_inf == -np.inf)
# [ True False False]

あとはこれまでの例と同じ。

print(np.count_nonzero(np.isinf(a_inf)))
# 2

print(np.count_nonzero(np.isposinf(a_inf)))
# 1

print(np.count_nonzero(np.isneginf(a_inf)))
# 1

無限大の演算などについては以下の記事を参照。

関連カテゴリー

関連記事