Ich habe gerade einen logischen Fehler in meinem Code entdeckt, der alle möglichen Probleme verursacht hat. Ich habe versehentlich ein bitweises UND anstelle eines logischen UND durchgeführt.
Ich änderte den Code von:
r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]
TO:
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 mehrdeutig. Verwenden Sie a.any() oder a.all()
Warum wurde ein ähnlicher Fehler nicht ausgegeben, wenn ich eine bitweise Operation verwende - und wie kann ich dies beheben?
r" ist ein numpy (rec)array. Also ist r["dt"] >= startdate
auch ein (boolesches)
Array. Bei numpy-Arrays gibt die Operation &
das elementweise-und der beiden
booleschen Arrays zurück.
Die NumPy-Entwickler waren der Meinung, dass es keinen allgemein verständlichen Weg gibt, um
ein Array im booleschen Kontext auszuwerten: Es könnte True
bedeuten, wenn ein Element True
ist
wahr" ist, oder es könnte "wahr" bedeuten, wenn alle Elemente "wahr" sind, oder "wahr", wenn das Array eine Länge ungleich Null hat, um nur drei Möglichkeiten zu nennen.
Da verschiedene Benutzer unterschiedliche Bedürfnisse und unterschiedliche Annahmen haben könnten, haben die
NumPy-Entwickler nicht raten und haben stattdessen beschlossen, einen ValueError
auszulösen, wenn man versucht, ein Array im booleschen Kontext auszuwerten. Die Anwendung von und
auf
zwei Numpy-Arrays bewirkt, dass die beiden Arrays im booleschen Kontext ausgewertet werden (durch
Aufruf von __bool__
in Python3 oder __nonzero__
in Python2).
Ihr ursprünglicher Code
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]
sieht korrekt aus. Wenn Sie jedoch und
wollen, dann verwenden Sie anstelle von a und b
(a-b).any()
oder (a-b).all()
.
Ich hatte das gleiche Problem (d.h. Indizierung mit Multi-Bedingungen, hier it's finden Daten in einem bestimmten Datumsbereich). 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 für meine gewünschte Funktionalität perfekt funktioniert (https://stackoverflow.com/questions/12647471/the-truth-value-of-an-array-with-more-than-one-element-is-ambigous-when-trying-t).
Anstatt den oben vorgeschlagenen Code zu verwenden, könnte man auch einfach numpy.logical_and(a,b)
verwenden. Hier sollten Sie den Code wie folgt umschreiben
selected = r[numpy.logical_and(r["dt"] >= startdate, r["dt"] <= enddate)]
Der Grund für die Ausnahme ist, dass und
implizit bool
aufruft. Zuerst auf den linken Operanden und (wenn der linke Operand True
ist) dann auf den rechten Operanden. Also ist x und y
äquivalent zu bool(x) und bool(y)
.
Jedoch wird bool
auf einem numpy.ndarray
(wenn es mehr als ein Element enthält) die Ausnahme auslösen, 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()
Aufruf ist implizit in und
, aber auch in if
, while
, or
, so dass jedes der folgenden Beispiele ebenfalls fehlschlagen wird:
>>> 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 noch mehr Funktionen und Anweisungen in Python, die bool
-Aufrufe verbergen, zum Beispiel ist 2 < x < 10
nur eine andere Art, 2 < x und x < 10
zu schreiben. Und das und
wird bool
aufrufen: bool(2 < x) und bool(x < 10)
.
Das elementweise Äquivalent für und
wäre die Funktion np.logical_and
, ebenso könnte man np.logical_or
als Äquivalent für or
verwenden.
Für boolesche Arrays - und Vergleiche wie <
, <=
, ==
, !=
, >=
und >
auf NumPy-Arrays, die boolesche NumPy-Arrays zurückgeben - können Sie auch die elementweise bitweisen Funktionen (und Operatoren) verwenden: np.bitwise_and
(&
Operator)
>>> 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
(|
Operator):
>>> 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 ist in der NumPy-Dokumentation zu finden: