ValueError: Der Wahrheitswert eines Arrays mit mehr als einem Element ist nicht eindeutig. Verwenden Sie a.any () oder a.all ()

221

Ich habe gerade einen logischen Fehler in meinem Code entdeckt, der alle möglichen Probleme verursachte. Ich habe versehentlich ein bitweises UND anstelle eines logischen UND gemacht .

Ich habe den Code geändert von:

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

ZU:

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

Zu meiner Überraschung erhielt ich die ziemlich kryptische Fehlermeldung:

ValueError: Der Wahrheitswert eines Arrays mit mehr als einem Element ist nicht eindeutig. Verwenden Sie a.any () oder a.all ()

Warum wurde ein ähnlicher Fehler nicht ausgegeben, wenn ich eine bitweise Operation verwende - und wie behebe ich das?

Homunculus Reticulli
quelle
1
Pandas bietet auch Dokumentation dafür
Greg

Antworten:

164

rist ein numpy (rec) Array. So r["dt"] >= startdateist auch ein (boolesches) Array. Bei numpy-Arrays gibt die &Operation das elementweise und der beiden booleschen Arrays zurück.

Die NumPy-Entwickler waren der Ansicht, dass es keinen allgemein bekannten Weg gibt, ein Array im booleschen Kontext zu bewerten: Es könnte bedeuten, Trueob ein Element vorhanden ist Trueoder Trueob alle Elemente vorhanden sind Trueoder Trueob das Array eine Länge ungleich Null hat, um nur drei zu nennen Möglichkeiten.

Da unterschiedliche Benutzer möglicherweise unterschiedliche Anforderungen und Annahmen haben, weigerten sich die NumPy-Entwickler zu raten und beschlossen stattdessen, einen ValueError auszulösen, wenn versucht wird, ein Array im booleschen Kontext auszuwerten. Durch Anwenden andauf zwei Numpy-Arrays werden die beiden Arrays im booleschen Kontext ausgewertet (durch Aufrufen __bool__von Python3 oder __nonzero__Python2).

Ihr Originalcode

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

sieht richtig aus. Wenn Sie jedoch nicht möchten and, dann statt a and bVerwendung (a-b).any()oder (a-b).all().

unutbu
quelle
2
Du hast recht. Der ursprüngliche Code war korrekt. Der Fehler scheint irgendwo anders im Code zu liegen.
Homunculus Reticulli
2
Hervorragende Erklärung. Dies impliziert jedoch, dass NumPy ziemlich ineffizient ist: Es wertet beide booleschen Arrays vollständig aus, während eine effiziente Implementierung cond1 (i) && cond2 (i) innerhalb einer einzelnen Schleife auswerten und cond2 überspringen würde, sofern cond1 nicht wahr ist.
Joachim W
@JoachimWuttke: Obwohl np.allund np.anyin der Lage sind, einen Kurzschluss zu verursachen, wird das an ihn übergebene Argument vorher ausgewertet np.alloder es np.anybesteht die Möglichkeit eines Kurzschlusses. Um dies besser zu machen, müssten Sie derzeit einen ähnlichen speziellen C / Cython-Code schreiben .
Unutbu
47

Ich hatte das gleiche Problem (dh Indizierung mit mehreren Bedingungen, hier werden Daten in einem bestimmten Datumsbereich gefunden). Die (a-b).any()oder (a-b).all()scheinen nicht zu funktionieren, zumindest für mich.

Alternativ habe ich eine andere Lösung gefunden, die perfekt für meine gewünschte Funktionalität funktioniert ( Der Wahrheitswert eines Arrays mit mehr als einem Element ist beim Versuch, ein Array zu indizieren, nicht eindeutig ).

Anstatt den oben vorgeschlagenen Code zu verwenden, würde einfach die Verwendung von a numpy.logical_and(a,b)funktionieren. Hier möchten Sie möglicherweise den Code umschreiben als

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

Der Grund für die Ausnahme ist, dass andimplizit aufgerufen wird bool. Zuerst auf dem linken Operanden und (wenn der linke Operand ist True) dann auf dem rechten Operanden. Ist x and yalso gleichbedeutend mit bool(x) and bool(y).

Das boolon a numpy.ndarray(wenn es mehr als ein Element enthält) löst jedoch die Ausnahme aus, die Sie gesehen haben:

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

Der bool()Anruf ist implizit in and, sondern auch in if, while, or, so dass jede der folgenden Beispiele wird auch fehlschlagen:

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

Es gibt mehr Funktionen und Anweisungen in Python, die boolAufrufe verbergen. Dies ist beispielsweise 2 < x < 10nur eine andere Schreibweise 2 < x and x < 10. Und der andwird anrufen bool: bool(2 < x) and bool(x < 10).

Das elementweise Äquivalent für andwäre die np.logical_andFunktion, ähnlich wie Sie es np.logical_orals Äquivalent für verwenden könnten or.

Für boolean Arrays - und Vergleiche wie <, <=, ==, !=, >=und >auf NumPy Arrays zurückgeben boolean NumPy Arrays - auch die können elementweise bitweise Funktionen (und Betreiber): np.bitwise_and( &Betreiber)

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

und bitwise_or( |Betreiber):

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

Eine vollständige Liste der logischen und binären Funktionen finden Sie in der NumPy-Dokumentation:

MSeifert
quelle
2

Wenn Sie mit pandasdem arbeiten, was das Problem für mich gelöst hat, war, dass ich versucht habe, Berechnungen durchzuführen, wenn ich NA-Werte hatte, war die Lösung:

df = df.dropna()

Und danach die Berechnung, die fehlgeschlagen ist.

Tomer Ben David
quelle
0

Diese typisierte Fehlermeldung wird auch angezeigt, während ein if-statementVergleich durchgeführt wird, wenn ein Array und beispielsweise ein Bool oder Int vorhanden sind. Siehe zum Beispiel:

... code snippet ...

if dataset == bool:
    ....

... code snippet ...

Diese Klausel hat einen Datensatz als Array und bool ist euhm die "offene Tür" ... Trueoder False.

Falls die Funktion in eine eingeschlossen try-statementist, erhalten Sie except Exception as error:die Nachricht ohne Fehlertyp:

Der Wahrheitswert eines Arrays mit mehr als einem Element ist nicht eindeutig. Verwenden Sie a.any () oder a.all ()

ZF007
quelle
-6

Versuchen Sie dies => numpy.array (r) oder numpy.array (Ihre Variable), gefolgt vom Befehl, um zu vergleichen, was Sie wollen.

Anurag Gupta
quelle