Skip to content

NumPy, pandas: Come risolvere ValueError: Il valore di verità … è ambiguo

Python

In NumPy e pandas, l’uso di numpy.ndarray o pandas.DataFrame nelle espressioni condizionali o nelle operazioni e, o può generare un errore.

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

In questo articolo vengono le cause di questo errore e come risolverlo.

  • Causa ultima
  • Usa all(), any(), size
  • Usa &, |, ~ invece di e, o, no
    • Utilizzare &, |, ~ per operazioni booleane/bit per bit a livello di elemento
    • Le parentesi sono obbligatorie per espressioni più condizionali
  • Per 1 o 0 elementi
  • Per panda.DataFrame, panda.Serie

Nella maggior parte dei casi, notare i due punti seguenti.

  1. Usa &, |, ~ invece di e, o, no.
    • e, o, non controllare se l’oggetto stesso è vero o falso.
    • &, |, ~ esegue operazioni booleane/bit per bit a livello di elemento.
  2. Quando si combinano più espressioni, racchiudere ciascuna espressione tra parentesi ().
    • &, | hanno una precedenza maggiore rispetto agli operatori di confronto (come <).

Il concetto è lo stesso per numpy.ndarray, pandas.DataFrame e pandas.Series.

Nel codice di esempio seguente, NumPy è la versione 1.17.3 e Pandas è la versione 0.25.1. Si noti che versioni diverse potrebbero comportarsi in modo diverso.

ValueError: il valore di verità di un array con più di un elemento è ambiguo.

L’uso di numpy.ndarray di bool nelle espressioni condizionali o nelle operazioni e, o, non generi un errore.

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

I casi di pandas.DataFrame e pandas.Series sono descritti di seguito.

Causa ultima

In Python, gli oggetti e le espressioni vengono valutati come valori bool (True, False) nelle espressioni condizionali e nelle operazioni and, or, not.

Ad esempio, se una lista è vuota (il numero di elementi è 0), viene valutata come False, altrimenti come True.

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

print(bool([]))
# False

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

print(not [])
# True

La valutazione di numpy.ndarray come valore bool genera un errore.

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

Come indica la parola “ambiguo”, è ambiguo ciò per cui vuoi controllare Vero o Falso, l’oggetto stesso o ogni elemento.

Usa all(), any(), size

Se vuoi controllare True o False per l’oggetto stesso, usa all() o any() come mostrato nel messaggio di errore.

all() restituisce True se tutti gli elementi sono True, any() restituisce True se almeno un elemento è 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

Inoltre, puoi ottenere il numero totale di elementi con l’attributo size e controllare se numpy.ndarray è vuoto o meno con esso.

print(a_bool.size)
# 3

print(a_bool.size == 0)
# False

Usa &, |, ~ invece di e, o, no

Utilizzare &, |, ~ per operazioni booleane/bit per bit a livello di elemento

Se vuoi eseguire operazioni AND, OR, NOT a livello di elemento, usa &, |, ~ invece di and, or, not. ^ (XOR) è anche disponibile.

Per numpy.ndarray di bool, gli operatori &, |, ~ e ^ eseguono AND, OR, NOT e XOR a livello di elemento.

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]

Nota che &, | e ~ sono usati per operazioni bit per bit su valori interi in Python.

Per numpy.ndarray di integer int, eseguire operazioni bit a bit a livello di elemento.

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]

e, o, non e &, |, ~ sono facilmente confusi.

e, o, non controllare se l’oggetto stesso è vero o falso. D’altra parte, & e | vengono utilizzati per operazioni bit a bit per valori interi e operazioni a livello di elemento per numpy.ndarray come sopra e operazioni di utilizzo per set.

Ricorda che le parole inglesi eeo sono spesso usate nella forma se A e B: ei simboli & e | sono usati in altre operazioni matematiche.

Le parentesi sono obbligatorie per espressioni più condizionali

Un’operazione di confronto su numpy.ndarray richiede un numpy.ndarray di 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]]

Come accennato in precedenza, per calcolare AND o OR per ogni elemento di questi numpy.ndarray, utilizzare & o | invece di eo o. Quando si combinano più condizioni con & o |, è necessario racchiudere ogni condizione tra parentesi ().

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

Questo perché & e | hanno una precedenza maggiore rispetto agli operatori di confronto (come <).

L’esempio precedente verrebbe operato come segue.

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

Ogni espressione deve essere racchiusa tra parentesi ().

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

Si noti che le operazioni di confronto su molti oggetti diversi da numpy.ndarray restituiscono True o False.

x = 10

print(x > 3)
# True

print(x % 2 == 1)
# False

eeo sono utilizzati per operazioni booleane di Vero e Falso. Poiché eeo hanno una precedenza rispetto inferiore agli operatori di confronto (come <), in questo caso non vi è alcun errore senza parentesi. Ovviamente sono accettabili anche le parentesi.

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

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

Per 1 o 0 elementi

Se il numero di elementi è uno o zero, come indicatore dal messaggio di errore “più di un elemento”, non viene generato alcun errore.

ValueError: il valore di verità di un array con più di un elemento è ambiguo.

Se il numero di elementi è uno, il valore dell’elemento viene valutato come valore bool. Ad esempio, se l’elemento è un intero int, è False se è 0 e True in caso contrario.

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

eeo restituiscono oggetti sul lato sinistro o destro invece di Vero o Falso.

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]

& e | restituiscono AND e OR a livello di elemento.

print(b_single & c_single)
# [0]

print(b_single | c_single)
# [3]

non risulta NON a livello di elemento. ~ l’elemento ~ (per gli interi con segno, ~x richiede -(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]

Se il numero di elementi è zero, viene emesso un avviso (DeprecationWarning).

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.

Dice che genererà un errore in futuro (l’esempio sopra è la versione 1.17.3), quindi è meglio usare la dimensione come dice il messaggio.

Per panda.DataFrame, panda.Serie

Per pandas.DataFrame, vieni con numpy.ndarray, usa & o | per le operazioni relative agli elementi e racchiudere le condizioni multiple tra parentesi ().

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

Vengono generati errori se si utilizzano e/o si omettono le parentesi ().

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

Sono possibili anche operazioni un po’ con valori scalari.

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

Bit shift <<, >> non può essere utilizzato.

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

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

Vengono forniti anche i metodi all() e any(), ma si noti che il valore predefinito è axis=0 a differenza di numpy.ndarray. Se vuoi coprire gli elementi, usa axis=Nessuno.

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

Vengono forniti anche gli attributi vuoti e dimensioni.

print(df.empty)
# False

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

print(df.size)
# 12

print(df_empty.size)
# 0

Lo stesso vale per pandas.Serie.

pandas.Series di bool viene utilizzato per selezionare le righe in base alle condizioni. Come numpy.ndarray e pandas.DataFrame, devi usare &, |, ~ e parentesi ().

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