Làm cách nào để chọn các hàng có một hoặc nhiều null từ DataFrame mà không liệt kê các cột rõ ràng?


234

Tôi có một khung dữ liệu với ~ 300K hàng và ~ 40 cột. Tôi muốn tìm hiểu xem có bất kỳ hàng nào chứa giá trị null không - và đặt các hàng 'null' này vào một khung dữ liệu riêng biệt để tôi có thể khám phá chúng dễ dàng.

Tôi có thể tạo một mặt nạ rõ ràng:

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

Hoặc tôi có thể làm một cái gì đó như:

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

Có cách nào thanh lịch hơn để làm điều đó (định vị các hàng có null trong đó) không?

Câu trả lời:


384

[Cập nhật để thích ứng với hiện đại pandas, có isnullphương pháp DataFrames ..]

Bạn có thể sử dụng isnullanyđể xây dựng một chuỗi boolean và sử dụng nó để lập chỉ mục vào khung của bạn:

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

[Dành cho người lớn tuổi pandas:]

Bạn có thể sử dụng hàm isnullthay vì phương thức:

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

dẫn đến khá nhỏ gọn:

In [60]: df[pd.isnull(df).any(axis=1)]
Out[60]: 
   0   1   2
1  0 NaN   0
2  0   0 NaN

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

sau đó khi nào bạn cần, bạn có thể gõ:

nans(your_dataframe)

1
df[df.isnull().any(axis=1)]làm việc nhưng ném UserWarning: Boolean Series key will be reindexed to match DataFrame index.. Làm thế nào để người ta viết lại điều này rõ ràng hơn và theo cách không kích hoạt thông điệp cảnh báo đó?
Vishal

3
@vishal Tôi nghĩ tất cả những gì bạn cần làm là thêm loc như thế này; df.loc[df.isnull().any(axis=1)]
James Draper

2
Ở một bên - bạn không nên đặt tên các chức năng ẩn danh (lambda) của mình. Luôn sử dụng câu lệnh def thay vì câu lệnh gán liên kết trực tiếp biểu thức lambda với mã định danh.
donrondadon

0

.any().all()rất tốt cho các trường hợp cực đoan, nhưng không phải khi bạn đang tìm kiếm một số giá trị null cụ thể. Đây là một cách cực kỳ đơn giản để làm những gì tôi tin rằng bạn đang yêu cầu. Nó khá dài dòng, nhưng đầy đủ chức năng.

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

Đầu ra

   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]

Sau đó, nếu bạn giống tôi và muốn xóa những hàng đó, bạn chỉ cần viết điều này:

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

Đầu ra:

   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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.