我有一个数据框架,有~300K行和~40列。 我想知道是否有任何行包含空值-并将这些“空”行放入一个单独的数据框架,以便我可以轻松地探索它们。

我可以显式地创建一个蒙版:

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

或者我可以这样做:

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

是否有一种更优雅的方法(定位包含空值的行)?


当前回答

少了4个字符,但多了2个ms

%%timeit
df.isna().T.any()
# 52.4 ms ± 352 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
df.isna().any(axis=1)
# 50 ms ± 423 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

我可能会用axis=1

其他回答

.any()和.all()适用于极端情况,但不适用于寻找特定数量的空值。这里有一个非常简单的方法,我相信你会问。它非常冗长,但功能强大。

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

输出

   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]

然后,如果你像我一样想清除这些行,你只需要这样写:

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

输出:

   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

少了4个字符,但多了2个ms

%%timeit
df.isna().T.any()
# 52.4 ms ± 352 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
df.isna().any(axis=1)
# 50 ms ± 423 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

我可能会用axis=1

def nans(df): return df[df.isnull().any(axis=1)]

然后当你需要它的时候,你可以输入:

nans(your_dataframe)
df1 = df[df.isna().any(axis=1)]

(在pandas数据框架中显示具有一个或多个NaN值的行)

如果你想通过一定数量的空值列来过滤行,你可以使用这个:

df.iloc[df[(df.isnull().sum(axis=1) >= qty_of_nuls)].index]

下面是例子:

你的dataframe:

>>> df = pd.DataFrame([range(4), [0, np.NaN, 0, np.NaN], [0, 0, np.NaN, 0], range(4), [np.NaN, 0, np.NaN, np.NaN]])
>>> df
     0    1    2    3
0  0.0  1.0  2.0  3.0
1  0.0  NaN  0.0  NaN
2  0.0  0.0  NaN  0.0
3  0.0  1.0  2.0  3.0
4  NaN  0.0  NaN  NaN

如果您想选择有两个或多个空值列的行,您可以运行以下命令:

>>> qty_of_nuls = 2
>>> df.iloc[df[(df.isnull().sum(axis=1) >=qty_of_nuls)].index]
     0    1    2   3
1  0.0  NaN  0.0 NaN
4  NaN  0.0  NaN NaN