upuszczasz nieskończone wartości z ramek danych w pandach?


220

jaki jest najszybszy / najprostszy sposób na usunięcie wartości nan i inf / inf z pandy DataFrame bez resetowania mode.use_inf_as_null? Chciałbym móc używać argumentów subseti howargumentów dropna, z wyjątkiem infwartości uważanych za brakujące, takich jak:

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

czy to możliwe? Czy istnieje sposób, aby powiedzieć, dropnaaby uwzględnić infw definicji brakujących wartości?

Odpowiedzi:


417

Najprostszym sposobem byłoby pierwsze replaceinformacje na NaN:

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

a następnie użyj dropna:

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

Na przykład:

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

Ta sama metoda działałaby dla serii.


2
Jak można „wymienić” infwartości na predefiniowane, inttakie jak 0w określonej kolumnie?
— 3kstc

4
@ 3kstc use .replace(..., 0). Aby to zrobić tylko w kolumnach, zaktualizuj te kolumny, tj.df[cols] = df[cols].replace(..., 0)
— Andy Hayden,

3
Może warto sprecyzować, że replaceto nie działa w miejscu, więc DataFramepowrócił nowy
— Marco

36

W kontekście opcji jest to możliwe bez stałego ustawienia use_inf_as_na. Na przykład:

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

Oczywiście można go ustawić tak, aby traktował go inftak samo jak na NaNstałe

pd.set_option('use_inf_as_na', True)

W starszych wersjach, wymienić use_inf_as_naz use_inf_as_null.


6
Jest to najbardziej czytelna odpowiedź, a zatem najlepsza, mimo że narusza literowe (ale nie duchowe) pierwotne pytanie.
— ijoseph

2
Pandy od (co najmniej) 0,24: use_inf_as_nullzostały wycofane i zostaną usunięte w przyszłej wersji. Użyj use_inf_as_nazamiast tego. Dodaj / zaktualizuj odpowiedź?
— Håkon T.

1
Ten jest lepszym wyborem do traktowania infjako wartości zerowe na poziomach ustawień globalnych zamiast na poziomie operacyjnym. Może to potencjalnie zaoszczędzić czas, przypisując najpierw wartości.
— TaoPR,

15

Oto kolejna metoda polegająca .locna zamianie inf na nan w serii:

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

W odpowiedzi na pierwotne pytanie:

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

Użyj (szybki i prosty):

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

Ta odpowiedź opiera się na odpowiedzi DougR na inne pytanie. Oto przykładowy kod:

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

Wynik:

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

Jeszcze innym rozwiązaniem byłoby użycie tej isinmetody. Użyj go, aby ustalić, czy każda wartość jest nieskończona, czy jej brakuje, a następnie połącz allmetodę, aby ustalić, czy wszystkie wartości w wierszach są nieskończone, czy ich brakuje.

Na koniec użyj negacji tego wyniku, aby wybrać wiersze, które nie mają wszystkich nieskończonych lub brakujących wartości, poprzez indeksowanie boolowskie.

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

7

Powyższe rozwiązanie zmodyfikuje te inf, które nie znajdują się w kolumnach docelowych. Aby temu zaradzić,

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

3
Python 2.7 i wyższe rozumieją dyktando wsparcia:{v: lst for v in cols}
— Aryeh Leib Taurog

4

Możesz używać pd.DataFrame.maskz np.isinf. Najpierw upewnij się, że wszystkie serie ramek danych są typu float. Następnie użyj dropnaz istniejącą logiką.

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.