NumPy, pandasのValueError: The truth value ... is ambiguousの対処法
NumPyやpandasで、numpy.ndarray
やpandas.DataFrame
をif文の条件式で使ったりand
やor
で演算したりすると、以下のようなエラーが出ることがある。
ValueError: The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all()
ValueError: The truth value of a Series is ambiguous.
Use a.empty, a.bool(), a.item(), a.any() or a.all().
このエラーの原因と対処法について説明する。
処理内容にもよるが、多くの場合、以下の2点に気を付ければよい。numpy.ndarray
でもpandas.DataFrame
, pandas.Series
でも考え方は同じ。
and
,or
,not
ではなく&
,|
,~
を使うand
,or
,not
はオブジェクト自体の真偽を判定するからndarray
やDataFrame
の要素ごとの演算は&
,|
,~
- 複数の条件式を組み合わせるときは、それぞれの条件式を括弧
()
で囲む&
,|
は比較演算子(<
など)より優先順位が高いから
本記事のサンプルコードのNumPyのバージョンは1.25.1
、pandasのバージョンは2.0.3
。バージョンが異なると挙動が異なる可能性があるので注意。
import numpy as np
print(np.__version__)
# 1.25.1
import pandas as pd
print(pd.__version__)
# 2.0.3
ValueError: The truth value ... is ambiguousの例
以下のように、bool
値を要素とするnumpy.ndarray
をif文の条件式で使ったり、and
, or
, not
で演算したりするとエラーが発生する。
a_bool = np.array([True, True, True])
b_bool = np.array([True, False, False])
# if a_bool:
# pass
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
# a_bool and b_bool
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
# a_bool or b_bool
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
# not b_bool
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
後述のように、pandas.DataFrame
, pandas.Series
でも同様にエラーが発生する。
ValueError: The truth value ... is ambiguousの原因
Pythonにおいて、if文の条件式やand
, or
, not
の演算などでは、オブジェクトや式がbool
値(True
, False
)として評価される。
例えばリストの場合、空(要素数が0)だとFalse
、それ以外はTrue
として処理される。
print(bool([0, 1, 2]))
# True
print(bool([]))
# False
print(not [0, 1, 2])
# False
print(not [])
# True
numpy.ndarray
に対してbool
値を評価しようとするとエラーとなる。
a_bool = np.array([True, True, True])
# bool(a_bool)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
ambiguous(曖昧)という文言の通り、何に対してTrue
, False
を判定したいのか(オブジェクト自体なのか、各要素なのか)が曖昧だというエラー。以降で説明するように、all()
などを使って明確にする必要がある。
なお、エラーメッセージにあるように、要素数が1個以下の場合はエラーにならない。後述。
対処法1: all(), any(), sizeを使う
オブジェクトそのものに対してTrue
,False
を判定したい場合、エラーメッセージにあるようにall()
, any()
を使う。
all()
はすべての要素がTrue
だとTrue
、any()
は少なくとも1つの要素がTrue
だとTrue
を返す。
a_bool = np.array([True, True, True])
b_bool = np.array([True, False, False])
print(a_bool.all())
# True
print(a_bool.any())
# True
print(b_bool.all())
# False
print(b_bool.any())
# True
そのほか、size
属性で全要素数を取得できる。numpy.ndarray
が空かどうかなどを判定することが可能。
print(a_bool.size)
# 3
print(a_bool.size == 0)
# False
対処法2: and, or, notではなく&, |, ~
要素ごとのブール演算・ビット演算は&, |, ~
要素ごとのAND, OR, NOTなどの演算を意図している場合、and
, or
, not
ではなく&
, |
, ~
を使う。XOR^
もある。
データ型dtype
がbool
のnumpy.ndarray
に対しては、&
, |
, ~
, ^
演算子は要素ごとのAND(論理積)、OR(論理和)、NOT(否定)、XOR(排他的論理和)になる。
a_bool = np.array([True, True, True])
b_bool = np.array([True, False, False])
print(a_bool & b_bool)
# [ True False False]
print(a_bool | b_bool)
# [ True True True]
print(~b_bool)
# [False True True]
print(a_bool ^ b_bool)
# [False True True]
なお、Pythonにおいて、&
, |
, ~
は整数値に対するビット単位の演算。
データ型dtype
が整数int
のnumpy.ndarray
に対しては要素ごとのビット演算(二進数で表した各ビットに対する論理演算)となる。
a_int = np.array([0, 1, 3]) # [0b00 0b01 0b11]
b_int = np.array([1, 0, 2]) # [0b01 0b00 0b10]
print(a_int & b_int)
# [0 0 2]
print(a_int | b_int)
# [1 1 3]
print(a_int ^ b_int)
# [1 1 1]
print(~a_int)
# [-1 -2 -4]
and
, or
, not
と&
, |
, ~
は混同しがちだが、基本的には、Pythonにおいてand
, or
, not
はオブジェクトそのものの真偽を判定して処理する。
一方、&
や|
は、上述の整数値に対するビット単位の処理やnumpy.ndarray
の要素ごとの処理のほか、set
型の集合演算にも使われる。
if A and B:
のような形で使うことが多いのが英単語のand
やor
で、それ以外の処理で使われるのが記号の&
や|
とでも覚えておけばよいだろう。
複数の条件式では括弧が必要
numpy.ndarray
に対して比較演算などを行うと、各要素がbool
値のnumpy.ndarray
が返される。
a = np.arange(12).reshape(3, 4)
print(a)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print(a > 3)
# [[False False False False]
# [ True True True True]
# [ True True True True]]
print(a % 2 == 0)
# [[ True False True False]
# [ True False True False]
# [ True False True False]]
上述のように、これらのnumpy.ndarray
の要素ごとのANDやORを算出するにはand
やor
ではなく&
や|
を使うが、複数の条件式を&
や|
で組み合わせる場合、各条件式を括弧()
で囲まないと意図した結果とならない。
# print(a > 3 & a % 2 == 0)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
これは、&
や|
は比較演算子(<
など)より優先順位が高いため。
括弧()
なしだと以下のように解釈されてしまう。
# print(a > (3 & (a % 2)) == 0)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
各条件式を括弧()
で囲めばよい。
print((a > 3) & (a % 2 == 0))
# [[False False False False]
# [ True False True False]
# [ True False True False]]
なお、numpy.ndarray
ではないオブジェクトに対する比較演算では、多くの場合、True
, False
そのものを返す。
x = 10
print(x > 3)
# True
print(x % 2 == 1)
# False
True
, False
のブール演算(論理演算)にはand
やor
を使う。and
やor
は比較演算子(<
など)より優先順位が低いため、このときは括弧がなくてもエラーにならない。もちろん括弧があっても良い。
print(x > 3 or x % 2 == 1)
# True
print((x > 3) or (x % 2 == 1))
# True
要素数1個以下の場合
エラーメッセージにmore than one element
とあるように、要素数が1個以下の場合はエラーにならない。
ValueError: The truth value of an array with more than one element is ambiguous.
要素数が1個の場合、その要素の値に対してbool
値が評価される。例えば数値の場合、0
はFalse
でそれ以外はTrue
。
a_single = np.array([0])
b_single = np.array([1])
c_single = np.array([2])
print(bool(a_single))
# False
print(bool(b_single))
# True
print(bool(c_single))
# True
and
, or
ではPythonの通常の文法に則って、左右いずれかのオブジェクトが返される。True
, False
が返されるわけではないので注意。詳細は以下の記事を参照。
print(b_single and c_single)
# [2]
print(c_single and b_single)
# [1]
print(b_single or c_single)
# [1]
print(c_single or b_single)
# [2]
&
や|
では要素ごとのビット演算が行われる。
print(b_single & c_single)
# [0]
print(b_single | c_single)
# [3]
not
ではbool
値の否定が返され、~
では各要素に対して~
の処理(符号付き整数の場合、~x
は-(x + 1)
)が行われる。
print(not a_single)
# True
print(not b_single)
# False
print(not c_single)
# False
print(~a_single)
# [-1]
print(~b_single)
# [-2]
print(~c_single)
# [-3]
要素数0個の場合、エラーにはならないが警告(DeprecationWarning
)が発生する。
a_empty = np.array([])
print(a_empty)
# []
print(bool(a_empty))
# False
#
# /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_40648/256863747.py:1: DeprecationWarning: The truth value of an empty array is ambiguous. Returning False, but in future this will result in an error. Use `array.size > 0` to check that an array is not empty.
# print(bool(a_empty))
将来的にはエラーになると書いてある(上の例はバージョン1.25.1
)ので、メッセージにあるようにsize
属性を使って判定したほうがよいだろう。
pandas.DataFrameの場合
pandas.DataFrame
も考え方はnumpy.ndarray
と同様。要素ごとに処理する場合は&
や|
を使い、複数条件の場合はそれぞれを括弧()
で囲む。
df = pd.DataFrame(np.arange(12).reshape(3, 4), columns=['a', 'b', 'c', 'd'], index=['x', 'y', 'z'])
print(df)
# a b c d
# x 0 1 2 3
# y 4 5 6 7
# z 8 9 10 11
print((df > 3) & (df % 2 == 0))
# a b c d
# x False False False False
# y True False True False
# z True False True False
&
や|
ではなくand
, or
を使ったり、括弧()
を省略したりするとエラー。
# print((df > 3) and (df % 2 == 0))
# ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
# print(df > 3 & df % 2 == 0)
# ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
pandas.DataFrame
のall()
, any()
メソッドはnumpy.ndarray
と異なりデフォルトがaxis=0
(列ごと)なので注意。全体を対象とする場合はaxis=None
とする。
print(df > 3)
# a b c d
# x False False False False
# y True True True True
# z True True True True
print((df > 3).all())
# a False
# b False
# c False
# d False
# dtype: bool
print((df > 3).all(axis=None))
# False
空かどうかを判定するempty
属性や、全要素数を返すsize
属性もある。
print(df)
# a b c d
# x 0 1 2 3
# y 4 5 6 7
# z 8 9 10 11
print(df.empty)
# False
print(df.size)
# 12
df_empty = pd.DataFrame()
print(df_empty)
# Empty DataFrame
# Columns: []
# Index: []
print(df_empty.empty)
# True
print(df_empty.size)
# 0
pandas.Seriesの場合
pandas.Series
もnumpy.ndarray
やpandas.DataFrame
と同様、要素ごとに処理する場合は&
や|
, ~
を使い、複数条件の場合はそれぞれを括弧()
で囲む。
条件を満たす行を抽出する際などに気を付ける必要がある。
df = pd.read_csv('data/src/sample_pandas_normal.csv')
print(df)
# name age state point
# 0 Alice 24 NY 64
# 1 Bob 42 CA 92
# 2 Charlie 18 CA 70
# 3 Dave 68 TX 70
# 4 Ellen 24 CA 88
# 5 Frank 30 NY 57
print(df['age'] < 35)
# 0 True
# 1 False
# 2 True
# 3 False
# 4 True
# 5 True
# Name: age, dtype: bool
print(~(df['state'] == 'NY'))
# 0 False
# 1 True
# 2 True
# 3 True
# 4 True
# 5 False
# Name: state, dtype: bool
print((df['age'] < 35) & ~(df['state'] == 'NY'))
# 0 False
# 1 False
# 2 True
# 3 False
# 4 True
# 5 False
# dtype: bool
df_and = df[(df['age'] < 35) & ~(df['state'] == 'NY')]
print(df_and)
# name age state point
# 2 Charlie 18 CA 70
# 4 Ellen 24 CA 88