Reemplace los valores inválidos con Ninguno en Pandas DataFrame

¿Hay algún método para reemplazar valores con None en Pandas en Python?

Puede usar df.replace('pre', 'post') y puede reemplazar un valor por otro, pero esto no se puede hacer si desea reemplazar el valor por None , que si lo intenta, obtiene un resultado extraño.

Así que aquí hay un ejemplo:

 df = DataFrame(['-',3,2,5,1,-5,-1,'-',9]) df.replace('-', 0) 

lo que devuelve un resultado exitoso.

Pero,

 df.replace('-', None) 

que devuelve un resultado siguiente:

 0 0 - // this isn't replaced 1 3 2 2 3 5 4 1 5 -5 6 -1 7 -1 // this is changed to `-1`... 8 9 

¿Por qué se devuelve un resultado tan extraño?

Ya que quiero verter este dataframe en la base de datos MySQL, no puedo poner los valores de NaN en ningún elemento de mi dataframe y en su lugar quiero poner None . Seguramente, primero puede cambiar '-' a NaN y luego convertir NaN a None , pero quiero saber por qué el dataframe actúa de una manera tan terrible.

En realidad, en versiones posteriores de pandas esto dará un TypeError:

 df.replace('-', None) TypeError: If "to_replace" and "value" are both None then regex must be a mapping 

Puedes hacerlo pasando una lista o un diccionario:

 In [11]: df.replace('-', df.replace(['-'], [None]) # or .replace('-', {0: None}) Out[11]: 0 0 None 1 3 2 2 3 5 4 1 5 -5 6 -1 7 None 8 9 

Pero recomiendo usar NaNs en lugar de Ninguno:

 In [12]: df.replace('-', np.nan) Out[12]: 0 0 NaN 1 3 2 2 3 5 4 1 5 -5 6 -1 7 NaN 8 9 

where es probablemente lo que buscas Asi que

 data=data.where(data=='-', None) 

De los documentos panda :

where [devuelve] un objeto de la misma forma que yo y cuyas entradas correspondientes son de sí mismo donde cond es Verdadero y de otro modo son de otro)

Prefiero la solución utilizando replace con un dict debido a su simplicidad y elegancia:

 df.replace({'-': None}) 

También puedes tener más reemplazos:

 df.replace({'-': None, 'None': None}) 

E incluso para los reemplazos más grandes, siempre es obvio y claro lo que se reemplaza por lo que, en mi opinión, es mucho más difícil para las listas largas.

 df = pd.DataFrame(['-',3,2,5,1,-5,-1,'-',9]) df = df.where(df!='-', None) 

La configuración de valores nulos se puede hacer con np.nan :

 import numpy as np df.replace('-', np.nan) 

La ventaja es que df.last_valid_index() reconoce que estos no son válidos.

Antes de continuar con esta publicación, es importante comprender la diferencia entre NaN y Ninguna . Uno es un tipo flotante, el otro es un tipo de objeto. Las pandas son más adecuadas para trabajar con tipos escalares, ya que muchos métodos en estos tipos pueden vectorizarse. Las pandas intentan manejar Ninguno y NaN consistentemente, pero NumPy no puede.

Mi sugerencia ( y la de Andy ) es quedarse con NaN.

(v0.24 +) Una mejor solución para CSV / Excel Data: na_values=['-']

Si cargó estos datos de CSV / Excel, tengo buenas noticias para usted. Puede anular esto en la raíz durante la carga de datos en lugar de tener que escribir una corrección con código como un paso posterior.

La mayoría de las funciones pd.read_* (como read_csv y read_excel ) aceptan un atributo na_values .

file.csv

 A,B -,1 3,- 2,- 5,3 1,-2 -5,4 -1,-1 -,0 9,0 

Ahora, para convertir los - caracteres en NaNs, haz,

 import pandas as pd df = pd.read_csv('file.csv', na_values=['-']) df AB 0 NaN 1.0 1 3.0 NaN 2 2.0 NaN 3 5.0 3.0 4 1.0 -2.0 5 -5.0 4.0 6 -1.0 -1.0 7 NaN 0.0 8 9.0 0.0 

Y similar para otras funciones / formatos de archivo.

PS: En v0.24 +, puede conservar el tipo entero incluso si su columna tiene NaNs (sí, hable acerca de tener el pastel y comérselo también). Puede especificar dtype='Int32'

 df = pd.read_csv('file.csv', na_values=['-'], dtype='Int32') df AB 0 NaN 1 1 3 NaN 2 2 NaN 3 5 3 4 1 -2 5 -5 4 6 -1 -1 7 NaN 0 8 9 0 df.dtypes A Int32 B Int32 dtype: object 

El tipo dtype no es un tipo int convencional … sino más bien, un tipo entero que acepta valores nulos. Hay otras opciones.


Manejo de datos numéricos: pd.to_numeric con errors='coerce

Si está tratando con datos numéricos, una solución más rápida es usar pd.to_numeric con el argumento de errors='coerce' , que obliga a los valores no válidos (valores que no se pueden convertir a números) a NaN.

 pd.to_numeric(df['A'], errors='coerce') 0 NaN 1 3.0 2 2.0 3 5.0 4 1.0 5 -5.0 6 -1.0 7 NaN 8 9.0 Name: A, dtype: float64 

Para retener el dtype entero (nullable), use

 pd.to_numeric(df['A'], errors='coerce').astype('Int32') 0 NaN 1 3 2 2 3 5 4 1 5 -5 6 -1 7 NaN 8 9 Name: A, dtype: Int32 

Para forzar múltiples columnas, use apply :

 df[['A', 'B']].apply(pd.to_numeric, errors='coerce').astype('Int32') AB 0 NaN 1 1 3 NaN 2 2 NaN 3 5 3 4 1 -2 5 -5 4 6 -1 -1 7 NaN 0 8 9 0 

… y volver a asignar el resultado después.

Más información se puede encontrar en esta respuesta .