Wie wähle ich Zeilen aus einem DataFrame
basierend auf Werten in einer Spalte in Python Pandas aus?
In SQL würde ich verwenden:
SELECT *
FROM table
WHERE colume_name = some_value
Ich habe versucht, die Dokumentation von pandas zu lesen, fand aber nicht sofort die Antwort.
Antworten:
some_value
Verwenden Sie Folgendes, um Zeilen auszuwählen, deren Spaltenwert einem Skalar entspricht==
:some_values
Verwenden Sie Folgendes, um Zeilen auszuwählen, deren Spaltenwert iterierbar istisin
:Kombinieren Sie mehrere Bedingungen mit
&
:Beachten Sie die Klammern. Aufgrund Pythons Betreiber Vorrangregeln ,
&
bindet fester als<=
und>=
. Daher sind die Klammern im letzten Beispiel erforderlich. Ohne die Klammernwird analysiert als
was zu einem Wahrheitswert einer Serie führt, ist ein mehrdeutiger Fehler .
Verwenden Sie Folgendes
some_value
, um Zeilen auszuwählen, deren Spaltenwert nicht gleich ist!=
:isin
Gibt eine boolesche Reihe zurück. Um also Zeilen auszuwählen, deren Wert nicht in istsome_values
, negieren Sie die boolesche Reihe mit~
:Zum Beispiel,
ergibt
Wenn Sie mehrere Werte einschließen möchten, fügen Sie diese in eine Liste (oder allgemeiner in eine iterierbare) ein und verwenden Sie
isin
:ergibt
Beachten Sie jedoch, dass , wenn Sie wollen dies viele Male tun, ist es effizienter , einen Index zuerst zu machen, und dann verwenden
df.loc
:ergibt
oder, um mehrere Werte aus dem Index aufzunehmen, verwenden Sie
df.index.isin
:ergibt
quelle
df.where(condition)
, muss die Bedingung die gleiche Form haben wiedf
.df[df['column_name'] == some_value]
funktioniert, warum brauchen wir fügen.loc
hier?Es gibt verschiedene Möglichkeiten, Zeilen aus einem Pandas-Datenrahmen auszuwählen:
df[df['col'] == value
])df.iloc[...]
)df.xs(...)
)df.query(...)
APIIm Folgenden zeige ich Ihnen jeweils Beispiele mit Ratschlägen zur Verwendung bestimmter Techniken. Angenommen, unser Kriterium ist Spalte
'A'
=='foo'
(Hinweis zur Leistung: Für jeden Basistyp können wir die Dinge mithilfe der Pandas-API einfach halten oder uns außerhalb der API wagen, normalerweise in die API hinein
numpy
, und die Dinge beschleunigen.)Setup
Das erste, was wir brauchen, ist die Identifizierung einer Bedingung, die als unser Kriterium für die Auswahl von Zeilen dient. Wir beginnen mit dem Fall des OP
column_name == some_value
und schließen einige andere häufige Anwendungsfälle ein.Ausleihen bei @unutbu:
1. Boolesche Indizierung
... Für die boolesche Indizierung muss ermittelt werden, ob der wahre Wert der
'A'
Spalte jeder Zeile gleich ist'foo'
, und anhand dieser Wahrheitswerte ermittelt werden, welche Zeilen beibehalten werden sollen. Normalerweise nennen wir diese Reihe eine Reihe von Wahrheitswertenmask
. Das machen wir auch hier.Wir können diese Maske dann verwenden, um den Datenrahmen zu schneiden oder zu indizieren
Dies ist eine der einfachsten Möglichkeiten, um diese Aufgabe zu erfüllen. Wenn Leistung oder Intuitivität kein Problem darstellen, sollte dies die von Ihnen gewählte Methode sein. Wenn jedoch die Leistung ein Problem darstellt, sollten Sie eine alternative Methode zum Erstellen des in Betracht ziehen
mask
.2. Positionsindizierung
Die Positionsindizierung (
df.iloc[...]
) hat ihre Anwendungsfälle, aber dies ist keiner von ihnen. Um herauszufinden, wo geschnitten werden soll, müssen wir zuerst dieselbe boolesche Analyse durchführen, die wir oben durchgeführt haben. Dadurch müssen wir einen zusätzlichen Schritt ausführen, um dieselbe Aufgabe zu erfüllen.3. Etikettenindizierung
Die Indizierung von Etiketten kann sehr praktisch sein, aber in diesem Fall erledigen wir wieder mehr Arbeit ohne Nutzen
4.
df.query()
APIpd.DataFrame.query
ist eine sehr elegante / intuitive Methode, um diese Aufgabe auszuführen, ist jedoch häufig langsamer. Allerdings , wenn Sie die Aufmerksamkeit auf die Timings unten zahlen, für große Daten, ist die Abfrage sehr effizient. Mehr als der Standardansatz und von ähnlicher Größe wie mein bester Vorschlag.Ich bevorzuge die
Boolean
mask
Tatsächliche Verbesserungen können vorgenommen werden, indem geändert wird, wie wir unsere erstellen
Boolean
mask
.mask
Alternative 1Verwenden Sie das zugrunde liegende
numpy
Array und verzichten Sie auf den Aufwand für die Erstellung eines anderenpd.Series
Ich werde am Ende vollständigere Zeittests zeigen, aber werfen Sie einen Blick auf die Leistungssteigerungen, die wir mit dem Beispieldatenrahmen erzielen. Zunächst betrachten wir den Unterschied bei der Erstellung der
mask
Die Auswertung
mask
mit demnumpy
Array ist ~ 30 mal schneller. Dies ist teilweise darauf zurückzuführen, dass dienumpy
Bewertung häufig schneller erfolgt. Dies ist auch teilweise auf den fehlenden Overhead zurückzuführen, der zum Erstellen eines Index und eines entsprechendenpd.Series
Objekts erforderlich ist .Als nächstes schauen wir uns den Zeitpunkt für das Schneiden mit dem einen
mask
gegen den anderen an.Die Leistungssteigerungen sind nicht so ausgeprägt. Wir werden sehen, ob dies gegenüber robusteren Tests Bestand hat.
mask
Alternative 2Wir hätten auch den Datenrahmen rekonstruieren können. Bei der Rekonstruktion eines Datenrahmens gibt es eine große Einschränkung - Sie müssen sich dabei um die kümmern
dtypes
!Stattdessen werden
df[mask]
wir dies tunWenn der Datenrahmen vom gemischten Typ ist, was unser Beispiel ist, dann sind, wenn wir
df.values
das resultierende Array erhalten,dtype
object
und folglich alle Spalten des neuen Datenrahmens vondtype
object
. Dies erfordertastype(df.dtypes)
und tötet potenzielle Leistungssteigerungen.Wenn der Datenrahmen jedoch nicht vom gemischten Typ ist, ist dies eine sehr nützliche Methode.
Gegeben
Gegen
Wir haben die Zeit halbiert.
mask
Alternative 3@unutbu zeigt uns auch, wie wir
pd.Series.isin
jedes Elementdf['A']
in einer Reihe von Werten berücksichtigen können. Dies ergibt dasselbe, wenn unser Wertesatz ein Satz von einem Wert ist, nämlich'foo'
. Es wird jedoch auch verallgemeinert, bei Bedarf größere Wertesätze einzuschließen. Es stellt sich heraus, dass dies immer noch ziemlich schnell ist, obwohl es eine allgemeinere Lösung ist. Der einzige wirkliche Verlust liegt in der Intuitivität für diejenigen, die mit dem Konzept nicht vertraut sind.Nach wie vor können wir jedoch
numpy
die Leistung verbessern und dabei praktisch nichts opfern. Wir werden verwendennp.in1d
Timing
Ich werde andere Konzepte, die in anderen Posts erwähnt werden, auch als Referenz aufnehmen.
Code unten
Jede Spalte in dieser Tabelle repräsentiert einen Datenrahmen unterschiedlicher Länge, über den wir jede Funktion testen. Jede Spalte zeigt die relative Zeit, die benötigt wird, wobei die schnellste Funktion einen Basisindex von hat
1.0
.Sie werden feststellen, dass die schnellsten Zeiten zwischen
mask_with_values
und geteilt zu werden scheinenmask_with_in1d
Funktionen
Testen
Sonderzeitpunkt
Betrachten Sie den Sonderfall, wenn wir ein einzelnes Nichtobjekt
dtype
für den gesamten Datenrahmen haben. Code untenEs stellt sich heraus, dass sich der Wiederaufbau nach ein paar hundert Reihen nicht lohnt.
Funktionen
Testen
quelle
.iloc(numpy.where(..))
in diesem Schema vergleichen? ii) Würden Sie erwarten, dass die Ranglisten bei Verwendung mehrerer Bedingungen gleich sind?pd.Series.isin
ist zu beachten , es tut Gebrauchnp.in1d
unter der Haube in einem bestimmten Szenario Khash Verwendungen in anderen, und gelten implizit einen Kompromiss zwischen Kosten von Hashing gegen Leistung in bestimmten Situationen. Diese Antwort enthält mehr Details.[{P|EXP}TIME]
- und[{C|P|EXP}SPACE]
- Kosten der Verwendung der oben vorgeschlagenen Formen der Block-Syntax ( die Verarbeitung top-down die gesamte Datenrahmen auf einmal) wachsen , und zwar , wenn auf einige~1E6, ~1E9, ~1E12
Zeilenzahlen skaliert ? Vielen Dank, dass Sie uns das ganze Bild gezeigt haben, Sir. Quantitative Benchmark Lesungen mit[min, Avg, MAX, StDev]
immer willkommen, da sowohl diemin
undMAX
Werte , die begleitenMean/StDev
Erleichterung der Partie.tl; dr
Die Pandas entsprechen
ist
Mehrere Bedingungen:
oder
Codebeispiel
Im obigen Code
df[df.foo == 222]
gibt222
in diesem Fall die Zeile die Zeilen basierend auf dem Spaltenwert an .Es sind auch mehrere Bedingungen möglich:
An dieser Stelle würde ich jedoch die Verwendung der Abfragefunktion empfehlen , da diese weniger ausführlich ist und das gleiche Ergebnis liefert:
quelle
query
ist hier die einzige Antwort, die mit der Methodenverkettung kompatibel ist. Es scheint, als wäre es das Pandas-Analogon zufilter
dplyr.[
keine runden Klammern(
an der Außenseite benötigen .|
für AND, aber natürlich ist es OR-Operator ...df[condition1][condition2]
df.query('`my col` == 124')
Ich finde die Syntax der vorherigen Antworten überflüssig und schwer zu merken. Pandas hat die
query()
Methode in Version 0.13 eingeführt und ich bevorzuge sie sehr. Für Ihre Frage könnten Sie tundf.query('col == val')
Wiedergabe von http://pandas.pydata.org/pandas-docs/version/0.17.0/indexing.html#indexing-query
Sie können auch auf Variablen in der Umgebung zugreifen, indem Sie eine voranstellen
@
.quelle
numexpr
installieren.Mehr Flexibilität
.query
mitpandas >= 0.25.0
:August 2019 aktualisierte Antwort
Da können
pandas >= 0.25.0
wir diequery
Methode verwenden, um Datenrahmen mit Pandas-Methoden und sogar Spaltennamen mit Leerzeichen zu filtern. Normalerweise würden die Leerzeichen in Spaltennamen einen Fehler ergeben, aber jetzt können wir das mit einem Backtick (`) lösen, siehe GitHub :Verwenden
.query
mit Methodestr.endswith
:Ausgabe
Wir können auch lokale Variablen verwenden, indem wir
@
in unserer Abfrage ein Präfix voranstellen:Ausgabe
quelle
Schnellere Ergebnisse können mit numpy.where erzielt werden .
Zum Beispiel mit dem Setup von unubtu -
Zeitvergleiche:
quelle
Hier ist ein einfaches Beispiel
quelle
Zum Auswählen nur bestimmter Spalten aus mehreren Spalten für einen bestimmten Wert in Pandas:
Optionen:
oder
quelle
Um an diese berühmte Frage anzuhängen (wenn auch etwas zu spät): Sie können auch
df.groupby('column_name').get_group('column_desired_value').reset_index()
einen neuen Datenrahmen mit einer bestimmten Spalte mit einem bestimmten Wert erstellen. Z.BFühren Sie dies ergibt:
quelle
get_group()
automatisch ein Datenrahmen zurückgegeben wird. Sie können auch einfach "drop = True" als Parameter von sagenreset_index()
. Mit anderen Worten, es kann verkürzt werden auf:b_is_two_dataframe = df.groupby('B').get_group('two').reset_index(drop=True)
Sie können auch .apply verwenden:
Es funktioniert tatsächlich zeilenweise (dh es wendet die Funktion auf jede Zeile an).
Die Ausgabe ist
Die Ergebnisse sind die gleichen wie bei @unutbu
quelle