NumPy配列の条件を満たす要素の確認や置換・カウントの方法まとめ

NumPyの配列から条件に合う要素を探索して操作するための主な関数やメソッドには以下があります。

  • np.any(): 配列内に条件を満たす要素が1つでもあるかどうか確認
  • ndarray.any(): 同上のメソッド版
  • np.all(): 配列内の全ての要素が条件を満たしているかどうか確認
  • ndarray.all(): 同上のメソッド版
  • np.where(): 条件に合う要素をx に、合わない要素をy に置換
  • np.nonzero(): 配列内のFalse(==0)以外の要素のインダイスを取得
  • ndarray.nonzero(): 同上のメソッド版
  • np.count_nonzero(): 条件を満たす要素をカウント

これら以外にも使用可能な関数やメソッドはありますが、基本的にはこれらを抑えておけば十分です。もし、これら以外が気になるとしても、このページからのリンク先のページで解説しているのでご安心ください。

それでは、これらの使い方について見ていきましょう。

条件式の書き方について
条件式を書くには、比較演算子や論理演算子、ビット演算子の理解が不可欠です。それらを理解しておくことで複数条件の指定も可能になります。『Pythonの演算子の一覧表とわかりやすい解説』で解説しているので確認しておきましょう。

目次

1. NumPy配列の条件確認

まず、NumPy配列の中に条件を満たす要素があるかどうかを確認する関数として、以下が用意されています。

  • np.any(): 配列内に1つでも条件を満たす要素があるか確認
  • ndarray.any():同上のメソッド版
  • np.all(): 配列内の全ての要素が条件を満たしているか確認
  • ndarray.all(): 同上のメソッド版

基本的には関数よりもメソッドの方が2-2.5倍ほど高速です。それでは、早速実際のコードで確認していきましょう。

any(): 1つでも条件を満たす要素があるか

以下の配列を使って、any()の使い方を確認しましょう。

In [1]:
import numpy as np
rng = np.random.default_rng()
a = rng.integers(-10, 11, (2, 5))
a
Out[1]:
array([[-6,  3,  6,  0,  7],
       [ 8,  4,  4, -5,  2]])

この配列の中に5以上の値が1つでも含まれているでしょうか?

In [2]:
# 配列a に5以上の値が1つでも含まれているか?
np.any(a >=5)
Out[2]:
True
In [3]:
# メソッドの書き方の確認
(a >= 5).any()
Out[3]:
True

含まれているのでTrue を返します。

any()は条件を満たす要素が1つもない場合にFalseを返します。

In [4]:
# 条件を満たす要素が1つもない場合にFalseを返す
np.any(a == 100)
Out[4]:
False
In [5]:
(a == 100).any() # メソッド
Out[5]:
False

なおサンプルコードでは多次元配列の中の全ての要素を一括で確認していますが、any()は指定の次元軸に従って確認することも可能です。その他のオプション引数も含めて、以下のページでより詳しく解説しています。

all(): 全ての要素が条件を満たすか

all()は、配列内のすべての要素が条件を満たしている場合のみTrue を返します。以下の配列を使って確認していきましょう。

In [1]:
import numpy as np
rng = np.random.default_rng()
a = rng.integers(0, 20, (2, 5))
a
Out[1]:
array([[18, 12, 16, 17,  0],
       [ 9,  7, 11,  1, 15]])

この配列のすべての要素が0以上の整数でしょうか?

In [2]:
# 配列a のすべての要素が0以上の整数か?
np.all(a >= 0)
Out[2]:
True
In [3]:
# メソッドの書き方の確認
(a >= 0).all()
Out[3]:
True

答えはTrueですね。

all()は、配列の中に1つでも条件を満たさない要素があるとFalseを返します。以下のコードでは、全ての要素が16でないという条件を満たさない(=1つ以上16がある)のでFalseを返しています。

In [4]:
# 1つでも条件を満たさない要素がある場合にFalseを返す
np.all(a != 16)
Out[4]:
False
In [5]:
(a != 16).all() # メソッド
Out[5]:
False

なお、all()any()と同様に次元軸を指定したり、ブロードキャストをしやすくするために次元数を維持したまま出力したりすることが可能です。より詳しくは以下のページで解説しています。

2. NumPy配列を条件で置換

配列の条件を満たす要素をx に、それ以外の要素をy に置換するにはnumpy.where()を使います。この関数には同名のメソッドはありません。

np.where(): 条件を満たす要素を置換

それでは以下の配列を例に確認していきましょう。

In [1]:
import numpy as np
rng = np.random.default_rng()
a = rng.integers(0, 11, (2, 5))
a
Out[1]:
array([[6, 5, 2, 5, 1],
       [6, 9, 8, 9, 8]])

numpy.where()は、第一引数に条件式を、第二引数に条件を満たす場合に置換する値を、第三引数にそれ以外の場合に置換する値を渡します。

以下のコードをご覧ください。

In [2]:
# 偶数を'e'に、奇数を'o'に置換
np.where(a%2==0, 'e', 'o')
Out[2]:
array([['e', 'o', 'e', 'o', 'o'],
       ['e', 'o', 'e', 'o', 'e']], dtype='<U1')

& や | や ^ といった演算子を使うことで複数条件を指定することも可能です。

In [3]:
# 偶数でかつ6以上を100に、それ以外を0に置換
np.where((a%2==0) & (a >= 6), 100, 0)
Out[3]:
array([[100,   0,   0,   0,   0],
       [100,   0, 100,   0, 100]])

以下のページでは、この関数についてさらに詳しく解説しています。ぜひご確認ください。

なお、numpy.where()でも条件を満たす要素のインダイスを取得することが可能ですが、その目的であれば次に解説するnumpy.nonzero()の方が適しています。

3. NumPy配列の条件を満たす要素のインダイスを取得

インダイスの配列を取得すると、配列のスライステクニックを使って、かなり自由に要素を抽出することが可能です。そして、条件を満たす要素のインダイスを取得したい場合は以下の関数やメソッドを使います。

なお、配列のスライスについては『NumPyの配列のスライスの必須テクニックまとめ』で詳しく解説しているので、インダイスの配列を使いこなすためには、是非一度ご確認ください。

  • np.nonzero(): False(==0)以外の要素のインダイスを取得
  • ndarray.nonzero(): 同上のメソッド版
  • np.flatnonzero(): False(==0)以外の要素のインダイスを1次元配列で取得
  • ndarray.flatnonzero(): 同上のメソッド版
  • np.argwhere(): 条件を満たす要素のインダイスを取得

基本的には関数よりもメソッドの方が、処理が2-2.5倍ほど高速です。

ここでは、この中で最も重要なnonzero()について解説します。flatnonzero()は、nonzero(a.flatten())と同じなので割愛します。

またnumpy.argwhere()で取得できるインダイスは、nonzero()と比べて配列のスライスには向いておらず、あまり使いどころがありません。それでも気になる場合は『NumPyで条件に合う要素のインダイスを取得するargwhere()の使い方』をご確認ください。

それでは、nonzero()の使い方を確認していきましょう。

nonzero(): False以外の要素のインダイスを取得

nonzero()は、配列内の0以外の要素のインダイスを取得する関数です。PythonではFalse==0 なので、これによって取得するインダイスを、条件を満たす要素を抽出するために使うことができます。

以下の配列を使って見ていきましょう。

In [1]:
import numpy as np
a = np.arange(-2, 7).reshape(3, 3)
a
Out[1]:
array([[-2, -1,  0],
       [ 1,  2,  3],
       [ 4,  5,  6]])

nonzero()は、デフォルトでは0以外の要素のインダイスを取得します。

In [2]:
# デフォルトでは0以外の要素のインダイスを取得
ind = np.nonzero(a)
ind
Out[2]:
(array([0, 0, 1, 1, 1, 2, 2, 2]), array([0, 1, 0, 1, 2, 0, 1, 2]))
In [3]:
# メソッド
ind = a.nonzero()
ind
Out[3]:
(array([0, 0, 1, 1, 1, 2, 2, 2]), array([0, 1, 0, 1, 2, 0, 1, 2]))

取得したインダイスでスライスすると、0以外の要素の値を取得することができます。

In [4]:
# 取得したインダイスでスライス
a[ind]
Out[4]:
array([-2, -1,  1,  2,  3,  4,  5,  6])

nonzero()の便利さは、条件を満たす要素のインダイスを取得することができる点にあります。例えば以下では4より大きな値という条件を満たす要素のインダイスを取得しています。

In [5]:
# 4以上の要素のインダイスを取得
ind = np.nonzero(a > 4)
ind
Out[5]:
(array([2, 2]), array([1, 2]))
In [6]:
# メソッド
ind = (a>4).nonzero()
ind
Out[6]:
(array([2, 2]), array([1, 2]))

スライスしてみましょう。

In [7]:
# 取得したインダイスを使ってスライス
a[ind]
Out[7]:
array([5, 6])

ここでは簡単な例を見てきましたが、こうしたインダイスの配列を用いたスライスは、高度なスライスでよく用いることになります。これを使いこなせるようになると、かなり自由自在に、任意の条件の値を取得することが可能になります。これらを身につけるためにも『NumPyの配列のスライスの必須テクニックまとめ』は必ず確認していただければと思います。

なお、flatnonzero()も含めてnonzero()についてより詳しいことは以下のページで解説していますので、こちらも是非ご確認ください。

またスライシングには不向きですが、False以外の要素の、要素ごとのインダイスを取得するには、numpy.argwhere()関数というものがあります。これについては『NumPyで条件に合う要素のインダイスを取得するargwhere()の使い方』で解説しています。

4. NumPy配列の条件カウント

最後に、配列内に条件を満たす要素が何個あるのかをカウントする関数について確認しておきましょう。

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

count_nonzero()を使うと、条件を満たす要素の数を取得することができます。なお、count_nonzero()にはメソッドはありません。

In [1]:
import numpy as np
a = np.arange(-2, 7).reshape(3, 3)
a
Out[1]:
array([[-2, -1,  0],
       [ 1,  2,  3],
       [ 4,  5,  6]])

デフォルトでは値が0(==False)以外の要素の数を取得します。

In [2]:
# 0以外の要素の数
np.count_nonzero(a)
Out[2]:
8

以下のコードのように引数を条件式で渡せば、条件に合う要素の数を取得します。

In [3]:
# 4より大きな要素の数
np.count_nonzero(a > 4)
Out[3]:
2

5. まとめ

以上がNumPy配列の条件を満たす要素を操作するために抑えておくべき主な関数・メソッドです。最後にもう一度一覧でまとめておきましょう。

関数・メソッド名 解説
np.any 条件を満たす要素が1つでもあるか確認
ndarray.any 同上のメソッド版
np.all 全ての要素が条件を満たしているか確認
ndarray.all 同上のメソッド版
np.where 条件を満たす要素をxに、それ以外をyに置換
np.nonzero 条件を満たす要素のインダイスを取得
ndarray.nonzero 同上のメソッド版
np.count_nonzero   条件を満たす要素をカウント

なお、これ以外に出てきたflatnonzero()についても『NumPyで0以外の要素のインダイスを取得するnonzero()の使い方』で解説しています。さらに、条件を満たす要素の要素ごとのインダイスを取得する手段として、他にも『NumPyで条件に合う要素のインダイスを取得するargwhere()の使い方』があります。

それぞれ役立てて頂ければ幸いです。



よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

目次
閉じる