NumPy配列ndarrayから条件を満たす要素・行・列を抽出、削除 | note.nkmk.me (original) (raw)

NumPy配列ndarrayから条件を満たす要素・行・列を抽出(取得)または削除する方法をサンプルコードとともに説明する。

ここでは、

について説明する。

データが欠落しているcsvファイルを読み込んだ場合など、ndarraynanが含まれている場合は以下の記事を参照。

条件を満たす要素を置換したりカウントしたりしたい場合は以下の記事を参照。

また、条件ではなくスライスやリストで行・列を抽出したい場合は以下の記事を参照。

条件を満たす要素を抽出

条件を満たす要素を抽出したい場合は、ndarray[条件式]とすればよい。

元のndarrayが多次元配列の場合でも、返されるのは平坦化された一次元配列。

`import numpy as np

a = np.arange(12).reshape((3, 4)) print(a)

[[ 0 1 2 3]

[ 4 5 6 7]

[ 8 9 10 11]]

print(a < 5)

[[ True True True True]

[ True False False False]

[False False False False]]

print(a[a < 5])

[0 1 2 3 4]

print(a < 10)

[[ True True True True]

[ True True True True]

[ True True False False]]

print(a[a < 10])

[0 1 2 3 4 5 6 7 8 9]

`

新たな配列ndarrayを返し、元のndarrayは変更されない。以降の例も同じ。

`b = a[a < 10] print(b)

[0 1 2 3 4 5 6 7 8 9]

print(a)

[[ 0 1 2 3]

[ 4 5 6 7]

[ 8 9 10 11]]

`

条件を満たす要素の合計sum()や平均mean()、最大値max()、最小値min()、標準偏差std()なども算出できる。

`print(a[a < 5].sum())

10

print(a[a < 5].mean())

2.0

print(a[a < 5].max())

4

print(a[a < 10].min())

0

print(a[a < 10].std())

2.8722813232690143

`

条件を満たす行・列を抽出

要素を抽出する例では一次元配列が返されたが、np.all(), np.any()を使うと元のndarrayの次元を保ったまま行・列を抽出できる。

以下の二通りについて説明する。

numpy.all()ですべての要素が条件を満たす行・列を抽出

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

引数axisを渡すと、各軸(各次元)それぞれに対してすべての要素がTrueのときにTrueを返す。二次元配列の場合はaxis=0が列に対して、axis=1が行に対しての結果となる。

`print(a < 5)

[[ True True True True]

[ True False False False]

[False False False False]]

print(np.all(a < 5))

False

print(np.all(a < 5, axis=0))

[False False False False]

print(np.all(a < 5, axis=1))

[ True False False]

print(a < 10)

[[ True True True True]

[ True True True True]

[ True True False False]]

print(np.all(a < 10, axis=0))

[ True True False False]

print(np.all(a < 10, axis=1))

[ True True False]

`

それぞれの結果を行または列のインデックス参照[行, 列]に与えると所望の行・列が抽出される。[行, :]の場合、末尾の, :は省略できる。

`print(a[:, np.all(a < 10, axis=0)])

[[0 1]

[4 5]

[8 9]]

print(a[np.all(a < 10, axis=1), :])

[[0 1 2 3]

[4 5 6 7]]

print(a[np.all(a < 10, axis=1)])

[[0 1 2 3]

[4 5 6 7]]

`

条件を満たさない場合は空のndarrayが返る。

`print(a[:, np.all(a < 5, axis=0)])

[]

`

一行だけあるいは一列だけの場合も次元数は変わらない。

`print(a[np.all(a < 5, axis=1)])

[[0 1 2 3]]

print(a[np.all(a < 5, axis=1)].ndim)

2

print(a[np.all(a < 5, axis=1)].shape)

(1, 4)

`

numpy.any()で条件を満たす要素が一つでもある行・列を抽出

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

引数axisを渡すと、各軸(各次元)それぞれに対してTrueの要素が一つでもあるときにTrueを返す。二次元配列の場合はaxis=0が列に対して、axis=1が行に対しての結果となる。

`print(a < 5)

[[ True True True True]

[ True False False False]

[False False False False]]

print(np.any(a < 5))

True

print(np.any(a < 5, axis=0))

[ True True True True]

print(np.any(a < 5, axis=1))

[ True True False]

`

np.all()と同じ要領で条件に合致した行・列を抽出できる。

`print(a[:, np.any(a < 5, axis=0)])

[[ 0 1 2 3]

[ 4 5 6 7]

[ 8 9 10 11]]

print(a[np.any(a < 5, axis=1)])

[[0 1 2 3]

[4 5 6 7]]

`

条件を満たす要素・行・列を削除

条件に応じて要素・行・列を抽出(取得)するのではなく削除したい場合は、以下の二通りの方法がある。

否定演算子を利用

条件に否定演算子~をつけると条件を満たさない要素・行・列が抽出される。これは条件を満たす要素・行・列を削除するのと等価。

`print(a[~(a < 5)])

[ 5 6 7 8 9 10 11]

print(a[:, np.all(a < 10, axis=0)])

[[0 1]

[4 5]

[8 9]]

print(a[:, ~np.all(a < 10, axis=0)])

[[ 2 3]

[ 6 7]

[10 11]]

print(a[np.any(a < 5, axis=1)])

[[0 1 2 3]

[4 5 6 7]]

print(a[~np.any(a < 5, axis=1)])

[[ 8 9 10 11]]

`

numpy.delete()とnumpy.where()を利用

行・列はnp.delete()np.where()を利用して削除することもできる。

np.delete()は、対象となるndarrayと削除するインデックス(行番号、列番号など)、対象となる軸(次元)axisを引数で設定する。

二次元配列の場合はaxis=0が行の削除、axis=1が列の削除で、上述のnp.all(), np.any()と違うので注意。

`print(a)

[[ 0 1 2 3]

[ 4 5 6 7]

[ 8 9 10 11]]

print(np.delete(a, [0, 2], axis=0))

[[4 5 6 7]]

print(np.delete(a, [0, 2], axis=1))

[[ 1 3]

[ 5 7]

[ 9 11]]

`

np.delete()については以下の記事も参照。

np.where()は条件を満たす要素のインデックスを返す。

多次元配列の場合は、各次元(行、列)に対して条件を満たすインデックス(行番号、列番号)のリストのタプルとなる。

`print(a < 2)

[[ True True False False]

[False False False False]

[False False False False]]

print(np.where(a < 2))

(array([0, 0]), array([0, 1]))

print(np.where(a < 2)[0])

[0 0]

print(np.where(a < 2)[1])

[0 1]

`

np.where()については以下の記事も参照。

この二つの関数を組み合わせると、条件を満たす行・列を削除できる。

`print(np.delete(a, np.where(a < 2)[0], axis=0))

[[ 4 5 6 7]

[ 8 9 10 11]]

print(np.delete(a, np.where(a < 2)[1], axis=1))

[[ 2 3]

[ 6 7]

[10 11]]

print(a == 6)

[[False False False False]

[False False True False]

[False False False False]]

print(np.where(a == 6))

(array([1]), array([2]))

print(np.delete(a, np.where(a == 6)))

[ 0 3 4 5 6 7 8 9 10 11]

print(np.delete(a, np.where(a == 6)[0], axis=0))

[[ 0 1 2 3]

[ 8 9 10 11]]

print(np.delete(a, np.where(a == 6)[1], axis=1))

[[ 0 1 3]

[ 4 5 7]

[ 8 9 11]]

`

上の例の通り、条件を満たす要素が一つでもある行・列の削除(np.any()を使った場合と同じ)となる。

np.where()で取得したインデックスの個数をカウントするなどの処理を行えばすべての要素が条件を満たす行・列の削除(np.all()を使った場合と同じ)も可能だが、np.all()を使ったほうが簡単。

複数条件の場合

複数の条件を組み合わせたい場合は、それぞれの条件式を()で囲み&|でつなげればOK。

`print(a[(a < 10) & (a % 2 == 1)])

[1 3 5 7 9]

print(a[np.any((a == 2) | (a == 10), axis=1)])

[[ 0 1 2 3]

[ 8 9 10 11]]

print(a[:, ~np.any((a == 2) | (a == 10), axis=0)])

[[ 0 1 3]

[ 4 5 7]

[ 8 9 11]]

`