Wie wähle ich Zeilen mit einer oder mehreren Nullen aus einem Pandas DataFrame aus, ohne Spalten explizit aufzulisten?

231

Ich habe einen Datenrahmen mit ~ 300K Zeilen und ~ 40 Spalten. Ich möchte herausfinden, ob Zeilen Nullwerte enthalten - und diese 'Null'-Zeilen in einen separaten Datenrahmen einfügen, damit ich sie leicht untersuchen kann.

Ich kann eine Maske explizit erstellen:

mask = False
for col in df.columns: 
    mask = mask | df[col].isnull()
dfnulls = df[mask]

Oder ich kann so etwas machen wie:

df.ix[df.index[(df.T == np.nan).sum() > 1]]

Gibt es eine elegantere Möglichkeit, dies zu tun (Zeilen mit Nullen darin zu suchen)?

Lev Selector
quelle

Antworten:

381

[Aktualisiert, um sich an die Moderne anzupassen pandas, die isnullals Methode von DataFrames ..]

Sie können eine boolesche Reihe verwenden isnullund anyerstellen, um sie in Ihren Frame zu indizieren:

>>> df = pd.DataFrame([range(3), [0, np.NaN, 0], [0, 0, np.NaN], range(3), range(3)])
>>> df.isnull()
       0      1      2
0  False  False  False
1  False   True  False
2  False  False   True
3  False  False  False
4  False  False  False
>>> df.isnull().any(axis=1)
0    False
1     True
2     True
3    False
4    False
dtype: bool
>>> df[df.isnull().any(axis=1)]
   0   1   2
1  0 NaN   0
2  0   0 NaN

[Für ältere pandas:]

Sie können die Funktion isnullanstelle der Methode verwenden:

In [56]: df = pd.DataFrame([range(3), [0, np.NaN, 0], [0, 0, np.NaN], range(3), range(3)])

In [57]: df
Out[57]: 
   0   1   2
0  0   1   2
1  0 NaN   0
2  0   0 NaN
3  0   1   2
4  0   1   2

In [58]: pd.isnull(df)
Out[58]: 
       0      1      2
0  False  False  False
1  False   True  False
2  False  False   True
3  False  False  False
4  False  False  False

In [59]: pd.isnull(df).any(axis=1)
Out[59]: 
0    False
1     True
2     True
3    False
4    False

was zu dem eher kompakten führt:

In [60]: df[pd.isnull(df).any(axis=1)]
Out[60]: 
   0   1   2
1  0 NaN   0
2  0   0 NaN
DSM
quelle
75
def nans(df): return df[df.isnull().any(axis=1)]

wann immer Sie es brauchen, können Sie Folgendes eingeben:

nans(your_dataframe)
Roko Mijic
quelle
1
df[df.isnull().any(axis=1)]funktioniert aber wirft UserWarning: Boolean Series key will be reindexed to match DataFrame index.. Wie schreibt man dies expliziter und so um, dass diese Warnmeldung nicht ausgelöst wird?
Vishal
3
@vishal Ich denke, alles was Sie tun müssten, ist loc wie folgt hinzuzufügen; df.loc[df.isnull().any(axis=1)]
James Draper
2
Nebenbei bemerkt - Sie sollten Ihre anonymen (Lambda) Funktionen nicht benennen . Verwenden Sie immer eine def-Anweisung anstelle einer Zuweisungsanweisung, die einen Lambda-Ausdruck direkt an einen Bezeichner bindet.
Donrondadon
0

.any()und .all()eignen sich hervorragend für Extremfälle, jedoch nicht, wenn Sie nach einer bestimmten Anzahl von Nullwerten suchen. Hier ist eine äußerst einfache Möglichkeit, das zu tun, was Sie meiner Meinung nach verlangen. Es ist ziemlich ausführlich, aber funktional.

import pandas as pd
import numpy as np

# Some test data frame
df = pd.DataFrame({'num_legs':          [2, 4,      np.nan, 0, np.nan],
                   'num_wings':         [2, 0,      np.nan, 0, 9],
                   'num_specimen_seen': [10, np.nan, 1,     8, np.nan]})

# Helper : Gets NaNs for some row
def row_nan_sums(df):
    sums = []
    for row in df.values:
        sum = 0
        for el in row:
            if el != el: # np.nan is never equal to itself. This is "hacky", but complete.
                sum+=1
        sums.append(sum)
    return sums

# Returns a list of indices for rows with k+ NaNs
def query_k_plus_sums(df, k):
    sums = row_nan_sums(df)
    indices = []
    i = 0
    for sum in sums:
        if (sum >= k):
            indices.append(i)
        i += 1
    return indices

# test
print(df)
print(query_k_plus_sums(df, 2))

Ausgabe

   num_legs  num_wings  num_specimen_seen
0       2.0        2.0               10.0
1       4.0        0.0                NaN
2       NaN        NaN                1.0
3       0.0        0.0                8.0
4       NaN        9.0                NaN
[2, 4]

Wenn Sie dann wie ich sind und diese Zeilen löschen möchten, schreiben Sie einfach Folgendes:

# drop the rows from the data frame
df.drop(query_k_plus_sums(df, 2),inplace=True)
# Reshuffle up data (if you don't do this, the indices won't reset)
df = df.sample(frac=1).reset_index(drop=True)
# print data frame
print(df)

Ausgabe:

   num_legs  num_wings  num_specimen_seen
0       4.0        0.0                NaN
1       0.0        0.0                8.0
2       2.0        2.0               10.0
Ryan Cocuzzo
quelle