Reemplazo de Pandas o Numpy Nan con None para usar con MysqlDB

128

Estoy tratando de escribir un marco de datos Pandas (o puedo usar una matriz numpy) en una base de datos mysql usando MysqlDB. MysqlDB no parece entender 'nan' y mi base de datos arroja un error que dice que nan no está en la lista de campos. Necesito encontrar una manera de convertir el 'nan' en un NoneType.

¿Algunas ideas?

Rishi
fuente
2
¿No hay ninguna configuración que pueda cambiar en Pandas para que vuelva Noneen NULLlugar de nan?
Nathan Hinchey

Respuestas:

195

@bogatron tiene razón, puede usarlo where, vale la pena señalar que puede hacer esto de forma nativa en pandas:

df1 = df.where(pd.notnull(df), None)

Nota: esto cambia el dtype de todas las columnas a object.

Ejemplo:

In [1]: df = pd.DataFrame([1, np.nan])

In [2]: df
Out[2]: 
    0
0   1
1 NaN

In [3]: df1 = df.where(pd.notnull(df), None)

In [4]: df1
Out[4]: 
      0
0     1
1  None

Nota: lo que no puede hacer es refundir los DataFrames dtypepara permitir todos los tipos de tipos de datos, usando astype, y luego el fillnamétodo DataFrame :

df1 = df.astype(object).replace(np.nan, 'None')

Desafortunadamente, ni esto, ni el uso replace, funcionan con Nonever este problema (cerrado) .


Como acotación al margen, vale la pena señalar que para la mayoría de los casos de uso no es necesario reemplazar NaN con None, consulte esta pregunta sobre la diferencia entre NaN y None en pandas .

Sin embargo, en este caso específico parece que sí (al menos en el momento de esta respuesta).

Andy Hayden
fuente
1
FWIW ... esto también cambiará el dtype de las columnas al objeto, aunque probablemente no te importe
Jeff
@Jeff Gracias por el enlace, ¡extrañamente no pude encontrarlo antes! Pensé que tenía que cambiar el dtype para permitir None, ¡definitivamente vale la pena mencionarlo!
Andy Hayden
útil de usar antes de insertar con Django para evitar que np.nanse convierta en una cadena"nan"
shadi
Advertencia útil. Tiene sentido recorrer solo aquellas columnas que ya son dtypede objecty hacerlo por esas y manejar otros tipos de manera diferente según sea necesario. Idealmente, fillna(None)sería fantástico.
Vishal
83
df = df.replace({np.nan: None})

El crédito es para este tipo por este problema de Github .

EliadL
fuente
4
esta es la mejor respuesta que puede usar df.replace({np.nan: None})como objeto temporal
Matt
17

Puede reemplazar nancon Noneen su matriz numpy:

>>> x = np.array([1, np.nan, 3])
>>> y = np.where(np.isnan(x), None, x)
>>> print y
[1.0 None 3.0]
>>> print type(y[1])
<type 'NoneType'>
bogatron
fuente
2
La única preocupación potencial es el cambio de dtype, x.dtypees dtype('float64'), mientras y.dtypees dtype('object').
Jaime
10

Después de tropezar, esto funcionó para mí:

df = df.astype(object).where(pd.notnull(df),None)
rodney cox
fuente
4

Solo una adición a la respuesta de @Andy Hayden:

Dado que DataFrame.maskes el gemelo opuesto de DataFrame.where, tienen exactamente la misma firma pero con un significado opuesto:

  • DataFrame.wherees útil para reemplazar valores donde la condición es falsa .
  • DataFrame.maskse utiliza para Reemplazar valores donde la condición es Verdadera .

Entonces, en esta pregunta, el uso df.mask(df.isna(), other=None, inplace=True)podría ser más intuitivo.

YaOzI
fuente
2

Otra adición: tenga cuidado al reemplazar múltiplos y convertir el tipo de columna de objeto a flotante . Si quieres estar seguro de que tu None's no cambiará a np.NaN' s, aplica la sugerencia de @ andy-hayden con using pd.where. Ilustración de cómo la sustitución aún puede salir 'mal':

In [1]: import pandas as pd

In [2]: import numpy as np

In [3]: df = pd.DataFrame({"a": [1, np.NAN, np.inf]})

In [4]: df
Out[4]:
     a
0  1.0
1  NaN
2  inf

In [5]: df.replace({np.NAN: None})
Out[5]:
      a
0     1
1  None
2   inf

In [6]: df.replace({np.NAN: None, np.inf: None})
Out[6]:
     a
0  1.0
1  NaN
2  NaN

In [7]: df.where((pd.notnull(df)), None).replace({np.inf: None})
Out[7]:
     a
0  1.0
1  NaN
2  NaN
gaatjeniksaan
fuente
Gracias por agregar esto. Repasando la documentación nuevamente, todavía no puedo entender este comportamiento. De todos modos, esto se puede .replace({np.nan: None})
solucionar
1
Sí, podrías terminar agregando otro replace({np.nan: None}). Mi comentario se agregó para señalar el posible error al reemplazar np.nan. ¡Lo anterior ciertamente me hizo tropezar un poco!
gaatjeniksaan
1

Bastante viejo, pero me encontré con el mismo problema. Intente hacer esto:

df['col_replaced'] = df['col_with_npnans'].apply(lambda x: None if np.isnan(x) else x)
Robin Nemeth
fuente
no funciona si el tipo de datos de la columna es numérico porque Ninguno simplemente se vuelve a convertir en nan (pandas 0.23)
shadi