Der Wahrheitswert einer Serie ist nicht eindeutig. Verwenden Sie a.empty, a.bool (), a.item (), a.any () oder a.all ()

368

Probleme beim Filtern meines Ergebnisdatenrahmens mit einer orBedingung. Ich möchte, dass mein Ergebnis dfalle Spaltenwerte extrahiert var, die über 0,25 und unter -0,25 liegen.

Diese Logik gibt mir einen mehrdeutigen Wahrheitswert, funktioniert jedoch, wenn ich diese Filterung in zwei separate Operationen aufteile. Was passiert hier? Ich bin mir nicht sicher, wo ich den vorgeschlagenen verwenden soll a.empty(), a.bool(), a.item(),a.any() or a.all().

 result = result[(result['var']>0.25) or (result['var']<-0.25)]
obabs
quelle
46
Verwenden Sie |anstelle vonor
MaxU
1
Hier ist eine abs(result['var'])>0.25
Problemumgehung

Antworten:

566

Die Anweisungen orund andpython erfordern truth-values. Da pandasdiese als mehrdeutig angesehen werden, sollten Sie "bitweise" |(oder) oder &(und) Operationen verwenden:

result = result[(result['var']>0.25) | (result['var']<-0.25)]

Diese sind für diese Art von Datenstrukturen überladen, um das Element or(oder and) zu erhalten.


Nur um dieser Aussage eine weitere Erklärung hinzuzufügen:

Die Ausnahme wird ausgelöst , wenn Sie die bekommen boolvon ein pandas.Series:

>>> import pandas as pd
>>> x = pd.Series([1])
>>> bool(x)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Was Sie schlagen war ein Ort , an dem der Bediener implizit die Operanden umgewandelt bool(Sie verwendet , oraber es passiert auch and, ifund while):

>>> x or x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> x and x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> if x:
...     print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> while x:
...     print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Neben diesen vier Aussagen gibt es mehrere Python - Funktionen , die einige verstecken boolAnrufe (wie any, all, filter, ...) diese sind in der Regel nicht problematisch , pandas.Seriesaber der Vollständigkeit halber wollte ich diese ganz zu schweigen.


In Ihrem Fall ist die Ausnahme nicht wirklich hilfreich, da sie nicht die richtigen Alternativen erwähnt . Für andund orSie können verwenden (wenn Sie elementweise Vergleiche wünschen):

  • numpy.logical_or::

    >>> import numpy as np
    >>> np.logical_or(x, y)

    oder einfach der |Betreiber:

    >>> x | y
  • numpy.logical_and::

    >>> np.logical_and(x, y)

    oder einfach der &Betreiber:

    >>> x & y

Wenn Sie die Operatoren verwenden, stellen Sie sicher, dass Sie Ihre Klammern aufgrund der Priorität des Operators richtig eingestellt haben .

Es gibt mehrere logische numpy Funktionen , die sollten arbeiten pandas.Series.


Die in der Ausnahme genannten Alternativen sind besser geeignet, wenn Sie beim Ausführen von ifoder auf sie gestoßen sind while. Ich werde diese kurz erläutern:

  • Wenn Sie überprüfen möchten, ob Ihre Serie leer ist :

    >>> x = pd.Series([])
    >>> x.empty
    True
    >>> x = pd.Series([1])
    >>> x.empty
    False

    Python interpretiert normalerweise die length von Containern (wie list, tuple, ...) als Wahrheitswert , wenn es keine explizite boolean Interpretation hat. Wenn Sie also die Python-ähnliche Prüfung wünschen, können Sie Folgendes tun: if x.sizeoder if not x.emptystattdessen if x.

  • Wenn Sie Seriesenthält einen und nur eine Booleschen Wert:

    >>> x = pd.Series([100])
    >>> (x > 50).bool()
    True
    >>> (x < 50).bool()
    False
  • Wenn Sie das erste und einzige Element Ihrer Serie überprüfen möchten (wie .bool(), funktioniert aber auch für nicht boolesche Inhalte):

    >>> x = pd.Series([100])
    >>> x.item()
    100
  • Wenn Sie überprüfen möchten, ob alle oder einige Elemente nicht Null, nicht leer oder nicht falsch sind:

    >>> x = pd.Series([0, 1, 2])
    >>> x.all()   # because one element is zero
    False
    >>> x.any()   # because one (or more) elements are non-zero
    True
MSeifert
quelle
Warum sind diese Python-Operatoren nicht überladen, um Pandas-Serien zu verarbeiten?
Mudit Jain
@MuditJain Es ist direkt Überlastung keine Möglichkeit and, orund notin Python. Diese Operatoren verwenden direkt, was boolauf den Operanden zurückgegeben wird. Und in gewisser Weise haben Pandas / NumPy das bereits überladen, um das zu erhöhen, ValueErrorweil sie den Wahrheitswert einer solchen Datenstruktur für mehrdeutig halten.
MSeifert
Die Lösung ist in Ordnung, aber die Erklärung ist
alles andere als
2
@blacksheep Hast du irgendwelche Vorschläge, was ich besser hätte erklären können?
MSeifert
Das ist eine großartige Erklärung. Es hat mir tatsächlich geholfen, bitweise und logisch so zu verstehen, wie es abstraktere Beispiele nicht geschafft haben.
RocksNwaves
41

Verwenden Sie für die boolesche Logik &und |.

np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))

>>> df
          A         B         C
0  1.764052  0.400157  0.978738
1  2.240893  1.867558 -0.977278
2  0.950088 -0.151357 -0.103219
3  0.410599  0.144044  1.454274
4  0.761038  0.121675  0.443863

>>> df.loc[(df.C > 0.25) | (df.C < -0.25)]
          A         B         C
0  1.764052  0.400157  0.978738
1  2.240893  1.867558 -0.977278
3  0.410599  0.144044  1.454274
4  0.761038  0.121675  0.443863

Um zu sehen, was passiert, erhalten Sie für jeden Vergleich eine Spalte mit Booleschen Werten, z

df.C > 0.25
0     True
1    False
2    False
3     True
4     True
Name: C, dtype: bool

Wenn Sie mehrere Kriterien haben, werden mehrere Spalten zurückgegeben. Aus diesem Grund ist die Verknüpfungslogik nicht eindeutig. Wenn Sie jede Spalte separat verwenden andoder orbehandeln, müssen Sie diese Spalte zunächst auf einen einzelnen booleschen Wert reduzieren. Überprüfen Sie beispielsweise, ob ein Wert oder alle Werte in jeder der Spalten True sind.

# Any value in either column is True?
(df.C > 0.25).any() or (df.C < -0.25).any()
True

# All values in either column is True?
(df.C > 0.25).all() or (df.C < -0.25).all()
False

Ein komplizierter Weg, um dasselbe zu erreichen, besteht darin, alle diese Spalten zusammen zu komprimieren und die entsprechende Logik auszuführen.

>>> df[[any([a, b]) for a, b in zip(df.C > 0.25, df.C < -0.25)]]
          A         B         C
0  1.764052  0.400157  0.978738
1  2.240893  1.867558 -0.977278
3  0.410599  0.144044  1.454274
4  0.761038  0.121675  0.443863

Weitere Informationen finden Sie unter Boolesche Indizierung in den Dokumenten.

Alexander
quelle
20

Nun, Pandas verwenden bitweise '&' '|' und jede Bedingung sollte in ein '()' eingeschlossen werden

Zum Beispiel folgende Arbeiten

data_query = data[(data['year'] >= 2005) & (data['year'] <= 2010)]

Dieselbe Abfrage ohne geeignete Klammern ist jedoch nicht möglich

data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]
Nipun
quelle
8

Alternativ können Sie auch das Operator-Modul verwenden. Weitere Informationen finden Sie hier Python-Dokumente

import operator
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
df.loc[operator.or_(df.C > 0.25, df.C < -0.25)]

          A         B         C
0  1.764052  0.400157  0.978738
1  2.240893  1.867558 -0.977278
3  0.410599  0.144044  1.454274
4  0.761038  0.121675  0.4438
Cảnh Toàn Nguyễn
quelle
1

Diese ausgezeichnete Antwort erklärt sehr gut, was passiert und bietet eine Lösung. Ich möchte eine weitere Lösung hinzufügen, die in ähnlichen Fällen geeignet sein könnte: Verwenden der queryMethode:

result = result.query("(var > 0.25) or (var < -0.25)")

Siehe auch http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-query .

(Einige Tests mit einem Datenrahmen, mit dem ich gerade arbeite, legen nahe, dass diese Methode etwas langsamer ist als die Verwendung der bitweisen Operatoren für eine Reihe von Booleschen Werten: 2 ms gegenüber 870 µs.)

Eine Warnung : Mindestens eine Situation, in der dies nicht einfach ist, besteht darin, dass Spaltennamen zufällig Python-Ausdrücke sind. Ich hatte Spalten genannt WT_38hph_IP_2, WT_38hph_input_2und log2(WT_38hph_IP_2/WT_38hph_input_2)und wollte die folgende Abfrage ausführen:"(log2(WT_38hph_IP_2/WT_38hph_input_2) > 1) and (WT_38hph_IP_2 > 20)"

Ich habe die folgende Ausnahmekaskade erhalten:

  • KeyError: 'log2'
  • UndefinedVariableError: name 'log2' is not defined
  • ValueError: "log2" is not a supported function

Ich denke, dies ist passiert, weil der Abfrageparser versucht hat, etwas aus den ersten beiden Spalten zu machen, anstatt den Ausdruck mit dem Namen der dritten Spalte zu identifizieren.

Eine mögliche Abhilfe wird vorgeschlagen , hier .

bli
quelle
1

Ich bin auf den gleichen Fehler gestoßen und wurde einige Tage lang mit einem Pyspark-Datenrahmen blockiert. Ich konnte ihn erfolgreich beheben, indem ich na-Werte mit 0 füllte, da ich ganzzahlige Werte aus 2 Feldern verglichen habe.

iretex
quelle