Wie lösche ich eine Spalte, die in Pandas nur Nullen enthält?

87

Ich habe derzeit einen Datenrahmen, der aus Spalten mit Einsen und Nullen als Werten besteht. Ich möchte die Spalten durchlaufen und diejenigen löschen, die nur aus Nullen bestehen. Folgendes habe ich bisher versucht:

ones = []
zeros = []
for year in years:
    for i in range(0,599):
        if year[str(i)].values.any() == 1:
            ones.append(i)
        if year[str(i)].values.all() == 0:
            zeros.append(i)
    for j in ones:
        if j in zeros:
            zeros.remove(j)
    for q in zeros:
        del year[str(q)]

In welchen Jahren ist eine Liste von Datenrahmen für die verschiedenen Jahre, die ich analysiere, Einsen bestehen aus Spalten mit einer Eins und Nullen ist eine Liste von Spalten, die alle Nullen enthalten. Gibt es eine bessere Möglichkeit, eine Spalte basierend auf einer Bedingung zu löschen? Aus irgendeinem Grund muss ich prüfen, ob die Einsenspalten auch in der Nullenliste enthalten sind, und sie aus der Nullenliste entfernen, um eine Liste aller Nullspalten zu erhalten.

user2587593
quelle
Mögliches Duplikat des Löschens
Shihe Zhang

Antworten:

213
df.loc[:, (df != 0).any(axis=0)]

Hier ist eine Aufschlüsselung der Funktionsweise:

In [74]: import pandas as pd

In [75]: df = pd.DataFrame([[1,0,0,0], [0,0,1,0]])

In [76]: df
Out[76]: 
   0  1  2  3
0  1  0  0  0
1  0  0  1  0

[2 rows x 4 columns]

df != 0Erstellt einen booleschen DataFrame, der True dfist, wobei er ungleich Null ist:

In [77]: df != 0
Out[77]: 
       0      1      2      3
0   True  False  False  False
1  False  False   True  False

[2 rows x 4 columns]

(df != 0).any(axis=0)Gibt eine boolesche Reihe zurück, die angibt, welche Spalten Einträge ungleich Null haben. (Die anyOperation aggregiert Werte entlang der 0-Achse - dh entlang der Zeilen - zu einem einzigen Booleschen Wert. Daher ist das Ergebnis ein Boolescher Wert für jede Spalte.)

In [78]: (df != 0).any(axis=0)
Out[78]: 
0     True
1    False
2     True
3    False
dtype: bool

Und df.lockann verwendet werden, um diese Spalten auszuwählen:

In [79]: df.loc[:, (df != 0).any(axis=0)]
Out[79]: 
   0  2
0  1  0
1  0  1

[2 rows x 2 columns]

Um die Nullspalten zu "löschen", weisen Sie Folgendes neu zu df:

df = df.loc[:, (df != 0).any(axis=0)]
unutbu
quelle
Ich versuche dies, um eine Spalte zu löschen, wenn sie entweder 0 oder 1 enthält und ein Fehler auftritt: df = df.loc [:, (df! = 0 & df! = 1) .any (axis = 0)]
Morpheus
1
df.loc[:, (~df.isin([0,1])).any(axis=0)]würde auch funktionieren.
Unutbu
1
@IgorFobia: Viele Dinge sind falsch, ohne 0 zu sein. Zum Beispiel leere Zeichenfolgen oder Keine oder NaN. Um den Unterschied zu zeigen, wenn df = pd.DataFrame([[np.nan]*10]), dann df.loc[:, df.any(axis=0)]eine leere Datenrahmen zurück, während df.loc[:, (df != 0).any(axis=0)]kehrt einen Datenrahmen mit 10 Spalten.
Unutbu
4
Ich glaube, es ist einfacher zu verstehen, ob wir prüfen, ob eine Bedingung wahr ist, anstatt zu prüfen, ob eine Bedingung, die nicht wahr ist, niemals nicht erfüllt ist. Ich denke (df == 0).all(axis=0)ist einfacher.
Ryszard Cetnarski
2
Danke für den Zusammenbruch. Es machte die Dinge sehr klar.
Regi Mathew
7

Hier ist eine alternative Art zu verwenden ist

df.replace(0,np.nan).dropna(axis=1,how="all")

Verglichen mit der Lösung von unutbu ist dieser Weg offensichtlich langsamer:

%timeit df.loc[:, (df != 0).any(axis=0)]
652 µs ± 5.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.replace(0,np.nan).dropna(axis=1,how="all")
1.75 ms ± 9.49 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Jeremy Z.
quelle
0

Für den Fall, dass Sie eine aussagekräftigere Methode zum Abrufen der Nullspaltennamen wünschen, damit Sie sie drucken / protokollieren und an Ort und Stelle nach ihren Namen ablegen können :

zero_cols = [ col for col, is_zero in ((df == 0).sum() == df.shape[0]).items() if is_zero ]
df.drop(zero_cols, axis=1, inplace=True)

Einige brechen zusammen:

# a pandas Series with {col: is_zero} items
# is_zero is True when the number of zero items in that column == num_all_rows
(df == 0).sum() == df.shape[0])

# a list comprehension of zero_col_names is built from the_series
[ col for col, is_zero in the_series.items() if is_zero ]
mork
quelle