Löschen Sie Zeilen mit allen Nullen im Pandas-Datenrahmen

101

Ich kann pandas dropna()Funktionen verwenden, um Zeilen mit einigen oder allen Spalten zu entfernen, die als NA's festgelegt sind. Gibt es eine äquivalente Funktion zum Löschen von Zeilen mit allen Spalten mit dem Wert 0?

P   kt  b   tt  mky depth
1   0   0   0   0   0
2   0   0   0   0   0
3   0   0   0   0   0
4   0   0   0   0   0
5   1.1 3   4.5 2.3 9.0

In diesem Beispiel möchten wir die ersten 4 Zeilen aus dem Datenrahmen löschen.

Vielen Dank!

user308827
quelle
Zur Verdeutlichung sind dies zwei Fragen. Erstens , um Spalten mit allen Werten als 0 zu löschen . Aber auch für eine Funktion , die dropna () entspricht und Spalten mit einem beliebigen Wert als 0 löscht .
Alchemie

Antworten:

110

Es stellt sich heraus, dass dies auf vektorisierte Weise gut ausgedrückt werden kann:

> df = pd.DataFrame({'a':[0,0,1,1], 'b':[0,1,0,1]})
> df = df[(df.T != 0).any()]
> df
   a  b
1  0  1
2  1  0
3  1  1
U2EF1
quelle
6
Schön, aber ich denke, Sie können Negation mitdf = df[(df.T != 0).any()]
Akavall
1
@ Akavall Viel besser!
U2EF1
1
Nur eine Anmerkung: OP wollte fallen lassen rows with all columns having value 0, aber man kann auf die allMethode schließen .
Paulochf
1
Alle diese Antworten erklären, wie wir Zeilen mit allen Nullen löschen können. Ich wollte jedoch Zeilen mit 0 in der ersten Spalte löschen. Mit Hilfe aller Diskussionen und Antworten in diesem Beitrag habe ich dies getan, indem ich df.loc [df.iloc [:, 0]! = 0] gemacht habe. Ich wollte nur teilen, weil dieses Problem mit dieser Frage zusammenhängt !!
Hemanta
2
Die Transponierung ist nicht erforderlich, any () kann eine Achse als Parameter verwenden. Das funktioniert also: df = df [df.any (Achse = 1)]
Rahul Jha
127

Einzeiler. Keine Transponierung erforderlich:

df.loc[~(df==0).all(axis=1)]

Und für diejenigen, die Symmetrie mögen, funktioniert dies auch ...

df.loc[(df!=0).any(axis=1)]
8one6
quelle
1
Der Kürze halber (und meiner Meinung nach der Klarheit des Zwecks) kombinieren Sie dies und Akavalls Kommentar : df.loc[(df != 0).any(1)]. Zusammenarbeit!
Dan Allan
1
+1, 30% schneller als die Transponierung - 491 bis 614 Mikrosekunden, und ich mag das, axis=1weil es explizit ist; mehr pythonisch meiner Meinung nach
gt6989b
Einige Erwähnungen sollten den Unterschied zwischen der Verwendung von .all und .any erwähnen, da in der ursprünglichen Frage die Gleichwertigkeit von dropna erwähnt wurde. Wenn Sie alle Zeilen mit einer Spalte löschen möchten, die eine Null enthält, müssen Sie die obigen Antworten .all und .any umkehren. Ich habe eine Weile gebraucht, um dies zu realisieren, als ich nach dieser Funktionalität suchte.
Zak Keirn
Dies funktioniert nicht für mich, gibt mir aber genau das gleiche zurückdf
Robvh
Gibt es eine "Inplace" -Version davon? Ich sehe, dass, um Zeilen in einem df zu löschen, wie es das OP angefordert hat, dies sein muss df = df.loc[(df!=0).all(axis=1)]und df = df.loc[(df!=0).any(axis=1)]Zeilen mit beliebigen Nullen gelöscht werden müssen, wie es das tatsächliche Äquivalent zu dropna () wäre.
Alchemie
19

Ich schaue diese Frage ungefähr einmal im Monat nach und muss immer die beste Antwort aus den Kommentaren herausfinden:

df.loc[(df!=0).any(1)]

Vielen Dank, Dan Allan!

Die Unfun Cat
quelle
2
Kein Graben erforderlich. @ 8one6 hat dies bereits 2014 in seine Antwort aufgenommen, die besagt: "Und für diejenigen, die Symmetrie mögen ...".
Rahul Murmuria
14

Ersetzen Sie die Nullen durch nanund löschen Sie die Zeilen mit allen Einträgen als nan. Danach durch nanNullen ersetzen .

import numpy as np
df = df.replace(0, np.nan)
df = df.dropna(how='all', axis=0)
df = df.replace(np.nan, 0)
stapelweise
quelle
3
Dies schlägt fehl, wenn die Daten bereits vorhandene NaNs enthalten.
OmerB
9

Ich denke, diese Lösung ist die kürzeste:

df= df[df['ColName'] != 0]
Ikbel Benab
quelle
1
Und es ist auch vorhanden!
Max Kleiner
7

Einige Lösungen, die ich beim Nachschlagen als hilfreich empfunden habe, insbesondere bei größeren Datenmengen:

df[(df.sum(axis=1) != 0)]       # 30% faster 
df[df.values.sum(axis=1) != 0]  # 3X faster 

Fahren Sie mit dem Beispiel von @ U2EF1 fort:

In [88]: df = pd.DataFrame({'a':[0,0,1,1], 'b':[0,1,0,1]})

In [91]: %timeit df[(df.T != 0).any()]
1000 loops, best of 3: 686 µs per loop

In [92]: df[(df.sum(axis=1) != 0)]
Out[92]: 
   a  b
1  0  1
2  1  0
3  1  1

In [95]: %timeit df[(df.sum(axis=1) != 0)]
1000 loops, best of 3: 495 µs per loop

In [96]: %timeit df[df.values.sum(axis=1) != 0]
1000 loops, best of 3: 217 µs per loop

Auf einem größeren Datensatz:

In [119]: bdf = pd.DataFrame(np.random.randint(0,2,size=(10000,4)))

In [120]: %timeit bdf[(bdf.T != 0).any()]
1000 loops, best of 3: 1.63 ms per loop

In [121]: %timeit bdf[(bdf.sum(axis=1) != 0)]
1000 loops, best of 3: 1.09 ms per loop

In [122]: %timeit bdf[bdf.values.sum(axis=1) != 0]
1000 loops, best of 3: 517 µs per loop
Uhr
quelle
Passieren schlimme Dinge, wenn Ihre Zeile eine -1 und eine 1 enthält?
Rhys Ulerich
Natürlich würde die Summe nicht funktionieren, wenn Sie gleiche Zeilen hätten, die sich zu 0 addieren. Hier ist eine schnelle Problemumgehung für das, was nur geringfügig langsamer ist: df[~(df.values.prod(axis=1) == 0) | ~(df.values.sum(axis=1)==0)]
Clocker
Die Funktion prod () löst nichts. Wenn Sie eine 0 in der Zeile haben, die 0 zurückgibt. Wenn Sie eine Zeile wie diese behandeln müssen: [-1, -0,5, 0, 0,5, 1], funktioniert keine Ihrer Lösungen.
Rahul Murmuria
Hier ist eine korrekte Version, die 3x schneller funktioniert als die akzeptierte Antwort:bdf[np.square(bdf.values).sum(axis=1) != 0]
Rahul Murmuria
5
import pandas as pd

df = pd.DataFrame({'a' : [0,0,1], 'b' : [0,0,-1]})

temp = df.abs().sum(axis=1) == 0      
df = df.drop(temp)

Ergebnis:

>>> df
   a  b
2  1 -1
Akavall
quelle
Hat bei mir mit einem 1-spaltigen Datenrahmen nicht funktioniert. GotValueError: labels [True ... ] not contained in matrix
The Unfun Cat
statt zu df = df.drop(temp)benutzendf = df.drop(df[temp].index)
Douglas Ferreira
3

Mit einer Schnellfunktion lambdakönnen Sie überprüfen, ob alle Werte in einer bestimmten Zeile vorhanden sind 0. Dann können Sie das Ergebnis dieser Anwendung verwenden, lambdaum nur die Zeilen auszuwählen, die dieser Bedingung entsprechen oder nicht entsprechen:

import pandas as pd
import numpy as np

np.random.seed(0)

df = pd.DataFrame(np.random.randn(5,3), 
                  index=['one', 'two', 'three', 'four', 'five'],
                  columns=list('abc'))

df.loc[['one', 'three']] = 0

print df
print df.loc[~df.apply(lambda row: (row==0).all(), axis=1)]

Ausbeuten:

              a         b         c
one    0.000000  0.000000  0.000000
two    2.240893  1.867558 -0.977278
three  0.000000  0.000000  0.000000
four   0.410599  0.144044  1.454274
five   0.761038  0.121675  0.443863

[5 rows x 3 columns]
             a         b         c
two   2.240893  1.867558 -0.977278
four  0.410599  0.144044  1.454274
five  0.761038  0.121675  0.443863

[3 rows x 3 columns]
8one6
quelle
1

Eine andere Alternative:

# Is there anything in this row non-zero?
# df != 0 --> which entries are non-zero? T/F
# (df != 0).any(axis=1) --> are there 'any' entries non-zero row-wise? T/F of rows that return true to this statement.
# df.loc[all_zero_mask,:] --> mask your rows to only show the rows which contained a non-zero entry.
# df.shape to confirm a subset.

all_zero_mask=(df != 0).any(axis=1) # Is there anything in this row non-zero?
df.loc[all_zero_mask,:].shape
bmc
quelle
0

Für mich hat dieser Code: df.loc[(df!=0).any(axis=0)] nicht funktioniert. Es wurde der genaue Datensatz zurückgegeben.

Stattdessen habe ich df.loc[:, (df!=0).any(axis=0)]alle Spalten mit 0-Werten im Datensatz verwendet und gelöscht

Die Funktion .all()hat alle Spalten gelöscht, in denen sich in meinem Datensatz Nullwerte befinden.

Denisa
quelle
-1
df = df [~( df [ ['kt'  'b'   'tt'  'mky' 'depth', ] ] == 0).all(axis=1) ]

Versuchen Sie diesen Befehl, es funktioniert perfekt.

Kumar Prasanna
quelle
-2

So löschen Sie alle Spalten mit den Werten 0 in einer beliebigen Zeile:

new_df = df[df.loc[:]!=0].dropna()
Yapi
quelle