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