635 Stimmen

Wie man Zeilen aus einem Pandas DataFrame basierend auf einem bedingten Ausdruck löscht

Ich habe einen Pandas DataFrame und möchte Zeilen daraus löschen, bei denen die Länge der Zeichenfolge in einer bestimmten Spalte größer als 2 ist.

Ich erwarte, dass ich dies tun kann (per diese Antwort ) :

df[(len(df['column name']) < 2)]

aber ich erhalte nur die Fehlermeldung:

KeyError: u'no item named False'

Was mache ich falsch?

(Anmerkung: Ich weiß, ich kann df.dropna() um Zeilen loszuwerden, die irgendwelche NaN aber ich habe nicht gesehen, wie man Zeilen auf der Grundlage eines bedingten Ausdrucks entfernt).

1480voto

User Punkte 55518

Um direkt zu beantworten dieser Frage ursprünglichen Titel "Wie man Zeilen aus einem Pandas DataFrame basierend auf einem bedingten Ausdruck löschen" (die ich verstehe, ist nicht unbedingt das OP-Problem, sondern könnte anderen Benutzern helfen, die über diese Frage kommen) eine Möglichkeit, dies zu tun ist die Verwendung der fallen lassen Methode:

df = df.drop(some labels)
df = df.drop(df[<some boolean condition>].index)

Beispiel

Um alle Zeilen zu entfernen, in denen die Spalte "Punktzahl" < 50 ist:

df = df.drop(df[df.score < 50].index)

Version an Ort und Stelle (wie in den Kommentaren hervorgehoben)

df.drop(df[df.score < 50].index, inplace=True)

Mehrere Bedingungen

(véase Boolesche Indizierung )

Die Betreiber sind: | para or , & para and y ~ para not . Diese müssen mit Hilfe von Klammern gruppiert werden.

So entfernen Sie alle Zeilen, in denen die Spalte "Punktzahl" < 50 und > 20 ist

df = df.drop(df[(df.score < 50) & (df.score > 20)].index)

271voto

BrenBarn Punkte 228691

Wenn Sie das tun len(df['column name']) erhalten Sie nur eine Zahl, nämlich die Anzahl der Zeilen im DataFrame (d. h. die Länge der Spalte selbst). Wenn Sie Folgendes anwenden möchten len zu jedem Element in der Spalte, verwenden Sie df['column name'].map(len) . Also versuchen

df[df['column name'].map(len) < 2]

180voto

somesingsomsing Punkte 3142

Sie können die DataFrame zu einer gefilterten Version seiner selbst:

df = df[df.score > 50]

Dies ist schneller als drop :

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test[test.x < 0]
# 54.5 ms ± 2.02 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test.drop(test[test.x > 0].index, inplace=True)
# 201 ms ± 17.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
test = pd.DataFrame({'x': np.random.randn(int(1e6))})
test = test.drop(test[test.x > 0].index)
# 194 ms ± 7.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

21voto

Zakir Punkte 2172

Ich werde die generische Lösung von @User erweitern, um eine drop kostenlose Alternative. Dies ist für Leute, die aufgrund des Titels der Frage hierher geleitet werden (nicht das Problem des Auftraggebers)

Angenommen, Sie möchten alle Zeilen mit negativen Werten löschen. Eine einfache Lösung ist:-

df = df[(df > 0).all(axis=1)]

Schritt-für-Schritt-Erläuterung:--

Erzeugen wir einen 5x5-Zufallsdatenrahmen mit Normalverteilung

np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,5), columns=list('ABCDE'))
      A         B         C         D         E
0  1.764052  0.400157  0.978738  2.240893  1.867558
1 -0.977278  0.950088 -0.151357 -0.103219  0.410599
2  0.144044  1.454274  0.761038  0.121675  0.443863
3  0.333674  1.494079 -0.205158  0.313068 -0.854096
4 -2.552990  0.653619  0.864436 -0.742165  2.269755

Die Bedingung sei das Löschen von Negativen. Ein boolescher Wert df, der die Bedingung erfüllt:-

df > 0
      A     B      C      D      E
0   True  True   True   True   True
1  False  True  False  False   True
2   True  True   True   True   True
3   True  True  False   True  False
4  False  True   True  False   True

Eine boolesche Reihe für alle Zeilen, die die Bedingung erfüllen Hinweis: Wenn ein Element in der Zeile die Bedingung nicht erfüllt, wird die Zeile als falsch markiert.

(df > 0).all(axis=1)
0     True
1    False
2     True
3    False
4    False
dtype: bool

Schließlich filtern Sie die Zeilen aus dem Datenrahmen auf der Grundlage der Bedingung

df[(df > 0).all(axis=1)]
      A         B         C         D         E
0  1.764052  0.400157  0.978738  2.240893  1.867558
2  0.144044  1.454274  0.761038  0.121675  0.443863

Sie können es wieder df zuweisen, um tatsächlich löschen gegen Filter ing oben getan
df = df[(df > 0).all(axis=1)]

Dies kann leicht erweitert werden, um Zeilen herauszufiltern, die NaN s (nicht numerische Einträge) enthalten:-
df = df[(~df.isnull()).all(axis=1)]

Dies kann auch für Fälle wie diesen vereinfacht werden: Alle Zeilen löschen, in denen die Spalte E negativ ist

df = df[(df.E>0)]

Zum Schluss möchte ich noch einige Statistiken darüber anführen, warum @User's drop Lösung ist langsamer als die Rohsäulenfiltration:-

%timeit df_new = df[(df.E>0)]
345 µs ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit dft.drop(dft[dft.E < 0].index, inplace=True)
890 µs ± 94.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Eine Spalte ist im Grunde eine Series d.h. eine NumPy Array, kann es ohne Kosten indiziert werden. Für Leute, die daran interessiert sind, wie sich die zugrunde liegende Speicherorganisation auf die Ausführungsgeschwindigkeit auswirkt, gibt es hier eine großartige Link zur Beschleunigung von Pandas :

12voto

BENY Punkte 302708

In Pandas können Sie Folgendes tun str.len mit Ihrer Begrenzung und verwenden Sie das boolesche Ergebnis, um es zu filtern.

df[df['column name'].str.len().lt(2)]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X