soltando valores infinitos de marcos de datos en pandas?


219

¿Cuál es la forma más rápida / sencilla de soltar los valores nan e inf / -inf de un DataFrame de pandas sin reiniciar mode.use_inf_as_null? Me gustaría poder usar los argumentos subsety howde dropna, excepto con infvalores que se consideran faltantes, como:

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

¿es posible? ¿Hay alguna manera de decir dropnaque se incluya infen su definición de valores faltantes?

Respuestas:


416

La forma más sencilla sería primero replaceinfs a NaN:

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

y luego usa dropna:

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

Por ejemplo:

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

El mismo método funcionaría para una serie.


2
¿Cómo se puede "intercambiar" los infvalores a un valor predefinido intcomo 0, por ejemplo , en una determinada columna?
3kstc

44
@ 3kstc uso .replace(..., 0). Para hacer solo en las columnas, actualice esas columnas, es decirdf[cols] = df[cols].replace(..., 0)
Andy Hayden el

3
Quizás valga la pena especificar que replaceno funciona en el lugar, por lo que DataFramese devuelve uno nuevo
Marco

36

Con el contexto de la opción, esto es posible sin configurarlo permanentemente use_inf_as_na. Por ejemplo:

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

Por supuesto, se puede configurar para tratar de infforma NaNpermanente con

pd.set_option('use_inf_as_na', True)

Para versiones anteriores, reemplace use_inf_as_nacon use_inf_as_null.


66
Esta es la respuesta más fácil de leer y, en consecuencia, es la mejor, a pesar de que viola en letra (pero no en espíritu) la pregunta original.
ijoseph

2
Pandas a partir de (al menos) 0.24: use_inf_as_nullhabía quedado en desuso y se eliminará en una versión futura. Usar en su use_inf_as_nalugar. ¿Agregar a / actualizar respuesta?
Håkon T.

1
Esta es una mejor opción para tratar infcomo nulos en los niveles de configuración global en lugar del nivel operativo. Esto podría ahorrar tiempo al imputar primero los valores.
TaoPR

15

Aquí hay otro método que usa .locpara reemplazar inf con nan en una Serie:

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

Entonces, en respuesta a la pregunta original:

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

Uso (rápido y simple):

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

Esta respuesta se basa en la respuesta de DougR en otra pregunta. Aquí un código de ejemplo:

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

Resultado:

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

Otra solución más sería utilizar el isinmétodo. Úselo para determinar si cada valor es infinito o falta y luego encadene el allmétodo para determinar si todos los valores en las filas son infinitos o faltantes.

Finalmente, use la negación de ese resultado para seleccionar las filas que no tienen todos los valores infinitos o faltantes a través de la indexación booleana.

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

7

La solución anterior modificará los correos electrónicos infque no están en las columnas de destino. Para remediar eso,

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

3
Python 2.7 y versiones superiores admiten comprensiones de dict:{v: lst for v in cols}
Aryeh Leib Taurog

4

Puedes usar pd.DataFrame.maskcon np.isinf. Primero debe asegurarse de que sus series de marcos de datos sean todas de tipo float. Luego utilícelo dropnacon su lógica existente.

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.