Cómo encontrar valores NaN en un DataFrame Pandas de Python y modificarlos

Cuando trabajamos con un DataFrame, especialmente si es extenso, podemos tener problemas con lo valores NaN. Los NaN (“Not a Number“) son valores vacíos no computables que debemos tratar en nuestros conjuntos de datos antes de trabajar con ellos. Veremos algunos códigos de Python que pueden ayudarnos a trabajar con los NaN.

Este código nos devolverá True si hay algún valor NaN en nuestro DataFrame.

df.isnull().values.any()

En mi caso (DataFrame llamado “spy”) si hay valores NaN:

Podemos obtener un DataFrame lógico completo indicando si el valor es NaN o no con el siguiente código:

df.isnull()

El resultado no es muy cómodo de visualizar si el DataFrame es grande como es mi caso:

Este código nos dirá en qué columnas se encuentran nuestros valores NaN:

df.isnull().any()

El resultado es interesante si tienes pocas columnas. En mi caso tengo 212 atributos por lo que tampoco no es fácil visualizarlo:

Si queremos ver cuántos NaN hay en cada columna cambiamos el .any() por un .sum() al código:

df.isnull().sum()

El resultado es igualmente difícil de visualizar con 212 atributos:

Este código nos dirá cuántos NaN tenemos en total, de forma que podemos entrever el problema al que nos enfrentamos:

df.isnull().sum().sum()

En mi caso solo hay un valor NaN:

Para afinar en nuestra búsqueda del valor NaN perdido podemos extraer las filas (la fila en mi caso) que contenga valores NaN:

nan_rows = df[df.isnull().any(1)]

Este código nos crea un nuevo DataFrame con las filas que contienen valores NaN. En mi caso debe decirme, usando después isnull() sobre el nuevo DataFrame creado, qué fila es la que contiene el valor NaN:

Ya tenemos fila ganadora: mi valor NaN se encuentra en la fila 917 del DataFrame.

Para localizar qué columna tiene el valor NaN basta con escribir el siguiente código:

df.columns[df.isnull().any()]

El resultado es la columna ganadora:

Por tanto mi valor NaN se encuentra en la posición [‘322’][917] de mi DataFrame.

¿Se podía haber realizado toda la búsqueda del valor NaN desde el principio de forma más fácil? Si, nos podíamos haber ahorrado toda la “exploración” si directamente hubiésemos ido a por la localización del valor NaN de la siguiente forma:

null_columns=df.columns[df.isnull().any()]
df[null_columns].isnull().sum()
print(df[df.isnull().any(axis=1)][null_columns].head())

Una vez localizado el valor NaN podemos eliminar dicha fila de la siguiente forma:

df_sin_nan = df.dropna(how='any')

En este caso, al ser un único valor NaN en toda una fila con 212 atributos no tiene mucho sentido eliminar toda la fila. Una opción es rellenarlo con la media de todo el grupo de la siguiente forma:

df = df.fillna(df.mean())

Esto me da el siguiente resultado:

Ha rellenado mi valor NaN situado en la posición [‘322’][917] con el valor 89.10, que es la media de la columna 322 al completo.

La solución es buena pero yo voy a proponer otra, que es rellenar el valor NaN con la media del valor anterior y el posterior. En mi caso esta solución tiene más sentido ya que es un DataFrame de valores de una sucesión temporal a lo largo de varios años y la media total no tiene porqué estar en torno a los valores que se estaban dando en la fecha de la fila 917.

Veo los valores anterior y posterior:

spy['322'][916]
spy['322'][918]

Calculo la media y la introduzco en la posición [‘322’][917]:

spy['322'][917] = ((spy['322'][918]+spy['322'][916])/2)

Y visualizo la posición del valor NaN para ver si se ha actualizado correctamente:

Resumiendo: hemos cambiado el valor NaN de la posición [‘322’][917] de nuestro DataFrame a 89.10 que es la media de toda la columna y posteriormente hemos decidido cambiarlo mejor a 85.625, que es la media de los valores anterior y posterior.

Para saber más:
Pandas: Find Rows Where Column/Field Is Null.
How to check if any value is NaN in a Pandas DataFrame.
Trabajar con datos NaN en dataframe.

Deja una respuesta