numpy.nonzero()は値が0以外(つまりFalse以外)の要素のインダイスを取得する関数です。この関数によって取得したインダイスは、配列の高度なスライスに使われます。なお、同機能のメソッド版にndarray.nonzero()もあります。基本的にはメソッド版の方が2.5倍ほど高速です。
さらに、同種の関数として、1次元配列に変換した場合の0以外の要素のインダイスを取得するnumpy.flatnonzero()と、0以外の要素の数を取得するnumpy.count_nonzero()もあります。
このページではこれらの関数について解説していきます。
NumPy配列の条件を満たす要素の操作まとめ
NumPy配列では、条件を満たす要素の値を取得したり、数をカウントしたり、置換したりなど様々な操作が可能です。こうした操作については、『NumPy配列の条件を満たす要素の確認や置換・カウントの方法まとめ』で全てまとめていますので、ぜひご確認ください。
1. numpy.nonzeroの使い方
まずは基本的な書き方を見ておきましょう。以下のようにnonzero()にはオプション引数はありません。
書き方:
np.nonzero(a)
パラメーター:
引数 | 型 | 解説 |
---|---|---|
a | array_like | 配列を渡します。 |
戻り値:
インダイスをタプルに格納した配列 配列内の0以外の要素のインダイス |
一緒に確認したい関数:
- ndarray.nonzero: 同機能のメソッド版
- flatnonzero: 1次元化した場合のインダイスを取得
- count_nonzero: 0以外の要素の数を取得
- argwhere: 次元軸ごとではなく要素ごとのインダイスを取得
書き方:
ndarray.nonzero()
Note
0以外の値は、a[np.nonzero(a)]で取得することはできますが、その目的であれば、x[x.astype(bool)] かx[x=!0] を使いましょう。
また、サンプルコードで見ていきますが、nonzero()で取得するインダイスは次元軸ごとに仕切られています。要素ごとのインダイスを取得したい場合はargwhere()を使います。
2. サンプルコード
それではサンプルコードを見ながら確認していきましょう。
ここでは冒頭で述べた以下の4つの関数およびメソッドと、
- numpy.nonzero()
- ndarray.nonzero()
- numpy.flatnonzero()
- numpy.count_nonzero()
上述した以下の関数についても簡潔に確認します。
- numpy.argwhere()
また、nonzero()は、基本的な使い方としては、値が0ではない要素のインダイスを取得します。しかし、実践上は主にブール値の配列で要素がTrue のインダイスを取得するために使います(Pythonでは 0 == False)。ここではそれぞれについて解説します。
2.1. 基本的な使い方
以下の2次元配列を例に確認しましょう。
import numpy as np
x = np.array([[3, 0, 0], [0, 4, 0], [5, 6, 0]])
x
この配列を、np.nonzero()に渡すと、以下のように値が0ではない要素のインデックスを返します。
# 値が0以外の要素のインデックスを取得
ind = np.nonzero(x)
ind
タプルの中の最初の配列が2次元軸(縦軸)のインデックスで、後の配列が1次元軸(横軸)のインデックスです。
メソッドも全く同じです。
# メソッドも同じ
ind = x.nonzero()
ind
以下のコードのように、このインダイスの配列を使って、元の配列をスライスすることができます。
# 値を取得
x[ind]
また、np.transpose()でこの配列を転置すると、多次元配列のインダイスを取得することができます。
# インデックスの取得にはnp.transpose()を使う
np.transpose(ind)
これを使ってfor文で0以外の要素を取り出すことができます。
# for文で0以外の要素を取り出す
for i in np.transpose(ind):
print(x[tuple(i)])
ただし、numpy.argwhere()を使えば、わざわざ転置する必要はありません。
# argwhere()関数でも取得可能
np.argwhere(x != 0)
このように要素ごとのインダイスを取得したい場合は、numpy.argwhere()を使いましょう。
flatnonzero()
なお、numpy.flatnonzero()は引数に渡した配列を1次元化した場合の0以外の要素のインデックスを取得します。
# np.flatnonzero()
ind = np.flatnonzero(x)
ind
余談ですが、インダイスの配列を任意のshapeの場合のインダイスに変換するにはnp.unravel_index()が便利です。
# インダイスの配列を
# 任意のshapeの配列の場合のインダイスに変換
np.unravel_index(ind, (3, 3))
count_nonzero()
さらに、配列内の0以外の要素の数をカウントするnumpy.count_nonzero()もあります。
# 0以外の要素の数を取得
np.count_nonzero(x)
2.2. 実践的な使い方
さて、ここまで見てきたようにnonzero()は、値が0以外の要素のインダイスを取得します。Pythonでは、False == 0 なので、nonzero()は、実践上はブール値の配列(“Masked Array”といいます)において条件式がTrue の要素のインダイスを取得するために主に使われます。
そして、ブール値の配列は、配列の高度なスライス(要素の取得)においてよく使います。配列のスライスについて知っておきたいテクニックについては『NumPyの配列のスライスの必須テクニックまとめ』で解説していますので、ぜひご確認ください。
それでは、以下の配列を使って見ていきましょう。
import numpy as np
a = np.arange(1, 10).reshape(3, 3)
a
この配列の中で値が3より大きい要素は、どこに存在するでしょうか。これは以下のコードで確認することができます。
a > 3
この時、numpy.nonzero()を使うとTrue の場所をインダイスで取得することができます。
# 条件式がTrue の要素のインダイスを取得
np.nonzero(a > 3)
もちろんメソッドでも同様です。
# メソッドとしての書き方も可能
(a > 3).nonzero()
これを使って、以下のように目的の値をスライスすることが可能です。
a[np.nonzero(a > 3)]
ただし、このような単純な場合は、以下のようにスライスする方が効率的です。繰り返しになりますが、より複雑なスライスについては『NumPyの配列のスライスの必須テクニックまとめ』をご確認ください。
a[a > 3]
3. まとめ
以上がnumpy.nonzero()の使い方です。
繰り返しになりますが、この関数で取得するインダイスの配列は、配列の高度なスライスにおいて活用することができます。詳しくは『NumPyの配列のスライスの必須テクニックまとめ』を確認しておくと良いでしょう。
コメント