Skip to content

NumPy, pandas : Comment corriger ValueError : La valeur de vérité … est ambiguë

Dans NumPy et pandas, l’utilisation de numpy.ndarray ou pandas.DataFrame dans des expressions conditionnelles ou et, ou des opérations peut générer une erreur.

ValueError: The truth value of an array with more than one element is ambiguous. 
ValueError: The truth value of a Series is ambiguous.

Cet article décrit les causes de cette erreur et comment la corriger.

  • Cause première
  • Utiliser tout(), tout(), taille
  • Utilisez &, |, ~ au lieu de and, or, not
    • Utilisez &, |, ~ pour les opérations booléennes/au niveau des éléments
    • Les parenthèses sont requises pour plusieurs expressions conditionnelles
  • Pour 1 ou 0 éléments
  • Pour pandas.DataFrame, pandas.Series

Dans la plupart des cas, notez les deux points suivants.

  1. Utilisez &, |, ~ au lieu de and, or, not.
    • et, ou, ne pas vérifier si l’objet lui-même est vrai ou faux.
    • &, |, ~ effectuent des opérations booléennes/au niveau des éléments.
  2. Lorsque vous combinez plusieurs expressions, placez chaque expression entre parenthèses ().
    • &, | ont une priorité plus élevée que les opérateurs de comparaison (tels que <).

Le concept est le même pour numpy.ndarray, pandas.DataFrame et pandas.Series.

Dans l’exemple de code suivant, NumPy est la version 1.17.3 et pandas est la version 0.25.1. Notez que différentes versions peuvent se comporter différemment.

ValueError : la valeur de vérité d’un tableau avec plus d’un élément est ambiguë.

L’utilisation de numpy.ndarray de bool dans des expressions conditionnelles or and, or, not operations génère une erreur.

import numpy as np

print(np.__version__)
# 1.17.3

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()

Les cas de pandas.DataFrame et pandas.Series sont décrits ci-dessous.

Cause première

En Python, les objets et les expressions sont évalués comme des valeurs booléennes (True, False) dans les expressions conditionnelles and and, or, not operations.

Par exemple, si une liste est vide (le nombre d’éléments est 0), elle est évaluée comme False, sinon comme True.

print(bool([0, 1, 2]))
# True

print(bool([]))
# False

print(not [0, 1, 2])
# False

print(not [])
# True

L’évaluation de numpy.ndarray en tant que valeur booléenne génère une erreur.

# bool(a_bool)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Comme le mot « ambigu » l’indique, c’est ambigu ce que vous voulez vérifier Vrai ou Faux, l’objet lui-même ou chaque élément.

Utiliser tout(), tout(), taille

Si vous souhaitez vérifier True ou False pour l’objet lui-même, utilisez all() ou any() comme indiqué dans le message d’erreur.

all() renvoie True si tous les éléments sont True, any() renvoie True si au moins un élément est 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

De plus, vous pouvez obtenir le nombre total d’éléments avec l’attribut size et vérifier si numpy.ndarray est vide ou non.

print(a_bool.size)
# 3

print(a_bool.size == 0)
# False

Utilisez &, |, ~ au lieu de and, or, not

Utilisez &, |, ~ pour les opérations booléennes/au niveau des éléments

Si vous souhaitez effectuer des opérations AND, OR, NOT au niveau des éléments, utilisez &, |, ~ au lieu de and, or, not. ^ (XOR) est également disponible.

Pour numpy.ndarray de bool, les opérateurs &, |, ~ et ^ effectuent par élément AND, OR, NOT et 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]

Notez que &, | et ~ sont utilisés pour les opérations au niveau du bit sur les valeurs entières en Python.

Pour numpy.ndarray d’entier int, ils effectuent des opérations binaires élément par élément.

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]

et, ou, non et &, |, ~ sont facilement confondus.

et, ou, ne pas vérifier si l’objet lui-même est vrai ou faux. D’autre part, & et | sont utilisés pour les opérations au niveau du bit pour les valeurs entières et les opérations au niveau des éléments pour numpy.ndarray comme décrit ci-dessus, et les opérations de définition pour set.

Rappelez-vous que les mots anglais and et or sont souvent utilisés sous la forme if A et B:, et les symboles & et | sont utilisés dans d’autres opérations mathématiques.

Les parenthèses sont requises pour plusieurs expressions conditionnelles

Une opération de comparaison sur numpy.ndarray renvoie un numpy.ndarray de bool.

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]]

Comme mentionné ci-dessus, pour calculer AND ou OR pour chaque élément de ces numpy.ndarray, utilisez & ou | au lieu de et ou ou. Lorsque vous combinez plusieurs conditions avec & ou |, il est nécessaire de placer chaque expression conditionnelle entre parenthèses ().

# 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()

C’est parce que & et | ont une priorité plus élevée que les opérateurs de comparaison (tels que <).

L’exemple ci-dessus fonctionnerait comme suit.

# 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()

Chaque expression conditionnelle doit être placée entre parenthèses ().

print((a > 3) & (a % 2 == 0))
# [[False False False False]
#  [ True False  True False]
#  [ True False  True False]]

Notez que les opérations de comparaison sur de nombreux objets autres que numpy.ndarray renvoient True ou False.

x = 10

print(x > 3)
# True

print(x % 2 == 1)
# False

et et ou sont utilisés pour les opérations booléennes de Vrai et Faux. Étant donné que and et or ont une priorité inférieure aux opérateurs de comparaison (tels que <), il n’y a pas d’erreur sans parenthèses dans ce cas. Bien sûr, les parenthèses sont également acceptables.

print(x > 3 or x % 2 == 1)
# True

print((x > 3) or (x % 2 == 1))
# True

Pour 1 ou 0 éléments

Si le nombre d’éléments est un ou zéro, comme indiqué par le message d’erreur « plus d’un élément », aucune erreur n’est générée.

ValueError : la valeur de vérité d’un tableau avec plus d’un élément est ambiguë.

Si le nombre d’éléments est un, la valeur de l’élément est évaluée comme une valeur booléenne. Par exemple, si l’élément est un entier int, il vaut False s’il vaut 0 et True sinon.

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

et et ou renvoient des objets de gauche ou de droite au lieu de True ou 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]

& et | renvoie ET et OU élément par élément.

print(b_single & c_single)
# [0]

print(b_single | c_single)
# [3]

not renvoie NOT élément par élément. ~ renvoie élément par élément ~ (pour les entiers signés, ~x renvoie -(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]

Si le nombre d’éléments est nul, un avertissement (DeprecationWarning) est émis.

a_empty = np.array([])
print(a_empty)
# []

print(bool(a_empty))
# False
# 
# /usr/local/lib/python3.7/site-packages/ipykernel_launcher.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.
#   """Entry point for launching an IPython kernel.

Il indique qu’il générera une erreur à l’avenir (l’exemple ci-dessus est la version 1.17.3), il est donc préférable d’utiliser la taille comme l’indique le message.

Pour pandas.DataFrame, pandas.Series

Pour pandas.DataFrame, comme avec numpy.ndarray, utilisez & ou | pour les opérations élément par élément, et placez les multiples conditions entre parenthèses ().

import pandas as pd

df = pd.DataFrame(pd.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

Des erreurs sont générées si vous utilisez et/ou omettez des parenthèses ().

# 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().

Les opérations au niveau du bit avec des valeurs scalaires sont également possibles.

print(df & 7)
#    a  b  c  d
# x  0  1  2  3
# y  4  5  6  7
# z  0  1  2  3

print(df | 1)
#    a  b   c   d
# x  1  1   3   3
# y  5  5   7   7
# z  9  9  11  11

Le décalage de bits <<, >> ne peut pas être utilisé.

# print(df << 1)
# TypeError: unsupported operand type(s) for <<: 'DataFrame' and 'int'

# print(df << df)
# TypeError: unsupported operand type(s) for <<: 'DataFrame' and 'DataFrame'

Les méthodes all() et any() sont également fournies, mais notez que la valeur par défaut est axis=0 contrairement à numpy.ndarray. Si vous souhaitez couvrir des éléments entiers, utilisez 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=1))
# x    False
# y     True
# z     True
# dtype: bool

print((df > 3).all(axis=None))
# False

Les attributs vide et taille sont également fournis.

print(df.empty)
# False

df_empty = pd.DataFrame()
print(df_empty.empty)
# True

print(df.size)
# 12

print(df_empty.size)
# 0

Il en va de même pour pandas.Series.

pandas.Series of bool est utilisé pour sélectionner des lignes en fonction des conditions. Comme numpy.ndarray et pandas.DataFrame, vous devez utiliser &, |, ~ et parenthèses ().

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