Ich arbeite mit dem booleschen Index in Pandas. Die Frage ist, warum die Aussage:
a[(a['some_column']==some_number) & (a['some_other_column']==some_other_number)]
funktioniert gut während
a[(a['some_column']==some_number) and (a['some_other_column']==some_other_number)]
Exits mit Fehler?
Beispiel:
a=pd.DataFrame({'x':[1,1],'y':[10,20]})
In: a[(a['x']==1)&(a['y']==10)]
Out: x y
0 1 10
In: a[(a['x']==1) and (a['y']==10)]
Out: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
and != &
. Derand
Operator in Python kann nicht überschrieben werden, wohingegen der&
Operator (__and__
) dies kann. Daher die Wahl der Verwendung&
bei Numpy und Pandas.Antworten:
Wenn du sagst
Sie fordern Python implizit auf,
(a['x']==1)
und zu konvertieren(a['y']==10)
zu Boolesche Werte.NumPy-Arrays (mit einer Länge größer als 1) und Pandas-Objekte wie Series haben keinen booleschen Wert - mit anderen Worten, sie werden erhöht
bei Verwendung als boolescher Wert. Das liegt daran, dass unklar ist, wann es wahr oder falsch sein sollte . Einige Benutzer nehmen möglicherweise an, dass sie True sind, wenn sie eine Länge ungleich Null haben, wie z. B. eine Python-Liste. Andere möchten vielleicht, dass es nur dann wahr ist, wenn alle seine Elemente wahr sind. Andere möchten vielleicht, dass es wahr ist, wenn überhaupt seiner Elemente wahr sind.
Da es so viele widersprüchliche Erwartungen gibt, weigern sich die Designer von NumPy und Pandas zu raten und lösen stattdessen einen ValueError aus.
Stattdessen müssen Sie explizit sein, indem Sie das
empty()
,all()
oder aufrufenany()
Methode um anzugeben, welches Verhalten Sie wünschen.In diesem Fall sieht es jedoch so aus, als ob Sie keine boolesche Auswertung wünschen, sondern ein elementweises logisches und. Das führt der
&
Binäroperator aus:Gibt ein boolesches Array zurück.
Übrigens, wie alexpmil bemerkt , sind die Klammern obligatorisch, da
&
sie eine höhere Operatorpriorität haben als==
. Ohne die Klammerna['x']==1 & a['y']==10
würde bewertet,a['x'] == (1 & a['y']) == 10
was wiederum dem verketteten Vergleich entspricht(a['x'] == (1 & a['y'])) and ((1 & a['y']) == 10)
. Das ist ein Ausdruck der FormSeries and Series
. Die Verwendungand
mit zwei Serien würde wieder das gleicheValueError
wie oben auslösen . Deshalb sind die Klammern obligatorisch.quelle
x and y
die Auswertung vonbool(x)
und auslöstbool(y)
. Python "wertet zuerst ausx
; wennx
es falsch ist, wird sein Wert zurückgegeben; andernfalls wirdy
es ausgewertet und der resultierende Wert wird zurückgegeben." Die Syntaxx and y
kann also nicht für elementweise logisch verwendet werden - und da nurx
odery
kann zurückgegeben werden. Im Gegensatz dazu könnenx & y
Triggerx.__and__(y)
und die__and__
Methode so definiert werden, dass sie alles zurückgeben, was uns gefällt.==
Klausel sind obligatorisch .a['x']==1 & a['y']==10
gibt den gleichen Fehler wie in der Frage zurück.TLDR; Logische Operatoren in Pandas sind
&
,|
und~
, und Klammern(...)
sind wichtig!Python ist
and
,or
undnot
logische Operatoren sind mit Skalare Arbeit entwickelt. Pandas musste also eine bessere Leistung erbringen und die bitweisen Operatoren überschreiben, um eine vektorisierte (elementweise) Version dieser Funktionalität zu erhalten.Also das Folgende in Python (
exp1
undexp2
sind Ausdrücke, die zu einem booleschen Ergebnis führen) ...... wird übersetzt in ...
für Pandas.
Wenn Sie bei der Ausführung einer logischen Operation eine erhalten
ValueError
, müssen Sie Klammern für die Gruppierung verwenden:Beispielsweise,
Und so weiter.
Boolesche Indizierung : Eine übliche Operation besteht darin, boolesche Masken unter logischen Bedingungen zu berechnen, um die Daten zu filtern. Pandas bietet drei Operatoren:
&
für logisches UND,|
für logisches ODER und~
für logisches NICHT.Betrachten Sie das folgende Setup:
Logisches UND
Zum
df
oben, sagen Sie alle Zeilen zurückgeben möchten , in der A <5 und B> 5. Diese durch Berechnung Masken für jede Bedingung separat durchgeführt wird, und Anding sie.Überladener bitweiser
&
OperatorBevor Sie fortfahren, beachten Sie bitte diesen speziellen Auszug der Dokumente, die angeben
In diesem Sinne kann das elementweise logische UND mit dem bitweisen Operator implementiert werden
&
:Und der nachfolgende Filterungsschritt ist einfach:
Die Klammern werden verwendet, um die Standardrangfolge von bitweisen Operatoren zu überschreiben, die eine höhere Priorität als die bedingten Operatoren
<
und haben>
. Siehe den Abschnitt Operator-Vorrang im in den Python-Dokumenten.Wenn Sie keine Klammern verwenden, wird der Ausdruck falsch ausgewertet. Zum Beispiel, wenn Sie versehentlich etwas versuchen wie
Es wird analysiert als
Welches wird,
Welches wird (siehe die Python-Dokumente zum verketteten Operatorvergleich ),
Welches wird,
Welches wirft
Machen Sie diesen Fehler also nicht! 1
Vermeiden der Gruppierung von Klammern
Die Korrektur ist eigentlich recht einfach. Die meisten Operatoren haben eine entsprechende gebundene Methode für DataFrames. Wenn die einzelnen Masken mithilfe von Funktionen anstelle von bedingten Operatoren erstellt werden, müssen Sie nicht mehr nach Parens gruppieren, um die Bewertungsreihenfolge anzugeben:
Siehe den Abschnitt über flexible Vergleiche. . Zusammenfassend haben wir
Eine weitere Option zum Vermeiden von Klammern ist die Verwendung
DataFrame.query
(odereval
):Ich habe ausführlich dokumentiert
query
undeval
in dynamischer Expression Evaluation in Pandas mit pd.eval () .operator.and_
Ermöglicht es Ihnen, diesen Vorgang auf funktionale Weise auszuführen. Interne Aufrufe,
Series.__and__
die dem bitweisen Operator entsprechen.Normalerweise brauchen Sie das nicht, aber es ist nützlich zu wissen.
Verallgemeinern:
np.logical_and
(undlogical_and.reduce
)Eine andere Alternative ist die Verwendung
np.logical_and
, für die auch keine Gruppierung in Klammern erforderlich ist:np.logical_and
ist ein Ufunc (Universal Functions) , und die meisten Ufuncs haben einereduce
Methode. Dies bedeutet, dass es einfacher ist, zu verallgemeinern,logical_and
wenn Sie mehrere Masken für AND haben. Zum Beispiel zu UND-Maskenm1
undm2
undm3
mit&
müssten Sie tunEine einfachere Option ist jedoch
Dies ist leistungsstark, da Sie mit einer komplexeren Logik darauf aufbauen können (z. B. indem Sie Masken in einem Listenverständnis dynamisch generieren und alle hinzufügen):
1 - Ich weiß, dass ich in diesem Punkt Harfe spiele, aber bitte ertrage es mit mir. Dies ist ein sehr , sehr häufiger Anfängerfehler und muss sehr gründlich erklärt werden.
Logisches ODER
Für die
df
oben, sagen Sie alle Zeilen zurückgeben möchten , in der A == 3 oder B == 7.Bitweise überladen
|
Wenn Sie dies noch nicht getan haben, lesen Sie bitte auch den Abschnitt über logisches UND oben. Alle Vorbehalte gelten hier.
Alternativ kann diese Operation mit angegeben werden
operator.or_
Ruft
Series.__or__
unter der Haube.np.logical_or
Verwenden Sie für zwei Bedingungen
logical_or
:Verwenden Sie für mehrere Masken
logical_or.reduce
:Logisch NICHT
Gegeben eine Maske, wie z
Wenn Sie jeden booleschen Wert invertieren müssen (damit das Endergebnis ist
[False, False, True]
), können Sie eine der folgenden Methoden verwenden.Bitweise
~
Auch hier müssen Ausdrücke in Klammern gesetzt werden.
Dies ruft intern auf
Aber benutze es nicht direkt.
operator.inv
Intern ruft
__invert__
die Serie auf.np.logical_not
Dies ist die numpy Variante.
Hinweis,
np.logical_and
kann durchnp.bitwise_and
,logical_or
mitbitwise_or
undlogical_not
mit ersetzt werdeninvert
.quelle
|
, was äquivalent zu istnumpy.bitwise_or
, anstelle vonnumpy.logical_or
. Darf ich fragen warum? Ist nichtnumpy.logical_or
speziell für diese Aufgabe konzipiert? Warum die Last hinzufügen, dies für jedes Elementpaar bitweise zu tun?|
für elementweise boolesche Operationen verwendet. Für mich ist diese Dokumentation jedoch eher ein "Tutorial", und im Gegensatz dazu sind diese API-Referenzen meiner Meinung nach näher an der Quelle der Wahrheit: numpy.bitwise_or und numpy.logical_or - also versuche ich zu verstehen, was ist hier beschrieben.Es ist wichtig zu erkennen , dass Sie keine der Python verwenden können logische Operatoren (
and
,or
odernot
) aufpandas.Series
oderpandas.DataFrame
s (ähnlich können Sie nicht verwenden sie aufnumpy.array
s mit mehr als einem Element). Der Grund, warum Sie diese nicht verwenden können, liegt darin, dass sie implizitbool
ihre Operanden aufrufen, was eine Ausnahme auslöst, da diese Datenstrukturen entschieden haben, dass der Boolesche Wert eines Arrays nicht eindeutig ist:Ich habe dies in meiner Antwort auf den "Wahrheitswert einer Reihe ist mehrdeutig. Verwenden Sie a.empty, a.bool (), a.item (), a.any () oder a.all ()" Q ausführlicher behandelt + A .
NumPys logische Funktionen
Jedoch NumPy bietet elementweise Betriebs Äquivalente zu diesen Operatoren als Funktionen , die auf die verwendet werden können
numpy.array
,pandas.Series
,pandas.DataFrame
oder jede andere (entsprechend)numpy.array
Unterklasse:and
hatnp.logical_and
or
hatnp.logical_or
not
hatnp.logical_not
numpy.logical_xor
Das hat kein Python-Äquivalent, ist aber eine logische "exklusive oder" OperationIm Wesentlichen sollte man also Folgendes verwenden (vorausgesetzt
df1
unddf2
es handelt sich um Pandas DataFrames):Bitweise Funktionen und bitweise Operatoren für Boolesche Werte
Wenn Sie jedoch über ein boolesches NumPy-Array, Pandas Series oder Pandas DataFrames verfügen, können Sie auch die elementweisen bitweisen Funktionen verwenden (für Boolesche Werte sind oder sollten sie zumindest nicht von den logischen Funktionen zu unterscheiden sein):
np.bitwise_and
oder der&
Operatornp.bitwise_or
oder die|
Operatornp.invert
(oder der Aliasnp.bitwise_not
) oder der~
Operatornp.bitwise_xor
oder der^
OperatorIn der Regel werden die Operatoren verwendet. In Kombination mit Vergleichsoperatoren muss jedoch daran gedacht werden, den Vergleich in Klammern zu setzen, da die bitweisen Operatoren eine höhere Priorität haben als die Vergleichsoperatoren :
Dies kann irritierend sein, da die logischen Python-Operatoren eine geringere Priorität als die Vergleichsoperatoren haben, sodass Sie normalerweise schreiben
a < 10 and b > 10
(woa
undb
sind beispielsweise einfache Ganzzahlen) und die Klammer nicht benötigen.Unterschiede zwischen logischen und bitweisen Operationen (bei Nicht-Booleschen)
Es ist wirklich wichtig zu betonen, dass Bit- und logische Operationen nur für boolesche NumPy-Arrays (und boolesche Serien- und Datenrahmen) äquivalent sind. Wenn diese keine Booleschen Werte enthalten, führen die Operationen zu unterschiedlichen Ergebnissen. Ich werde Beispiele mit NumPy-Arrays einfügen, aber die Ergebnisse für die Pandas-Datenstrukturen sind ähnlich:
Und da NumPy (und ähnlich Pandas) verschiedene Dinge für boolesche ( Boolesche oder "Masken" -Index-Arrays ) und ganzzahlige ( Index-Arrays ) Indizes ausführt, sind auch die Ergebnisse der Indizierung unterschiedlich:
Übersichtstabelle
Wo der logische Operator für NumPy-Arrays , Pandas Series und Pandas DataFrames nicht funktioniert . Die anderen arbeiten an diesen Datenstrukturen (und einfachen Python-Objekten) und arbeiten elementweise. Seien Sie jedoch vorsichtig mit der bitweisen Invertierung auf einfachen Pythons,
bool
da der Bool in diesem Kontext als Ganzzahlen interpretiert wird (z. B.~False
Rückgaben-1
und~True
Rückgaben-2
).quelle