Bagaimana memilih baris dengan satu atau lebih null dari panda DataFrame tanpa mencantumkan kolom secara eksplisit?

234

Saya memiliki dataframe dengan ~ 300K baris dan ~ 40 kolom. Saya ingin mencari tahu apakah ada baris yang berisi nilai null - dan letakkan baris 'null' ini ke dalam kerangka data terpisah sehingga saya bisa menjelajahinya dengan mudah.

Saya dapat membuat topeng secara eksplisit:

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

Atau saya dapat melakukan sesuatu seperti:

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

Apakah ada cara yang lebih elegan untuk melakukannya (menemukan baris dengan nol di dalamnya)?

Lev Selector
sumber

Jawaban:

384

[Diperbarui untuk beradaptasi dengan modern pandas, yang memiliki isnullmetode DataFrame...]

Anda dapat menggunakan isnulldan anymembangun Seri boolean dan menggunakannya untuk mengindeks ke dalam bingkai Anda:

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

[Untuk yang lebih tua pandas:]

Anda bisa menggunakan fungsi isnullalih-alih metode:

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

mengarah ke yang agak kompak:

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

maka kapan pun Anda membutuhkannya Anda dapat mengetik:

nans(your_dataframe)
Roko Mijic
sumber
1
df[df.isnull().any(axis=1)]bekerja tetapi melempar UserWarning: Boolean Series key will be reindexed to match DataFrame index.. Bagaimana seseorang menulis ulang ini secara lebih eksplisit dan dengan cara yang tidak memicu pesan peringatan itu?
Vishal
3
@vishal Saya pikir semua yang perlu Anda lakukan adalah menambahkan loc seperti ini; df.loc[df.isnull().any(axis=1)]
James Draper
2
Selain itu - Anda tidak boleh menyebutkan fungsi anonim (lambda) Anda. Selalu gunakan pernyataan def bukannya pernyataan penugasan yang mengikat ekspresi lambda langsung ke pengenal.
donrondadon
0

.any()dan .all()bagus untuk kasus-kasus ekstrem, tetapi tidak ketika Anda sedang mencari sejumlah nilai null tertentu. Inilah cara yang sangat sederhana untuk melakukan apa yang saya yakin Anda minta. Ini sangat verbose, tetapi fungsional.

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

Keluaran

   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]

Kemudian, jika Anda seperti saya dan ingin menghapus baris-baris itu, Anda cukup menulis ini:

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

Keluaran:

   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
sumber