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!


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

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)]

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!


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)

3
Dies schlägt fehl, wenn die Daten bereits vorhandene NaNs enthalten.
OmerB


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

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

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]

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

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.


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

Versuchen Sie diesen Befehl, es funktioniert perfekt.


-2

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

new_df = df[df.loc[:]!=0].dropna()
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.