So löschen Sie Zeilen von Pandas DataFrame, deren Wert in einer bestimmten Spalte NaN ist

754

Ich habe dies DataFrameund möchte nur die Datensätze, deren EPSSpalte nicht ist NaN:

>>> df
                 STK_ID  EPS  cash
STK_ID RPT_Date                   
601166 20111231  601166  NaN   NaN
600036 20111231  600036  NaN    12
600016 20111231  600016  4.3   NaN
601009 20111231  601009  NaN   NaN
601939 20111231  601939  2.5   NaN
000001 20111231  000001  NaN   NaN

... dh so etwas wie df.drop(....)diesen resultierenden Datenrahmen zu bekommen:

                  STK_ID  EPS  cash
STK_ID RPT_Date                   
600016 20111231  600016  4.3   NaN
601939 20111231  601939  2.5   NaN

Wie mache ich das?

großer Käfer
quelle
176
df.dropna(subset = ['column1_name', 'column2_name', 'column3_name'])
osa

Antworten:

655

Lassen Sie sich nicht fallen, sondern nehmen Sie die Zeilen, in denen EPS nicht NA ist:

df = df[df['EPS'].notna()]
Eumiro
quelle
470
Ich würde empfehlen, pandas.notnullanstelle vonnp.isfinite
Wes McKinney
11
Gibt es einen Vorteil beim Indizieren und Kopieren gegenüber dem Löschen?
Robert Muil
9
Erstellt Fehler: TypeError: ufunc 'isfinite' wird für die Eingabetypen nicht unterstützt, und die Eingaben konnten gemäß der Casting-Regel '' safe ''
Philipp Schwarz
4
@ wes-mckinney könnte mich bitte wissen lassen, ob dropna () in diesem Fall eine bessere Wahl als pandas.notnull ist? Wenn ja, warum dann?
Sturmfeld
4
@PhilippSchwarz Dieser Fehler tritt auf, wenn die Spalte ( EPSim Beispiel) Zeichenfolgen oder andere Typen enthält, die nicht verdaut werden können np.isfinite(). Ich empfehle, pandas.notnull()dies großzügiger zu handhaben.
Normanius
902

Diese Frage ist bereits gelöst, aber ...

... berücksichtigen Sie auch die von Wouter in seinem ursprünglichen Kommentar vorgeschlagene Lösung . Die Fähigkeit, fehlende Daten einschließlich zu verarbeiten dropna(), ist explizit in Pandas integriert. Abgesehen von einer potenziell verbesserten Leistung gegenüber der manuellen Ausführung bieten diese Funktionen auch eine Vielzahl von Optionen, die nützlich sein können.

In [24]: df = pd.DataFrame(np.random.randn(10,3))

In [25]: df.iloc[::2,0] = np.nan; df.iloc[::4,1] = np.nan; df.iloc[::3,2] = np.nan;

In [26]: df
Out[26]:
          0         1         2
0       NaN       NaN       NaN
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
4       NaN       NaN  0.050742
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
8       NaN       NaN  0.637482
9 -0.310130  0.078891       NaN

In [27]: df.dropna()     #drop all rows that have any NaN values
Out[27]:
          0         1         2
1  2.677677 -1.466923 -0.750366
5 -1.250970  0.030561 -2.678622
7  0.049896 -0.308003  0.823295

In [28]: df.dropna(how='all')     #drop only if ALL columns are NaN
Out[28]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
4       NaN       NaN  0.050742
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
8       NaN       NaN  0.637482
9 -0.310130  0.078891       NaN

In [29]: df.dropna(thresh=2)   #Drop row if it does not have at least two values that are **not** NaN
Out[29]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
5 -1.250970  0.030561 -2.678622
7  0.049896 -0.308003  0.823295
9 -0.310130  0.078891       NaN

In [30]: df.dropna(subset=[1])   #Drop only if NaN in specific column (as asked in the question)
Out[30]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
9 -0.310130  0.078891       NaN

Es gibt auch andere Optionen (siehe Dokumente unter http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html ), einschließlich des Löschens von Spalten anstelle von Zeilen.

Ziemlich praktisch!

Ein Mann
quelle
282
Sie können auch verwenden df.dropna(subset = ['column_name']). Ich hoffe, das spart mindestens einer Person die zusätzlichen 5 Sekunden von "Was mache ich falsch?". Tolle Antwort, +1
James Tobin
10
@ JamesTobin, ich habe gerade 20 Minuten damit verbracht, eine Funktion dafür zu schreiben! Die offizielle Dokumentation war sehr kryptisch: "Beschriftungen entlang einer anderen zu berücksichtigenden Achse, z. B. wenn Sie Zeilen löschen, wäre dies eine Liste der einzuschließenden Spalten." Ich konnte nicht verstehen, was sie bedeuteten ...
osa
df.dropna(subset = ['column_name'])ist genau das, wonach ich gesucht habe! Vielen Dank!
Amalik2205
123

Ich weiß, dass dies bereits beantwortet wurde, aber nur um eine rein pandasische Lösung für diese spezielle Frage zu finden, im Gegensatz zu der allgemeinen Beschreibung von Aman (die wunderbar war) und für den Fall, dass jemand anderes dies tut:

import pandas as pd
df = df[pd.notnull(df['EPS'])]
Kirk Hadley
quelle
10
Eigentlich wäre die spezifische Antwort: df.dropna(subset=['EPS'])(basierend auf der allgemeinen Beschreibung von Aman funktioniert das natürlich auch)
joris
2
notnullist auch das, was Wes (Autor von Pandas) in seinem Kommentar zu einer anderen Antwort vorgeschlagen hat.
fantastisch
Dies ist vielleicht eine Noob-Frage. Aber wenn ich ein df [pd.notnull (...) oder df.dropna mache, wird der Index gelöscht. Wenn es also einen Nullwert im Zeilenindex 10 in einem df der Länge 200 gab. Der Datenrahmen nach dem Ausführen der Drop-Funktion hat Indexwerte von 1 bis 9 und dann 11 bis 200. Wie auch immer, um ihn neu zu indizieren
Aakash Gupta
Sie könnten auch tun, df[pd.notnull(df[df.columns[INDEX]])]wo INDEXdie nummerierte Spalte wäre, wenn Sie den Namen nicht kennen
ocean800
60

Sie können dies verwenden:

df.dropna(subset=['EPS'], how='all', inplace=True)
Joe
quelle
18
how='all'redundanten hier ist, weil Sie Datenrahmen nur mit einem Feld so beide subsetting 'all'und 'any'haben die gleiche Wirkung.
Anton Protopopov
35

Einfachste aller Lösungen:

filtered_df = df[df['EPS'].notnull()]

Die obige Lösung ist viel besser als die Verwendung von np.isfinite ()

Gil Baggio
quelle
22

Sie können die Datenrahmenmethode notnull oder invers von isnull oder numpy.isnan verwenden :

In [332]: df[df.EPS.notnull()]
Out[332]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [334]: df[~df.EPS.isnull()]
Out[334]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [347]: df[~np.isnan(df.EPS)]
Out[347]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN
Anton Protopopov
quelle
10

noch eine andere Lösung, die die Tatsache nutzt, dass np.nan != np.nan:

In [149]: df.query("EPS == EPS")
Out[149]:
                 STK_ID  EPS  cash
STK_ID RPT_Date
600016 20111231  600016  4.3   NaN
601939 20111231  601939  2.5   NaN
MaxU
quelle
2

Andere Version:

df[~df['EPS'].isna()]
Keramat
quelle
Warum dies über verwenden Series.notna()?
AMC
2

In Datensätzen mit einer großen Anzahl von Spalten ist es noch besser zu sehen, wie viele Spalten Nullwerte enthalten und wie viele nicht.

print("No. of columns containing null values")
print(len(df.columns[df.isna().any()]))

print("No. of columns not containing null values")
print(len(df.columns[df.notna().all()]))

print("Total no. of columns in the dataframe")
print(len(df.columns))

Zum Beispiel enthielt es in meinem Datenrahmen 82 Spalten, von denen 19 mindestens einen Nullwert enthielten.

Außerdem können Sie Spalten und Zeilen automatisch entfernen, je nachdem, welche mehr Nullwerte haben.
Hier ist der Code, der dies intelligent macht:

df = df.drop(df.columns[df.isna().sum()>len(df.columns)],axis = 1)
df = df.dropna(axis = 0).reset_index(drop=True)

Hinweis: Der obige Code entfernt alle Ihre Nullwerte. Wenn Sie Nullwerte möchten, verarbeiten Sie diese zuvor.

Pradeep Singh
quelle
Es ist eine andere Frage Link
Pradeep Singh
0

Es kann hinzugefügt werden, dass '&' verwendet werden kann, um zusätzliche Bedingungen hinzuzufügen, z

df = df[(df.EPS > 2.0) & (df.EPS <4.0)]

Beachten Sie, dass Pandas bei der Bewertung der Aussagen Klammern benötigen.

David
quelle
2
Entschuldigung, aber OP möchte etwas anderes. Übrigens, Ihr Code ist falsch, kehren Sie zurück ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().. Sie müssen Klammern hinzufügen - df = df[(df.EPS > 2.0) & (df.EPS <4.0)]aber es ist auch keine Antwort auf diese Frage.
Jezrael
-1

Aus irgendeinem Grund hat keine der zuvor eingereichten Antworten für mich funktioniert. Diese grundlegende Lösung hat:

df = df[df.EPS >= 0]

Dabei werden natürlich auch Zeilen mit negativen Zahlen gelöscht. Wenn Sie diese möchten, ist es wahrscheinlich klug, dies auch nachträglich hinzuzufügen.

df = df[df.EPS <= 0]
Samthebrand
quelle
Das macht etwas ganz anderes, oder?
AMC
-1

Eine der Lösungen kann sein

df = df[df.isnull().sum(axis=1) <= Cutoff Value]

Ein anderer Weg kann sein

df= df.dropna(thresh=(df.shape[1] - Cutoff_value))

Ich hoffe diese sind nützlich.

Amit Gupta
quelle