Wenn du sagst
(a['x']==1) and (a['y']==10)
Sie fordern Python implizit auf, zu konvertieren (a['x']==1)
und (a['y']==10)
zu booleschen Werten.
NumPy-Arrays (mit einer Länge größer als 1) und Pandas-Objekte wie Series haben keinen booleschen Wert – mit anderen Worten, sie erhöhen
ValueError: Der Wahrheitswert eines Arrays ist mehrdeutig. Verwenden Sie a.empty, a.any() oder a.all().
bei Verwendung als boolescher Wert. Das ist, weil es ist unklar, wann es wahr oder falsch sein sollte. Einige Benutzer nehmen möglicherweise an, dass sie wahr sind, wenn sie eine Länge ungleich Null haben, wie eine Python-Liste. Andere mögen wünschen, dass es nur wahr ist, wenn alle seine Elemente sind wahr. Andere möchten vielleicht, dass es True if ist irgendein seiner Elemente sind wahr.
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 die aufrufen empty()
, all()
oder any()
Methode, um anzuzeigen, welches Verhalten Sie wünschen.
In diesem Fall sieht es jedoch so aus, als ob Sie keine boolesche Auswertung wollen, Sie wollen elementweise logisch-und. Das ist, was die &
binärer Operator führt aus:
(a['x']==1) & (a['y']==10)
gibt ein boolesches Array zurück.
Übrigens, wie alexpmil anmerkt, sind die Klammern seither obligatorisch &
hat eine höhere Operator Vorrang als ==
.
Ohne die Klammern a['x']==1 & a['y']==10
würde gewertet als a['x'] == (1 & a['y']) == 10
was wiederum dem verketteten Vergleich äquivalent wäre (a['x'] == (1 & a['y'])) and ((1 & a['y']) == 10)
. Das ist ein Ausdruck der Form Series and Series
. Die Verwendung von and
bei zwei Serien würde das wieder das gleiche auslösen ValueError
wie oben. Deshalb sind die Klammern obligatorisch.
TLDR; Logische Operatoren in Pandas sind &
, |
und ~
und Klammern (...)
ist wichtig!
Pythons and
, or
und not
Logische Operatoren sind für die Arbeit mit Skalaren ausgelegt. Pandas musste also noch eins draufsetzen und die bitweisen Operatoren überschreiben, um das zu erreichen vektorisiert (elementweise) Version dieser Funktionalität.
Also das Folgende in Python (exp1
und exp2
sind Ausdrücke, die zu einem boolschen Ergebnis ausgewertet werden)…
exp1 and exp2 # Logical AND
exp1 or exp2 # Logical OR
not exp1 # Logical NOT
…übersetzt zu…
exp1 & exp2 # Element-wise logical AND
exp1 | exp2 # Element-wise logical OR
~exp1 # Element-wise logical NOT
für Pandas.
Wenn Sie beim Ausführen einer logischen Operation a erhalten ValueError
dann müssen Sie Klammern zum Gruppieren verwenden:
(exp1) op (exp2)
Zum Beispiel,
(df['col1'] == x) & (df['col2'] == y)
Usw.
Boolesche Indizierung: Eine übliche Operation besteht darin, boolesche Masken durch logische Bedingungen zu berechnen, um die Daten zu filtern. Pandas bietet drei Betreiber: &
für logisches UND, |
für logisches ODER und ~
für logisches NICHT.
Betrachten Sie die folgende Konfiguration:
np.random.seed(0)
df = pd.DataFrame(np.random.choice(10, (5, 3)), columns=list('ABC'))
df
A B C
0 5 0 3
1 3 7 9
2 3 5 2
3 4 7 6
4 8 8 1
Logisches UND
Zum df
Sagen Sie oben, Sie möchten alle Zeilen zurückgeben, in denen A < 5 und B > 5 ist. Dies geschieht, indem Sie Masken für jede Bedingung separat berechnen und sie UND-verknüpfen.
Bitweise überladen &
Operator
Bevor Sie fortfahren, beachten Sie bitte diesen speziellen Auszug aus den Dokumenten, der besagt
Eine weitere übliche Operation ist die Verwendung von booleschen Vektoren zum Filtern der Daten. Die Operatoren sind: |
zum or
, &
zum and
und ~
zum not
. Diese müssen mit Klammern gruppiert werdenda Python standardmäßig einen Ausdruck wie z df.A > 2 & df.B < 3
wie df.A > (2 &
df.B) < 3
während die gewünschte Auswertungsreihenfolge lautet (df.A > 2) & (df.B <
3)
.
Vor diesem Hintergrund kann ein elementweises logisches UND mit dem bitweisen Operator implementiert werden &
:
df['A'] < 5
0 False
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df['B'] > 5
0 False
1 True
2 False
3 True
4 True
Name: B, dtype: bool
(df['A'] < 5) & (df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
Und der anschließende Filterschritt ist einfach,
df[(df['A'] < 5) & (df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
Die Klammern werden verwendet, um die Standardprioritätsreihenfolge bitweiser Operatoren zu überschreiben, die Vorrang vor den bedingten Operatoren haben <
und >
. Siehe den Abschnitt von Vorrang des Operators in der Python-Dokumentation.
Wenn Sie keine Klammern verwenden, wird der Ausdruck falsch ausgewertet. Wenn Sie beispielsweise versehentlich etwas wie z
df['A'] < 5 & df['B'] > 5
Es wird analysiert als
df['A'] < (5 & df['B']) > 5
Was wird,
df['A'] < something_you_dont_want > 5
Was wird (siehe die Python-Dokumentation auf Verketteter Operatorvergleich),
(df['A'] < something_you_dont_want) and (something_you_dont_want > 5)
Was wird,
# Both operands are Series...
something_else_you_dont_want1 and something_else_you_dont_want2
Welche wirft
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Machen Sie also nicht diesen Fehler!1
Klammergruppierung vermeiden
Die Lösung ist eigentlich ganz einfach. Die meisten Operatoren haben eine entsprechende gebundene Methode für DataFrames. Wenn die einzelnen Masken mit Funktionen anstelle von Bedingungsoperatoren aufgebaut sind, müssen Sie nicht mehr nach Klammern gruppieren, um die Auswertungsreihenfolge anzugeben:
df['A'].lt(5)
0 True
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df['B'].gt(5)
0 False
1 True
2 False
3 True
4 True
Name: B, dtype: bool
df['A'].lt(5) & df['B'].gt(5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
Siehe den Abschnitt über Flexible Vergleiche.. Zusammenfassend haben wir
╒════╤════════════╤════════════╕
│ │ Operator │ Function │
╞════╪════════════╪════════════╡
│ 0 │ > │ gt │
├────┼────────────┼────────────┤
│ 1 │ >= │ ge │
├────┼────────────┼────────────┤
│ 2 │ < │ lt │
├────┼────────────┼────────────┤
│ 3 │ <= │ le │
├────┼────────────┼────────────┤
│ 4 │ == │ eq │
├────┼────────────┼────────────┤
│ 5 │ != │ ne │
╘════╧════════════╧════════════╛
Eine weitere Möglichkeit, Klammern zu vermeiden, ist use DataFrame.query
(oder eval
):
df.query('A < 5 and B > 5')
A B C
1 3 7 9
3 4 7 6
Ich habe ausführlich dokumentiert query
und eval
in der dynamischen Ausdrucksauswertung in Pandas mit pd.eval().
operator.and_
Ermöglicht es Ihnen, diesen Vorgang auf funktionale Weise auszuführen. Anrufe intern Series.__and__
was dem bitweisen Operator entspricht.
import operator
operator.and_(df['A'] < 5, df['B'] > 5)
# Same as,
# (df['A'] < 5).__and__(df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
df[operator.and_(df['A'] < 5, df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
Sie werden dies normalerweise nicht brauchen, aber es ist nützlich zu wissen.
Verallgemeinerung: np.logical_and
(und logical_and.reduce
)
Eine andere Alternative ist die Verwendung np.logical_and
die auch keine Klammergruppierung benötigt:
np.logical_and(df['A'] < 5, df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
Name: A, dtype: bool
df[np.logical_and(df['A'] < 5, df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
np.logical_and
ist ein ufunc (Universelle Funktionen)und die meisten ufuncs haben a reduce
Methode. Dies bedeutet, dass es einfacher ist, mit zu verallgemeinern logical_and
wenn Sie mehrere Masken mit UND haben. Zum Beispiel zu UND-Masken m1
und m2
und m3
mit &
müsstest du machen
m1 & m2 & m3
Es gibt jedoch eine einfachere Option
np.logical_and.reduce([m1, m2, m3])
Dies ist leistungsfähig, da Sie damit mit komplexerer Logik darauf aufbauen können (z. B. Masken in einem Listenverständnis dynamisch generieren und alle hinzufügen):
import operator
cols = ['A', 'B']
ops = [np.less, np.greater]
values = [5, 5]
m = np.logical_and.reduce([op(df[c], v) for op, c, v in zip(ops, cols, values)])
m
# array([False, True, False, True, False])
df[m]
A B C
1 3 7 9
3 4 7 6
1 – Ich weiß, dass ich an diesem Punkt herumzicke, aber bitte haben Sie Geduld mit mir. Das ist ein sehr, sehr ein häufiger Anfängerfehler und muss sehr genau erklärt werden.
Logisches ODER
Für die df
Sagen Sie oben, Sie möchten alle Zeilen zurückgeben, in denen A == 3 oder B == 7 ist.
Bitweise überladen |
df['A'] == 3
0 False
1 True
2 True
3 False
4 False
Name: A, dtype: bool
df['B'] == 7
0 False
1 True
2 False
3 True
4 False
Name: B, dtype: bool
(df['A'] == 3) | (df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
dtype: bool
df[(df['A'] == 3) | (df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Falls noch nicht geschehen, lesen Sie bitte auch den Abschnitt über Logisches UND oben gelten hier alle Vorbehalte.
Alternativ kann diese Operation mit angegeben werden
df[df['A'].eq(3) | df['B'].eq(7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
operator.or_
Anrufe Series.__or__
unter der Haube.
operator.or_(df['A'] == 3, df['B'] == 7)
# Same as,
# (df['A'] == 3).__or__(df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
dtype: bool
df[operator.or_(df['A'] == 3, df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
np.logical_or
Verwenden Sie für zwei Bedingungen logical_or
:
np.logical_or(df['A'] == 3, df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df[np.logical_or(df['A'] == 3, df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Verwenden Sie für mehrere Masken logical_or.reduce
:
np.logical_or.reduce([df['A'] == 3, df['B'] == 7])
# array([False, True, True, True, False])
df[np.logical_or.reduce([df['A'] == 3, df['B'] == 7])]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Logisches NICHT
Angesichts einer Maske, wie z
mask = pd.Series([True, True, False])
Wenn Sie jeden booleschen Wert invertieren müssen (so dass das Endergebnis [False, False, True]
), dann können Sie eine der folgenden Methoden verwenden.
Bitweise ~
~mask
0 False
1 False
2 True
dtype: bool
Auch hier müssen Ausdrücke eingeklammert werden.
~(df['A'] == 3)
0 True
1 False
2 False
3 True
4 True
Name: A, dtype: bool
Dieser ruft intern an
mask.__invert__()
0 False
1 False
2 True
dtype: bool
Aber nicht direkt verwenden.
operator.inv
Anrufe intern __invert__
auf der Serie.
operator.inv(mask)
0 False
1 False
2 True
dtype: bool
np.logical_not
Dies ist die numpy-Variante.
np.logical_not(mask)
0 False
1 False
2 True
dtype: bool
Notiz, np.logical_and
kann ersetzt werden np.bitwise_and
, logical_or
mit bitwise_or
und logical_not
mit invert
.
Logische Operatoren für die boolesche Indizierung in Pandas
Es ist wichtig zu wissen, dass Sie kein Python verwenden können logische Operatoren (and
, or
oder not
) an pandas.Series
oder pandas.DataFrame
s (ebenso können Sie sie nicht auf verwenden numpy.array
s mit mehr als einem Element). Der Grund, warum Sie diese nicht verwenden können, ist, dass sie implizit aufrufen bool
auf ihren Operanden, die eine Ausnahme auslöst, weil diese Datenstrukturen entschieden haben, dass der boolesche Wert eines Arrays mehrdeutig ist:
>>> import numpy as np
>>> import pandas as pd
>>> arr = np.array([1,2,3])
>>> s = pd.Series([1,2,3])
>>> df = pd.DataFrame([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()
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> bool(df)
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Ich habe dies ausführlicher in meiner Antwort auf die Frage „Der Wahrheitswert einer Reihe ist mehrdeutig. Verwenden Sie a.empty, a.bool(), a.item(), a.any() oder a.all()“ Q behandelt +A.
Die logischen Funktionen von NumPy
Jedoch NumPy bietet elementweise operative Äquivalente zu diesen Operatoren als Funktionen, die verwendet werden können numpy.array
, pandas.Series
, pandas.DataFrame
oder jede andere (konforme) numpy.array
Unterklasse:
Also sollte man im Wesentlichen verwenden (vorausgesetzt df1
und df2
sind Pandas DataFrames):
np.logical_and(df1, df2)
np.logical_or(df1, df2)
np.logical_not(df1)
np.logical_xor(df1, df2)
Bitweise Funktionen und bitweise Operatoren für Boolesche Werte
Falls Sie jedoch ein boolesches NumPy-Array, eine Pandas-Serie oder Pandas-DataFrames haben, können Sie auch die verwenden elementweise bitweise Funktionen (für boolesche Werte sind sie – oder sollten es zumindest sein – nicht von den logischen Funktionen zu unterscheiden):
Typischerweise werden die Operatoren verwendet. In Kombination mit Vergleichsoperatoren muss man jedoch daran denken, den Vergleich in Klammern zu setzen, da die bitweisen Operatoren ein a haben Vorrang vor den Vergleichsoperatoren:
(df1 < 10) | (df2 > 10) # instead of the wrong df1 < 10 | df2 > 10
Dies kann irritierend sein, da die logischen Python-Operatoren eine niedrigere Priorität haben als die Vergleichsoperatoren, also schreiben Sie normalerweise a < 10 and b > 10
(wo a
und b
sind zum Beispiel einfache ganze Zahlen) und brauchen keine Klammern.
Unterschiede zwischen logischen und bitweisen Operationen (bei nicht-booleschen Werten)
Es ist wirklich wichtig zu betonen, dass Bit- und logische Operationen nur für boolesche NumPy-Arrays (und boolesche Serien und Datenrahmen) gleichwertig sind. Wenn diese keine booleschen Werte enthalten, führen die Operationen zu anderen Ergebnissen. Ich werde Beispiele mit NumPy-Arrays einfügen, aber die Ergebnisse werden für die Pandas-Datenstrukturen ähnlich sein:
>>> import numpy as np
>>> a1 = np.array([0, 0, 1, 1])
>>> a2 = np.array([0, 1, 0, 1])
>>> np.logical_and(a1, a2)
array([False, False, False, True])
>>> np.bitwise_and(a1, a2)
array([0, 0, 0, 1], dtype=int32)
Und da NumPy (und ähnlich Pandas) verschiedene Dinge für Boolean (Boolesche oder „maskierte“ Indexarrays) und Ganzzahl (Index-Arrays)-Indizes werden die Ergebnisse der Indizierung ebenfalls unterschiedlich sein:
>>> a3 = np.array([1, 2, 3, 4])
>>> a3[np.logical_and(a1, a2)]
array([4])
>>> a3[np.bitwise_and(a1, a2)]
array([1, 1, 1, 2])
Übersichtstabelle
Logical operator | NumPy logical function | NumPy bitwise function | Bitwise operator
-------------------------------------------------------------------------------------
and | np.logical_and | np.bitwise_and | &
-------------------------------------------------------------------------------------
or | np.logical_or | np.bitwise_or | |
-------------------------------------------------------------------------------------
| np.logical_xor | np.bitwise_xor | ^
-------------------------------------------------------------------------------------
not | np.logical_not | np.invert | ~
Wo Der logische Operator funktioniert nicht für NumPy-Arrays, Pandas Series und Pandas DataFrames. Die anderen arbeiten an diesen Datenstrukturen (und einfachen Python-Objekten) und arbeiten elementweise. Seien Sie jedoch vorsichtig mit der bitweisen Umkehrung in einfachem Python bool
s weil bool in diesem Zusammenhang als ganze Zahlen interpretiert wird (z ~False
kehrt zurück -1
und ~True
kehrt zurück -2
).
Dies liegt daran, dass numpy-Arrays und Pandas-Serien die bitweisen Operatoren und nicht die logischen verwenden, da Sie jedes Element im Array/in der Serie mit einem anderen vergleichen. Daher ist es in dieser Situation nicht sinnvoll, den logischen Operator zu verwenden. siehe verwandt: stackoverflow.com/questions/8632033/…
– EdChum
28. Januar 2014 um 20:15 Uhr
Bei Python
and != &
. Dasand
Operator in Python kann nicht überschrieben werden, wohingegen der&
Operator (__and__
) kann. Daher die Wahl der Verwendung&
in Numpy und Pandas.– Steven Rumbalski
28. Januar 2014 um 20:19 Uhr
Verwandt: Der Wahrheitswert einer Serie ist mehrdeutig. Verwenden Sie a.empty, a.bool(), a.item(), a.any() oder a.all()
– cs95
8. März 2019 um 22:10 Uhr
Die Titel- oder Schlüsselwortliste soll numpy enthalten, aber die Bearbeitungswarteschlange ist voll.
– Rainald62
21. Juli um 10:56 Uhr