Cách thả các hàng của Pandas DataFrame có giá trị trong một cột nhất định là NaN


754

Tôi có cái này DataFramevà chỉ muốn các bản ghi có EPScột không NaN:

>>> df
                 STK_ID  EPS  cash
STK_ID RPT_Date                   
601166 20111231  601166  NaN   NaN
600036 20111231  600036  NaN    12
600016 20111231  600016  4.3   NaN
601009 20111231  601009  NaN   NaN
601939 20111231  601939  2.5   NaN
000001 20111231  000001  NaN   NaN

... tức là một cái gì đó muốn df.drop(....)có được khung dữ liệu kết quả này:

                  STK_ID  EPS  cash
STK_ID RPT_Date                   
600016 20111231  600016  4.3   NaN
601939 20111231  601939  2.5   NaN

Làm thế nào để làm điều đó?



176
df.dropna(subset = ['column1_name', 'column2_name', 'column3_name'])
osa

Câu trả lời:


655

Đừng bỏ qua, chỉ lấy các hàng trong đó EPS không NA:

df = df[df['EPS'].notna()]

470
Tôi khuyên bạn nên sử dụng pandas.notnullthay vìnp.isfinite
Wes McKinney

11
Có bất kỳ lợi thế để lập chỉ mục và sao chép hơn thả?
Robert Muil

9
Lỗi tạo: TypeError: ufunc 'isfinite' không được hỗ trợ cho các loại đầu vào và các đầu vào không thể bị ép buộc an toàn đối với bất kỳ loại được hỗ trợ nào theo quy tắc truyền '' an toàn ''
Philipp Schwarz

4
@ wes-mckinney có thể vui lòng cho tôi biết nếu dropna () là lựa chọn tốt hơn so với pandas.notnull trong trường hợp này? Nếu vậy thì tại sao?
bão

4
@PhilippSchwarz Lỗi này xảy ra nếu cột ( EPStrong ví dụ) chứa chuỗi hoặc các loại khác không thể được tiêu hóa bởi np.isfinite(). Tôi khuyên bạn nên sử dụng pandas.notnull()nó sẽ xử lý việc này một cách hào phóng hơn.
Normanius

902

Câu hỏi này đã được giải quyết, nhưng ...

... cũng xem xét giải pháp được đề xuất bởi Wouter trong nhận xét ban đầu của mình . Khả năng xử lý dữ liệu bị thiếu, bao gồm dropna(), được xây dựng thành gấu trúc một cách rõ ràng. Bên cạnh hiệu suất có khả năng được cải thiện so với thực hiện thủ công, các chức năng này cũng đi kèm với nhiều tùy chọn có thể hữu ích.

In [24]: df = pd.DataFrame(np.random.randn(10,3))

In [25]: df.iloc[::2,0] = np.nan; df.iloc[::4,1] = np.nan; df.iloc[::3,2] = np.nan;

In [26]: df
Out[26]:
          0         1         2
0       NaN       NaN       NaN
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
4       NaN       NaN  0.050742
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
8       NaN       NaN  0.637482
9 -0.310130  0.078891       NaN

In [27]: df.dropna()     #drop all rows that have any NaN values
Out[27]:
          0         1         2
1  2.677677 -1.466923 -0.750366
5 -1.250970  0.030561 -2.678622
7  0.049896 -0.308003  0.823295

In [28]: df.dropna(how='all')     #drop only if ALL columns are NaN
Out[28]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
4       NaN       NaN  0.050742
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
8       NaN       NaN  0.637482
9 -0.310130  0.078891       NaN

In [29]: df.dropna(thresh=2)   #Drop row if it does not have at least two values that are **not** NaN
Out[29]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
5 -1.250970  0.030561 -2.678622
7  0.049896 -0.308003  0.823295
9 -0.310130  0.078891       NaN

In [30]: df.dropna(subset=[1])   #Drop only if NaN in specific column (as asked in the question)
Out[30]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
9 -0.310130  0.078891       NaN

Ngoài ra còn có các tùy chọn khác (Xem tài liệu tại http://pandas.pydata.org/pandas-docs/urdy/generated/pandas.DataFrame.dropna.html ), bao gồm cả việc thả cột thay vì hàng.

Khá tiện dụng!


282
bạn cũng có thể sử dụng df.dropna(subset = ['column_name']). Hy vọng rằng sẽ tiết kiệm cho ít nhất một người thêm 5 giây trong 'tôi đang làm gì sai'. Câu trả lời tuyệt vời, +1
James Tobin

10
@JamesTobin, tôi chỉ mất 20 phút để viết một hàm cho điều đó! Tài liệu chính thức rất khó hiểu: "Các nhãn dọc theo trục khác cần xem xét, ví dụ: nếu bạn thả hàng thì đây sẽ là danh sách các cột cần bao gồm". Tôi không thể hiểu được, ý của họ là gì ...
osa

df.dropna(subset = ['column_name'])chính xác là những gì tôi đang tìm kiếm! Cảm ơn!
amalik2205

123

Tôi biết điều này đã được trả lời, nhưng chỉ vì một giải pháp hoàn toàn cho gấu trúc cho câu hỏi cụ thể này trái ngược với mô tả chung từ Aman (thật tuyệt vời) và trong trường hợp bất kỳ ai khác xảy ra về điều này:

import pandas as pd
df = df[pd.notnull(df['EPS'])]

10
Trên thực tế, câu trả lời cụ thể sẽ là: df.dropna(subset=['EPS'])(dựa trên mô tả chung về Aman, tất nhiên điều này cũng có tác dụng)
joris

2
notnullcũng là những gì Wes (tác giả của Pandas) gợi ý trong bình luận của mình về một câu trả lời khác.
tưởng tượng

Đây có thể là một câu hỏi không. Nhưng khi tôi thực hiện một df [pd.notnull (...) hoặc df.dropna thì chỉ mục sẽ bị hủy. Vì vậy, nếu có một giá trị null trong chỉ mục hàng 10 trong một df có độ dài 200. Khung dữ liệu sau khi chạy hàm thả có các giá trị chỉ mục từ 1 đến 9 và sau đó là 11 đến 200. Dù sao để "lập chỉ mục lại" nó
Aakash Gupta

bạn cũng có thể làm df[pd.notnull(df[df.columns[INDEX]])]nơi INDEXsẽ là cột được đánh số nếu bạn không biết tên
Ocean800

60

Bạn có thể sử dụng điều này:

df.dropna(subset=['EPS'], how='all', inplace=True)

18
how='all'ở đây là dư thừa, vì bạn chỉ đặt lại khung dữ liệu với một trường nên cả hai 'all''any'sẽ có cùng hiệu ứng.
Anton Protopopov

35

Đơn giản nhất trong tất cả các giải pháp:

filtered_df = df[df['EPS'].notnull()]

Giải pháp trên là cách tốt hơn so với sử dụng np.isfinite ()


22

Bạn có thể sử dụng phương thức dataframe notnull hoặc nghịch đảo của isnull hoặc numpy.isnan :

In [332]: df[df.EPS.notnull()]
Out[332]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [334]: df[~df.EPS.isnull()]
Out[334]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [347]: df[~np.isnan(df.EPS)]
Out[347]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN

18

Cách đơn giản và dễ dàng

df.dropna(subset=['EPS'],inplace=True)

nguồn: https://pandas.pydata.org/pandas-docs/urdy/generated/pandas.DataFrame.dropna.html


inplace=Truelà một chủ đề kỳ lạ, và không có tác dụng DataFrame.dropna(). Xem: github.com/pandas-dev/pandas/issues/16529
AMC

Câu trả lời này khác với câu trả lời của @ Joe như thế nào? Ngoài ra, cuối cùng sẽ bị phản đối, tốt nhất là không sử dụng nó.
misantroop

10

một giải pháp khác sử dụng thực tế là np.nan != np.nan:

In [149]: df.query("EPS == EPS")
Out[149]:
                 STK_ID  EPS  cash
STK_ID RPT_Date
600016 20111231  600016  4.3   NaN
601939 20111231  601939  2.5   NaN

2

Phiên bản khác:

df[~df['EPS'].isna()]

Tại sao sử dụng này hơn Series.notna()?
AMC

2

Trong các bộ dữ liệu có số lượng cột lớn thậm chí còn tốt hơn để xem có bao nhiêu cột chứa giá trị null và bao nhiêu cột không.

print("No. of columns containing null values")
print(len(df.columns[df.isna().any()]))

print("No. of columns not containing null values")
print(len(df.columns[df.notna().all()]))

print("Total no. of columns in the dataframe")
print(len(df.columns))

Ví dụ: trong khung dữ liệu của tôi, nó chứa 82 cột, trong đó 19 cột chứa ít nhất một giá trị null.

Hơn nữa, bạn cũng có thể tự động xóa cols và hàng tùy theo đó có nhiều giá trị null hơn
Đây là mã thực hiện điều này một cách thông minh:

df = df.drop(df.columns[df.isna().sum()>len(df.columns)],axis = 1)
df = df.dropna(axis = 0).reset_index(drop=True)

Lưu ý: Mã trên loại bỏ tất cả các giá trị null của bạn. Nếu bạn muốn giá trị null, xử lý chúng trước.



0

Nó có thể được thêm vào tại đó '&' có thể được sử dụng để thêm các điều kiện bổ sung, vd

df = df[(df.EPS > 2.0) & (df.EPS <4.0)]

Lưu ý rằng khi đánh giá các tuyên bố, gấu trúc cần dấu ngoặc đơn.


2
Xin lỗi, nhưng OP muốn đôi khi khác. Btw, mã của bạn là sai, trở lại ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().. Bạn cần thêm dấu ngoặc đơn - df = df[(df.EPS > 2.0) & (df.EPS <4.0)]nhưng cũng không phải là câu trả lời cho câu hỏi này.
jezrael

-1

Vì một số lý do, không có câu trả lời nào được gửi trước đây làm việc cho tôi. Giải pháp cơ bản này đã làm:

df = df[df.EPS >= 0]

Mặc dù tất nhiên điều đó cũng sẽ giảm hàng với số âm. Vì vậy, nếu bạn muốn những thứ đó có lẽ cũng thông minh để thêm cái này sau.

df = df[df.EPS <= 0]

Điều này làm một cái gì đó hoàn toàn khác nhau, không?
AMC

-1

Một trong những giải pháp có thể là

df = df[df.isnull().sum(axis=1) <= Cutoff Value]

Một cách khác có thể là

df= df.dropna(thresh=(df.shape[1] - Cutoff_value))

Tôi hy vọng những điều này là hữu ích.

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.