ValueError: il valore di verità di un array con più di un elemento è ambiguo. Usa a.any () o a.all ()


222

Ho appena scoperto un errore logico nel mio codice che causava ogni tipo di problema. Inavvertitamente stavo facendo un AND bit per bit anziché un AND logico .

Ho cambiato il codice da:

r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]

PER:

r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) and (r["dt"] <= enddate))
selected = r[mask]

Con mia sorpresa, ho ricevuto il messaggio di errore piuttosto criptico:

ValueError: il valore di verità di un array con più di un elemento è ambiguo. Usa a.any () o a.all ()

Perché un errore simile non è stato emesso quando utilizzo un'operazione bit a bit - e come posso risolvere questo problema?


1
Pandas offre anche documentazione per questo
Greg

Risposte:


164

rè una matrice numpy (rec). Quindi r["dt"] >= startdateè anche un array (booleano). Per gli array numpy l' &operazione restituisce gli array elementwise e dei due array booleani.

Gli sviluppatori di NumPy hanno ritenuto che non esistesse un modo comune per valutare un array in un contesto booleano: potrebbe significare Truese qualsiasi elemento lo è True, oppure potrebbe significare Truese tutti gli elementi lo sono Trueo Truese l'array ha una lunghezza diversa da zero, solo per citarne tre possibilità.

Poiché utenti diversi potrebbero avere esigenze e ipotesi diverse, gli sviluppatori NumPy si sono rifiutati di indovinare e hanno invece deciso di aumentare un ValueError ogni volta che si tenta di valutare un array in un contesto booleano. L'applicazione anda due array intorpiditi fa sì che i due array vengano valutati in un contesto booleano (chiamando __bool__in Python3 o __nonzero__in Python2).

Il tuo codice originale

mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]

sembra corretto. Tuttavia, se lo desideri and, invece di a and butilizzare (a-b).any()o (a-b).all().


2
Hai ragione. Il codice originale era corretto. Il bug sembra trovarsi altrove nel codice.
Homunculus Reticulli

2
Spiegazione eccellente. Implica, tuttavia, che NumPy sia abbastanza inefficiente: valuta completamente entrambi gli array booleani, mentre un'implementazione efficiente valuterà cond1 (i) && cond2 (i) all'interno di un singolo loop e salterà cond2 a meno che cond1 non sia vero.
Gioacchino W

@JoachimWuttke: Sebbene np.alle np.anysiano in grado di cortocircuitare, l'argomento passato ad esso viene valutato prima np.allo np.anyha una possibilità di cortocircuito. Per fare meglio, al momento, dovresti scrivere un codice C / Cython specializzato simile a questo .
unutbu,

47

Ho avuto lo stesso problema (ovvero indicizzazione con più condizioni, qui sta trovando i dati in un determinato intervallo di date). Il (a-b).any()o (a-b).all()sembra non funzionare, almeno per me.

In alternativa, ho trovato un'altra soluzione che funziona perfettamente per la mia funzionalità desiderata ( Il valore di verità di un array con più di un elemento è ambiguo quando provo ad indicizzare un array ).

Invece di utilizzare il codice suggerito sopra, semplicemente usando un numpy.logical_and(a,b)avrebbe funzionato. Qui potresti voler riscrivere il codice come

selected  = r[numpy.logical_and(r["dt"] >= startdate, r["dt"] <= enddate)]

34

Il motivo dell'eccezione è che andchiama implicitamente bool. Prima sull'operando di sinistra e (se l'operando di sinistra è True) poi sull'operando di destra. Quindi x and yè equivalente a bool(x) and bool(y).

Tuttavia, l' boolon a numpy.ndarray(se contiene più di un elemento) genererà l'eccezione che hai visto:

>>> import numpy as np
>>> arr = np.array([1, 2, 3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

La bool()chiamata è in implicita and, ma anche in if, while, or, in modo che qualsiasi dei seguenti esempi fallirà anche:

>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

>>> if arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

>>> while arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

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

Ci sono più funzioni e istruzioni in Python che nascondono le boolchiamate, ad esempio 2 < x < 10è solo un altro modo di scrivere 2 < x and x < 10. E la andchiamerà bool: bool(2 < x) and bool(x < 10).

L' equivalente dal punto di vista dell'elementoand sarebbe la np.logical_andfunzione, allo stesso modo si potrebbe usare np.logical_orcome equivalente per or.

Per gli array booleani - e confronti piace <, <=, ==, !=, >=e >sul NumPy array restituiscono array NumPy booleane - è anche possibile utilizzare i elemento-saggio bit a bit funzioni (e operatori): np.bitwise_and( &operatore)

>>> np.logical_and(arr > 1, arr < 3)
array([False,  True, False], dtype=bool)

>>> np.bitwise_and(arr > 1, arr < 3)
array([False,  True, False], dtype=bool)

>>> (arr > 1) & (arr < 3)
array([False,  True, False], dtype=bool)

e bitwise_or( |operatore):

>>> np.logical_or(arr <= 1, arr >= 3)
array([ True, False,  True], dtype=bool)

>>> np.bitwise_or(arr <= 1, arr >= 3)
array([ True, False,  True], dtype=bool)

>>> (arr <= 1) | (arr >= 3)
array([ True, False,  True], dtype=bool)

Un elenco completo di funzioni logiche e binarie è disponibile nella documentazione di NumPy:


2

se lavori con pandasciò che ho risolto il problema per me era che stavo cercando di fare calcoli quando avevo valori NA, la soluzione era quella di eseguire:

df = df.dropna()

E poi il calcolo fallito.


0

Questo messaggio di errore digitato mostra anche mentre if-statementviene eseguito un confronto in cui è presente un array e, ad esempio, un valore bool o int. Vedi ad esempio:

... code snippet ...

if dataset == bool:
    ....

... code snippet ...

Questa clausola ha un set di dati come array e bool è euhm la "porta aperta" ... Trueo False.

Nel caso in cui la funzione sia racchiusa in una try-statement, riceverai except Exception as error:il messaggio senza il suo tipo di errore:

Il valore di verità di un array con più di un elemento è ambiguo. Usa a.any () o a.all ()


-6

prova this => numpy.array (r) o numpy.array (yourvariable) seguito dal comando per confrontare qualunque cosa tu voglia.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.