giảm giá trị vô hạn từ dataframes trong gấu trúc?


219

cách nhanh nhất / đơn giản nhất để giảm giá trị nan và inf / -inf khỏi DataFrame của gấu trúc mà không cần đặt lại là mode.use_inf_as_nullgì? Tôi muốn có thể sử dụng subsetvà các howđối số của dropna, ngoại trừ infcác giá trị được coi là bị thiếu, như:

df.dropna(subset=["col1", "col2"], how="all", with_inf=True)

điều này có thể không Có cách nào để nói dropnađể bao gồm inftrong định nghĩa của nó về các giá trị còn thiếu không?

Câu trả lời:


416

Cách đơn giản nhất là lần đầu tiên replaceđến NaN:

df.replace([np.inf, -np.inf], np.nan)

và sau đó sử dụng dropna:

df.replace([np.inf, -np.inf], np.nan).dropna(subset=["col1", "col2"], how="all")

Ví dụ:

In [11]: df = pd.DataFrame([1, 2, np.inf, -np.inf])

In [12]: df.replace([np.inf, -np.inf], np.nan)
Out[12]:
    0
0   1
1   2
2 NaN
3 NaN

Phương pháp tương tự sẽ làm việc cho một Series.


2
Làm thế nào người ta có thể "trao đổi" các infgiá trị với một định nghĩa trước intnhư 0, trong một cột nhất định?
3kstc

4
@ 3kstc sử dụng .replace(..., 0). Để chỉ thực hiện trên các cột, bạn cập nhật các cột đó tức làdf[cols] = df[cols].replace(..., 0)
Andy Hayden

3
Có lẽ nó đáng để xác định rằng replacenó không hoạt động tại chỗ, vì vậy một cái mới DataFrameđược trả lại
Marco

36

Với bối cảnh tùy chọn, điều này là có thể mà không cần thiết lập vĩnh viễn use_inf_as_na. Ví dụ:

with pd.option_context('mode.use_inf_as_na', True):
    df = df.dropna(subset=['col1', 'col2'], how='all')

Tất nhiên nó có thể được thiết lập để coi infNaNvĩnh viễn với

pd.set_option('use_inf_as_na', True)

Đối với các phiên bản cũ hơn, thay thế use_inf_as_nabằng use_inf_as_null.


6
Đây là câu trả lời dễ đọc nhất và do đó là tốt nhất, mặc dù nó vi phạm trong thư (nhưng không phải về tinh thần) câu hỏi ban đầu.
ijoseph

2
Gấu trúc tính đến (ít nhất) 0,24: use_inf_as_nullđã bị phản đối và sẽ bị xóa trong phiên bản tương lai. Sử dụng use_inf_as_nathay thế. Thêm vào / cập nhật câu trả lời?
Håkon T.

1
Đây là một lựa chọn tốt hơn để coi inflà null ở cấp độ cài đặt toàn cầu thay vì cấp độ hoạt động. Điều này có khả năng tiết kiệm thời gian để đưa ra các giá trị đầu tiên.
TaoPR

15

Đây là một phương pháp khác sử dụng .locđể thay thế inf bằng nan trên Sê-ri:

s.loc[(~np.isfinite(s)) & s.notnull()] = np.nan

Vì vậy, để trả lời cho câu hỏi ban đầu:

df = pd.DataFrame(np.ones((3, 3)), columns=list('ABC'))

for i in range(3): 
    df.iat[i, i] = np.inf

df
          A         B         C
0       inf  1.000000  1.000000
1  1.000000       inf  1.000000
2  1.000000  1.000000       inf

df.sum()
A    inf
B    inf
C    inf
dtype: float64

df.apply(lambda s: s[np.isfinite(s)].dropna()).sum()
A    2
B    2
C    2
dtype: float64

11

Sử dụng (nhanh chóng và đơn giản):

df = df[np.isfinite(df).all(1)]

Câu trả lời này dựa trên câu trả lời của DougR trong một câu hỏi khác. Đây là một mã ví dụ:

import pandas as pd
import numpy as np
df=pd.DataFrame([1,2,3,np.nan,4,np.inf,5,-np.inf,6])
print('Input:\n',df,sep='')
df = df[np.isfinite(df).all(1)]
print('\nDropped:\n',df,sep='')

Kết quả:

Input:
    0
0  1.0000
1  2.0000
2  3.0000
3     NaN
4  4.0000
5     inf
6  5.0000
7    -inf
8  6.0000

Dropped:
     0
0  1.0
1  2.0
2  3.0
4  4.0
6  5.0
8  6.0

7

Một giải pháp khác là sử dụng isinphương pháp này. Sử dụng nó để xác định xem mỗi giá trị là vô hạn hay bị thiếu và sau đó xâu chuỗi allphương thức để xác định xem tất cả các giá trị trong các hàng là vô hạn hay bị thiếu.

Cuối cùng, sử dụng phủ định kết quả đó để chọn các hàng không có tất cả các giá trị vô hạn hoặc thiếu thông qua lập chỉ mục boolean.

all_inf_or_nan = df.isin([np.inf, -np.inf, np.nan]).all(axis='columns')
df[~all_inf_or_nan]

7

Giải pháp trên sẽ sửa đổi các infs không có trong các cột mục tiêu. Để khắc phục điều đó,

lst = [np.inf, -np.inf]
to_replace = {v: lst for v in ['col1', 'col2']}
df.replace(to_replace, np.nan)

3
python 2.7 và cao hơn hỗ trợ nhận thức chính tả:{v: lst for v in cols}
Aryeh Leib Taurog

4

Bạn có thể sử dụng pd.DataFrame.maskvới np.isinf. Bạn nên đảm bảo đầu tiên loạt chuỗi dữ liệu của bạn là tất cả các loại float. Sau đó sử dụng dropnavới logic hiện có của bạn.

print(df)

       col1      col2
0 -0.441406       inf
1 -0.321105      -inf
2 -0.412857  2.223047
3 -0.356610  2.513048

df = df.mask(np.isinf(df))

print(df)

       col1      col2
0 -0.441406       NaN
1 -0.321105       NaN
2 -0.412857  2.223047
3 -0.356610  2.513048
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.