np.count_nonzeroの使い方|NumPyで条件に合う要素数・Trueの数を数える(axis・NaN・sumとの速度比較)

np.count_nonzero(a)は、配列のうち0でない要素(ブール配列ならTrue)の個数を返す関数です。条件に合う要素数はnp.count_nonzero(arr > 0)のように条件式を渡して数え、行ごと・列ごとに数えるときはaxisを指定します。

この記事のコードはすべてNumPy 2.5.4・Python 3.12で実行し、出力をそのまま載せています(2026年10月15日確認)。引数の仕様は公式リファレンスnumpy.count_nonzeroに沿っています。

np.count_nonzeroの書式と引数

numpy.count_nonzero(a, axis=None, *, keepdims=False)
引数 意味 既定値
a 数える対象の配列(リストなども可) 必須
axis 数える方向。整数かタプル。指定しなければ全体を数える None
keepdims Trueにすると、数えた軸を長さ1の次元として残す False

公式リファレンスでは、「0でない」とはブール値として評価したときに真になる値のことで、0以外の数と空でない文字列が含まれる、と説明されています。戻り値は、axisを指定しなければ整数1つ、指定すれば整数の配列です。

基本:0でない要素と、条件に合う要素を数える

import numpy as np

arr = np.array([10, -5, 0, 20, -15, 30, 0])
print(np.count_nonzero(arr))       # 0でない要素の数
print(np.count_nonzero(arr > 0))   # 0より大きい要素の数
print(arr > 0)
5
3
[ True False False  True False  True False]

arr > 0は要素ごとに比較したTrue/Falseの配列(ブール配列)を返します。Trueは「0でない値」として扱われるので、ブール配列をcount_nonzeroに渡すとTrueの数、つまり条件に合う要素数になります。「numpy count true」で探している場合も、答えはこの書き方です。

0の個数を数える(count_zeroはない)

NumPyにcount_zeroという関数はありません。0の個数は、全要素数から0でない要素数を引くか、== 0の条件を数えます。

print(arr.size - np.count_nonzero(arr))
print(np.count_nonzero(arr == 0))
2
2

複数の条件を組み合わせて数える

範囲指定(AND)は&、どちらか(OR)は|でつなぎます。Pythonのand/orは配列には使えず、各条件はかっこで囲む必要があります。

print(np.count_nonzero((arr >= 0) & (arr <= 20)))   # 0以上20以下
print(np.count_nonzero((arr < 0) | (arr > 20)))     # 0未満または20より大きい
4
3

2次元配列で行ごと・列ごとに数える(axis・keepdims)

4人×3科目の点数で、60点以上の数を数えてみます。

# 4人 × 3科目の点数
scores = np.array([[80, 45, 92],
                   [60, 70, 65],
                   [55, 88, 75],
                   [90, 20, 65]])
mask = scores >= 60
print(np.count_nonzero(mask))                         # 全体
print(np.count_nonzero(mask, axis=0))                 # 科目(列)ごと
print(np.count_nonzero(mask, axis=1))                 # 人(行)ごと
print(np.count_nonzero(mask, axis=1, keepdims=True))  # 行ごと・次元を残す
9
[3 2 4]
[2 3 2 2]
[[2]
 [3]
 [2]
 [2]]
指定 数える方向 結果の形
なし 全要素 整数1つ(9)
axis=0 縦方向に数える=列ごと (3,)
axis=1 横方向に数える=行ごと (4,)
axis=1, keepdims=True 行ごと (4, 1)

keepdims=Trueは、結果を元の配列と計算したいとき(例:行ごとの合格科目数で各セルを割る)に、ブロードキャストの形を合わせるために使います。keepdimsの考え方はNumPyのkeepdims=Trueとは?で詳しく説明しています。

NaN(欠損値)の数え方に注意

NaNは0ではないので、count_nonzeroにそのまま渡すと「0でない値」として数えられてしまいます。NaNの数を数えるときはnp.isnan()でブール配列にしてから渡します。

x = np.array([1.0, np.nan, 0.0, np.nan, 3.0])
print(np.count_nonzero(x))             # NaNも0でない値として数えられる
print(np.count_nonzero(np.isnan(x)))   # NaNの数
print(np.count_nonzero(~np.isnan(x)))  # NaNでない要素の数
4
2
3

NaNを含む行や列を取り除く方法はNumPyでNaNを含む行・列を削除する方法にまとめています。

文字列の配列にも使える

公式リファレンスのとおり、空でない文字列は「0でない値」として数えられます。

s = np.array(["a", "", "b", ""])
print(np.count_nonzero(s))          # 空文字でない要素の数
print(np.count_nonzero(s == "a"))   # "a" の数
2
1

sum()・np.where()との違いと速度

ブール配列のTrueは1として足し算されるので、mask.sum()やnp.sum(mask)でも同じ数が得られます。np.where(mask)はTrueの位置(インデックス)を返すので、その長さでも数えられます。結果はどれも同じです。

r1 = np.count_nonzero(arr > 0)
r2 = (arr > 0).sum()
r3 = np.sum(arr > 0)
print(type(r1), type(r2), type(r3), r1, r2, r3)
print(np.where(arr > 0))
<class 'numpy.int64'> <class 'numpy.int64'> <class 'numpy.int64'> 3 3 3
(array([0, 3, 5]),)

1,000万要素のブール配列で、4つの書き方の実行時間をtimeitで測りました(各20回の平均を5回測った最小値)。

import timeit
import numpy as np

rng = np.random.default_rng(0)
a = rng.random(10_000_000)
mask = a > 0.5
for stmt in ["np.count_nonzero(mask)", "mask.sum()", "np.sum(mask)", "len(np.where(mask)[0])"]:
    t = min(timeit.repeat(stmt, globals=globals(), number=20, repeat=5)) / 20
    print(f"{stmt:24s} {t*1000:.2f} ms")
np.count_nonzero(mask)   0.33 ms
mask.sum()               1.95 ms
np.sum(mask)             1.94 ms
len(np.where(mask)[0])   6.74 ms

筆者の環境(Apple M2、NumPy 2.5.4)ではcount_nonzeroがいちばん速く、sum()の約6分の1の時間でした。数値は環境によって変わりますが、np.where()は位置の配列を作るぶん遅くなります。個数だけが必要ならcount_nonzero、位置も使うならnp.where()、割合(平均)を出すならnp.mean(mask)、と使い分けます。

書き方 返すもの 向いている場面
np.count_nonzero(mask) 個数 個数だけ知りたい
mask.sum() 個数 ほかの集計と書き方をそろえたい
np.mean(mask) 割合(0〜1) 条件に合う割合を出したい
np.where(mask) 位置(インデックス) どこにあるかも使いたい

np.where()の使い方はnp.whereの使い方で解説しています。

値ごとの出現回数をまとめて数える

特定の1つの値ならnp.count_nonzero(v == 3)で数えられますが、すべての値の出現回数を一度に知りたいときはnp.unique(..., return_counts=True)が便利です。0以上の整数ならnp.bincount()も使えます。

v = np.array([3, 1, 3, 2, 3, 1])
print(np.count_nonzero(v == 3))
vals, counts = np.unique(v, return_counts=True)
print(vals, counts)
print(np.bincount(v))   # 0, 1, 2, 3 それぞれの個数
3
[1 2 3] [2 1 3]
[0 2 1 3]

np.uniqueの詳しい使い方はnp.uniqueとは?を参照してください。

よくある質問

Q. np.count_nonzeroとsum()はどちらを使えばよいですか。

結果は同じです。個数を数えるだけならcount_nonzeroのほうが意図が読み取りやすく、今回の計測でもsum()より速く動きました。行ごと・列ごとに数えるときは、どちらもaxisを指定できます。

Q. 0の個数を数える関数はありますか。

count_zeroという関数はありません。arr.size – np.count_nonzero(arr)、またはnp.count_nonzero(arr == 0)で数えます。

Q. NaNの数を数えたら多すぎる値が出ました。

NaNは0ではないため、count_nonzeroにそのまま渡すと数に入ります。NaNの数はnp.count_nonzero(np.isnan(x))で数えてください。

Q. pandasのDataFrameでも使えますか。

使えます。np.count_nonzero(df[“列”] > 0)のように条件式を渡せば個数が返ります。pandasだけで書くなら(df[“列”] > 0).sum()でも同じ結果になります。

まとめ

  • np.count_nonzero(a)は0でない要素(True)の個数を返す
  • 条件に合う要素数はnp.count_nonzero(条件式)。複数条件は&・|とかっこ
  • 行ごと・列ごとはaxis、形を残すならkeepdims=True
  • 0の個数はsizeから引く。NaNはnp.isnan()を通してから数える
  • 個数だけならcount_nonzero、割合はnp.mean、位置はnp.where

NumPy|抽出・条件の関連記事

条件指定やスライスで、配列から必要な要素を取り出す操作の記事です。

NumPy全体の使い方は「NumPyの使い方」、「NumPy関数一覧」でまとめています。

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら