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.