NumPy配列ndarrayを要素ごとに比較(比較演算子、np.allcloseなど)
2つのNumPy配列ndarray
を要素ごとに比較するには、>
や==
などの比較演算子を使う。真偽値bool
型(True
, False
)を要素とするndarray
が返される。ndarray
同士だけでなくndarray
とスカラー値との比較も可能。
また、すべての要素が等しいか判定するnp.array_equal()
, np.array_equiv()
、それぞれの要素またはすべての要素が近いか判定するnp.isclose()
, np.allclose()
といった関数も提供されている。
- numpy.array_equal — NumPy v1.17 Manual
- numpy.array_equiv — NumPy v1.17 Manual
- numpy.isclose — NumPy v1.17 Manual
- numpy.allclose — NumPy v1.17 Manual
ここでは、以下の内容について説明する。
- 比較演算子による配列
ndarray
の比較- ブール値の配列
ndarray
が返される np.count_nonzero()
,np.all()
,np.any()
と組み合わせ- 欠損値
NaN
との比較:np.isnan()
- 複数条件や複数配列の場合:
&
,|
- ブール値の配列
- すべての要素が等しいか判定:
np.array_equal()
,np.array_equiv()
- それぞれの要素が近いか判定:
np.isclose()
- すべての要素が近いか判定:
np.allclose()
比較演算子による配列ndarrayの比較
ブール値の配列ndarrayが返される
以下の2つの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]]
b = np.arange(12).reshape(4, 3).T
print(b)
# [[ 0 3 6 9]
# [ 1 4 7 10]
# [ 2 5 8 11]]
比較演算子でそのまま比較すると、真偽値bool
型(True
, False
)を要素とするndarray
が返される。
a_compare = a < b
print(a_compare)
# [[False True True True]
# [False False True True]
# [False False False False]]
print(type(a_compare))
# <class 'numpy.ndarray'>
print(a_compare.dtype)
# bool
そのほかの比較演算子でも同様。
print(a > b)
# [[False False False False]
# [ True True False False]
# [ True True True False]]
print(a <= b)
# [[ True True True True]
# [False False True True]
# [False False False True]]
print(a >= b)
# [[ True False False False]
# [ True True False False]
# [ True True True True]]
print(a == b)
# [[ True False False False]
# [False False False False]
# [False False False True]]
print(a != b)
# [[False True True True]
# [ True True True True]
# [ True True True False]]
値としての比較なので、データ型dtype
が異なっていても問題ない。
b_float = b.astype(float)
print(b_float)
# [[ 0. 3. 6. 9.]
# [ 1. 4. 7. 10.]
# [ 2. 5. 8. 11.]]
print(b_float.dtype)
# float64
print(a == b_float)
# [[ True False False False]
# [False False False False]
# [False False False True]]
なお、浮動小数点数float
を==
で比較する場合は誤差に注意。ある程度の差を許容して比較するには後述のnp.isclose()
を使う。
次元数が異なっていても可能であればブロードキャストされる。
- 関連記事: NumPyのブロードキャスト(形状の自動変換)
b_1d = np.arange(4, 8)
print(b_1d)
# [4 5 6 7]
print(a < b_1d)
# [[ True True True True]
# [False False False False]
# [False False False False]]
スカラー値と比較すると、その値とすべての要素がそれぞれ比較される。
print(a < 6)
# [[ True True True True]
# [ True True False False]
# [False False False False]]
演算結果と比較することも可能。例えば整数の要素が偶数かどうかを判定する例は以下のように書ける。
print(a % 2)
# [[0 1 0 1]
# [0 1 0 1]
# [0 1 0 1]]
print(a % 2 == 0)
# [[ True False True False]
# [ True False True False]
# [ True False True False]]
np.count_nonzero(), np.all(), np.any()と組み合わせ
bool
型の配列ndarray
のTrue
の数はnp.count_nonzero()
でカウントできる。
print(np.count_nonzero(a < 6))
# 6
すべてTrue
か、または、少なくとも一つはTrue
を含むかといった判定にはnp.all()
, np.any()
を使う。いずれも引数axis
を使うことで行ごとや列ごとに処理できる。
print(np.all(a < 6))
# False
print(np.all(a < 6, axis=1))
# [ True False False]
print(np.any(a < 6))
# True
print(np.any(a < 6, axis=1))
# [ True True False]
比較演算子とnp.count_nonzero()
, np.all()
, np.any()
との組み合わせについての詳細は以下の記事を参照。
欠損値NaNとの比較: np.isnan()
データが欠落したCSVファイルを読み込んだ場合などに欠損値NaN
が発生する。
欠損値NaN
同士を比較してもFalse
が返されるので、欠損値NaN
の存在確認などにはnp.isnan()
を使う必要がある。
a_nan = np.array([0, 1, np.nan])
print(a_nan)
# [ 0. 1. nan]
print(a_nan == np.nan)
# [False False False]
print(np.isnan(a_nan))
# [False False True]
大小比較の場合もNaN
との比較はFalse
となるので注意。
print(a_nan > 0)
# [False True False]
#
# /usr/local/lib/python3.7/site-packages/ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in greater
# """Entry point for launching an IPython kernel.
なお、要素数1個(NaN
だけ)の場合やNaN
単体を比較した場合は警告は発生しないが、要素数2個以上の配列にNaN
が含まれていると上の例のように警告が発生する(多数の要素の中にNaN
が紛れているのを知らせるため?)。
a_nan_only = np.array([np.nan])
print(a_nan_only)
# [nan]
print(a_nan_only > 0)
# [False]
print(np.nan > 0)
# False
NaN
とNaN
が同じ位置にあるときにTrue
としたい場合は後述のnp.isclose()
を使う。
複数条件や複数配列の場合: &, |
Pythonでは以下のように条件式をつなげて書ける。
x = 6
print(4 < x < 8)
# True
ndarray
にはこのような書き方はできない。複数条件を指定したい場合はそれぞれの条件式を別々に書き、&
(かつ)や|
(または)を使う。
# print(4 < a < 8)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
print((a > 4) & (a < 8))
# [[False False False False]
# [False True True True]
# [False False False False]]
and
やor
を使ったり、括弧を省略するとエラーになるので注意。
# print((a > 4) and (a < 8))
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
# print(a > 4 & a < 8)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
このエラーについての詳細は以下の記事を参照。
3つ以上のndarray
を比較する際も同様。Pythonの文法上はまとめて比較可能。
x = 6
y = 6
z = 6
print(x == y == z)
# True
これもndarray
ではダメ。それぞれの条件式と&
や|
をつかう。
c = np.zeros((3, 4), int)
print(c)
# [[0 0 0 0]
# [0 0 0 0]
# [0 0 0 0]]
# print(a == b == c)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
print((a == b) & (b == c))
# [[ True False False False]
# [False False False False]
# [False False False False]]
すべての要素が等しいか判定: np.array_equal(), np.array_equiv()
2つのndarray
のすべての要素が等しいかどうかは、上述のように==
とnp.all()
を使って判定できる。
a = np.arange(3)
print(a)
# [0 1 2]
b = np.arange(3)
print(b)
# [0 1 2]
c = np.arange(1, 4)
print(c)
# [1 2 3]
print(np.all(a == b))
# True
print(np.all(a == c))
# False
np.array_equal()
, np.array_equiv()
という関数を使う方法もある。
print(np.array_equal(a, b))
# True
print(np.array_equal(a, c))
# False
print(np.array_equiv(a, b))
# True
print(np.array_equiv(a, c))
# False
==
と同じく値としての比較なので、データ型dtype
が異なっていても問題ない。
b_f = np.arange(3, dtype=float)
print(b_f)
# [0. 1. 2.]
print(np.array_equal(a, b_f))
# True
print(np.array_equiv(a, b_f))
# True
np.array_equal()
は形状shape
が不一致だとFalse
を返すのに対し、np.array_equiv()
はスカラー値との比較やブロードキャストを伴う比較が可能。
ones = np.ones(3)
print(ones)
# [1. 1. 1.]
print(np.array_equal(ones, 1))
# False
print(np.array_equiv(ones, 1))
# True
a_2d = np.array([[0, 1, 2], [0, 1, 2], [0, 1, 2]])
print(a_2d)
# [[0 1 2]
# [0 1 2]
# [0 1 2]]
print(np.array_equal(a_2d, b))
# False
print(np.array_equiv(a_2d, b))
# True
欠損値NaN
同士の比較はFalse
となるので、NaN
が含まれていると同じ位置にあってもFalse
となる。
a_nan = np.array([np.nan, 1, 2])
print(a_nan)
# [nan 1. 2.]
b_nan = np.array([np.nan, 1, 2])
print(b_nan)
# [nan 1. 2.]
print(np.array_equal(a_nan, b_nan))
# False
print(np.array_equiv(a_nan, b_nan))
# False
print(np.all(a_nan == b_nan))
# False
同じ位置にNaN
があるときはすべての要素が等しいと判定したい場合は、NaN
を他の値に置換するか、最後に説明するnp.allclose()
を使う。
それぞれの要素が近いか判定: np.isclose()
浮動小数点数float
はコンピュータの内部では2進数で表現されているため、10進数の小数と厳密に同じ値を表現できない。
例えば0.1 + 0.1 + 0.1
は0.3
と等しくない。
print(0.1 + 0.1 + 0.1)
# 0.30000000000000004
a = np.array([0.3, 0.1 + 0.1 + 0.1])
print(a)
# [0.3 0.3]
b = np.array([0.3, 0.3])
print(b)
# [0.3 0.3]
print(a == b)
# [ True False]
なお、上の例ではprint()
の出力がすべて0.3
と表示されているが、これはデフォルトが小数点以下8桁までの表示であるため。np.set_printoptions()
で設定を変更できる。
np.set_printoptions(precision=18)
print(a)
# [0.3 0.30000000000000004]
np.isclose()
を使うと、ある程度の誤差を許容してそれぞれの要素の値が近いかを判定できる。スカラー値との比較や、ここでは例を省略するがブロードキャストを伴う比較も可能。
print(np.isclose(a, b))
# [ True True]
print(np.isclose(a, 0.3))
# [ True True]
スカラー値同士の比較はndarray
ではなくスカラー値を返す。
print(np.isclose(0.1 + 0.1 + 0.1, 0.3))
# True
np.isclose()
は引数rtol
, atol
を指定可能(デフォルトはrtol=1e-05
, atol=1e-08
)。その2つの値を用いて以下の計算式で判定される。absoluteは絶対値。
absolute(a - b) <= (atol + rtol * absolute(b)) numpy.isclose — NumPy v1.17 Manual
標準ライブラリのmathモジュールにもmath.isclose()
という関数があるが、判定の計算式が異なるので注意。
例えば、単純に差分の絶対値が1
以内のときにTrue
としたい場合は以下のように設定する。
print(np.isclose(100, 101))
# False
print(np.isclose(100, 101, rtol=0, atol=1))
# True
また、np.isclose()
では引数equal_nan
を指定可能。equal_nan=True
とすると、欠損値NaN
同士の比較がTrue
となる。
print(np.isclose(np.nan, np.nan))
# False
print(np.isclose(np.nan, np.nan, equal_nan=True))
# True
True
となるのはあくまでもNaN
同士で、他の値とNaN
の比較はequal_nan=True
でもFalse
。
print(np.isclose(np.nan, 100, equal_nan=True))
# False
NaN
を含むndarray
の例。
a_nan = np.array([np.nan, 1, 2])
print(a_nan)
# [nan 1. 2.]
b_nan = np.array([np.nan, np.nan, 2])
print(b_nan)
# [nan nan 2.]
print(np.isclose(a_nan, b_nan))
# [False False True]
print(np.isclose(a_nan, b_nan, equal_nan=True))
# [ True False True]
すべての要素が近いか判定: np.allclose()
np.allclose()
は2つのndarray
のすべての要素が近いかを判定する。
a = np.array([0.3, 0.1 + 0.1 + 0.1])
print(a)
# [0.3 0.3]
b = np.array([0.3, 0.3])
print(b)
# [0.3 0.3]
c = np.array([0.2, 0.3])
print(c)
# [0.2 0.3]
print(np.allclose(a, b))
# True
print(np.allclose(a, c))
# False
引数はnp.isclose()
と同じで、判定のための計算式も同じ。内部ではnp.isclose()
の結果をnp.all()
で判定しているだけ。
引数rtol
, atol
を指定する例。
a_100 = np.array([99, 100, 101])
print(a_100)
# [ 99 100 101]
print(np.allclose(a_100, 100))
# False
print(np.allclose(a_100, 100, rtol=0, atol=1))
# True
上の例のようなスカラー値との比較や、ここでは例を省略するがブロードキャストを伴う比較も可能。
引数equal_nan
を指定する例。
a_nan = np.array([np.nan, 1, 2])
print(a_nan)
# [nan 1. 2.]
b_nan = np.array([np.nan, 1, 2])
print(b_nan)
# [nan 1. 2.]
print(np.allclose(a_nan, b_nan))
# False
print(np.allclose(a_nan, b_nan, equal_nan=True))
# True