Manejar datos nulos
Contents
Manejar datos nulos#
Los datos nulos corresponden a información que no se consignó, ya fuese en la creación del archivo o en la entrada de datos. Nuevamente, esta es una decisión de diseño del modelo de datos y no todos los casos son iguales, así que hay que tener en cuenta que no todos los conjuntos de datos requerirán las mismas acciones.
dropna()
#
Esta función elimina los valores nulos de un conjunto de datos. Su sintaxis es:
df.dropna()
Por ejemplo, si la aplicamos a los datos de muestra_covid
tendremos el siguiente resultado:
sin_nulos = muestra_covid.dropna()
print(sin_nulos.shape)
sin_nulos.head()
(783, 12)
Unnamed: 0 | sexo | edad | entidad_nacimiento | municipio_residencia | indigena | nacionalidad | migrante | pais_nacionalidad | fecha_ingreso | fecha_sintomas | fecha_def | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
337 | 337 | HOMBRE | 84 | OAXACA | nezahualcóyotl | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-06 | 2021-12-24 | 2022-01-14 |
1248 | 1248 | MUJER | 71 | HIDALGO | tlanepantla | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-27 | 2022-01-12 |
1249 | 1249 | MUJER | 79 | MÉXICO | nezahualcóyotl | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-25 | 2022-01-07 |
2305 | 2305 | HOMBRE | 87 | MÉXICO | ecatepec de morelos | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-02 | 2021-12-23 | 2022-01-03 |
2478 | 2478 | HOMBRE | 34 | MÉXICO | tlalnepantla de baz | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-02 | 2021-12-30 | 2022-01-03 |
Ahora tenemos un conjunto de datos más sintetizado. Demasiado sintético diría yo. El inconveniente con usar este método de manera simple es que cualquier fila que contenga un valor nulo será eliminada. Por lo tanto, solamente tendremos 783 casos en los que toda la información es válida.
Una solución menos “radical” podría ser eliminar los valores nulos solamente de una columna, por ejemplo, municipio_residencia
:
sin_nulos = muestra_covid.dropna(subset=['municipio_residencia'])
print(sin_nulos.shape)
sin_nulos.head()
(149707, 12)
Unnamed: 0 | sexo | edad | entidad_nacimiento | municipio_residencia | indigena | nacionalidad | migrante | pais_nacionalidad | fecha_ingreso | fecha_sintomas | fecha_def | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
7 | 7 | MUJER | 75 | QUERÉTARO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-21 | 2022-02-16 | NaN |
10 | 10 | HOMBRE | 40 | CIUDAD DE MÉXICO | atizapán | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-05-19 | 2022-05-19 | NaN |
23 | 23 | MUJER | 9 | CIUDAD DE MÉXICO | zumpango | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-12 | 2022-01-07 | NaN |
24 | 24 | MUJER | 40 | GUERRERO | zumpango | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-12 | 2022-01-08 | NaN |
25 | 25 | MUJER | 13 | CIUDAD DE MÉXICO | nezahualcóyotl | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-26 | 2022-01-26 | NaN |
En este caso tendremos un número un tanto más significativo de casos (149,707).
Aparentemente hemos perdido mucha información, pero en realidad hemos segmentado el conjunto de datos para seleccionar solamente aquellos que podamos representar en un mapa. Como conservamos nuestro conjunto de datos original, incluso nuestro dataframe segmentado (muestra_covid
), no debemos preocuparnos por perder la información de sexo, edad, etc; que no esté asociada a una ubicación geográfica.
fillna()
#
Otra función para lidiar con valores nulos es fillna()
. Esta función reemplaza los valores nulos por un valor específico. Su sintaxis es:
df.fillna(valor)
Ciertas operaciones en pandas
no pueden lidiar con datos nulos, pero no siempre (como vimos arriba) podemos eliminar esos campos. Por esa razón, esta función permite llenar estos campos con un valor constante con el que podremos trabajar posteriormente.
Una aclaración
Aunque podemos asignar cualquier valor a fillna()
es importante que seamos coherentes con el tipo de dato de la columna que estamos transformando. Por ejemplo, si la columna fecha_diagnostico
es de tipo int64
, entonces fillna()
debe ser de tipo int64
.
Además, en todos los casos, el valor debe ser similar a un valor nulo. Por ejemplo, 0
o 'N/A'
son valores que pueden reemplazar a un valor nulo.
Al igual que en dropna()
si usamos un valor indistintamente de la columna, se reemplazarán todos los valores nulos de todo el dataframe:
nulos_reemplazados = muestra_covid.fillna('N/A')
nulos_reemplazados.head()
Unnamed: 0 | sexo | edad | entidad_nacimiento | municipio_residencia | indigena | nacionalidad | migrante | pais_nacionalidad | fecha_ingreso | fecha_sintomas | fecha_def | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | HOMBRE | 43 | CIUDAD DE MÉXICO | N/A | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-05-03 | 2022-05-03 | N/A |
1 | 1 | HOMBRE | 39 | CIUDAD DE MÉXICO | N/A | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-13 | 2022-01-10 | N/A |
2 | 2 | HOMBRE | 55 | CIUDAD DE MÉXICO | N/A | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-12 | 2022-01-12 | N/A |
3 | 3 | HOMBRE | 54 | CIUDAD DE MÉXICO | N/A | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-20 | 2022-02-13 | N/A |
4 | 4 | MUJER | 41 | CIUDAD DE MÉXICO | N/A | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-12 | 2022-01-10 | N/A |
En este caso, el reemplazo en municipio_residencia
es claro, pero en fecha_def
puede llevar a errores (por ejemplo, cuando tratemos de cambiar los valores de fecha_def
a datetime64[ns]
). Otro inconveniente es que no es posible establecer una fecha 0
(recuerda lo que dijimos al respecto en la sección dedicada a variables cuantitativas y cualitativas sobre las escalas de intervalo). Por lo que en este caso, la decisión más adecuada podría ser reemplazar únicamente los valores nulos de la columna municipio_residencia
con 'NO APLICA'
.
nulos_reemplazados = muestra_covid.fillna({'municipio_residencia': 'NO APLICA'}) # usamos 'NO APLICA' como valor pues es el que se utiliza en el dataset original para otras categorías
nulos_reemplazados.head()
Unnamed: 0 | sexo | edad | entidad_nacimiento | municipio_residencia | indigena | nacionalidad | migrante | pais_nacionalidad | fecha_ingreso | fecha_sintomas | fecha_def | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | HOMBRE | 43 | CIUDAD DE MÉXICO | NO APLICA | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-05-03 | 2022-05-03 | NaN |
1 | 1 | HOMBRE | 39 | CIUDAD DE MÉXICO | NO APLICA | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-13 | 2022-01-10 | NaN |
2 | 2 | HOMBRE | 55 | CIUDAD DE MÉXICO | NO APLICA | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-12 | 2022-01-12 | NaN |
3 | 3 | HOMBRE | 54 | CIUDAD DE MÉXICO | NO APLICA | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-20 | 2022-02-13 | NaN |
4 | 4 | MUJER | 41 | CIUDAD DE MÉXICO | NO APLICA | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-12 | 2022-01-10 | NaN |
¿Cómo saber cuáles columnas tienen valores nulos?#
En conjuntos grandes de datos, es posible que no identifiquemos un valor nulo hasta el momento que nos encontremos con un mensaje de error. Por esta razón, es probable que queramos obtener las columnas que tengan valores nulos antes de proceder con un dataframe. Para ello, podemos usar la función isnull()
aplicada a una columna en específico, combinada con el método .loc
:
es_nula = muestra_covid.loc[muestra_covid['fecha_def'].isnull()]
es_nula
Unnamed: 0 | sexo | edad | entidad_nacimiento | municipio_residencia | indigena | nacionalidad | migrante | pais_nacionalidad | fecha_ingreso | fecha_sintomas | fecha_def | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | HOMBRE | 43 | CIUDAD DE MÉXICO | NaN | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-05-03 | 2022-05-03 | NaN |
1 | 1 | HOMBRE | 39 | CIUDAD DE MÉXICO | NaN | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-13 | 2022-01-10 | NaN |
2 | 2 | HOMBRE | 55 | CIUDAD DE MÉXICO | NaN | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-12 | 2022-01-12 | NaN |
3 | 3 | HOMBRE | 54 | CIUDAD DE MÉXICO | NaN | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-20 | 2022-02-13 | NaN |
4 | 4 | MUJER | 41 | CIUDAD DE MÉXICO | NaN | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-12 | 2022-01-10 | NaN |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1323496 | 1323496 | HOMBRE | 48 | CIUDAD DE MÉXICO | NaN | NO ESPECIFICADO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-05 | 2022-01-01 | NaN |
1323497 | 1323497 | HOMBRE | 27 | CIUDAD DE MÉXICO | NaN | NO ESPECIFICADO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-04 | 2022-01-01 | NaN |
1323498 | 1323498 | MUJER | 46 | CIUDAD DE MÉXICO | NaN | NO ESPECIFICADO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-05 | 2022-01-01 | NaN |
1323499 | 1323499 | MUJER | 33 | CIUDAD DE MÉXICO | NaN | NO ESPECIFICADO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-05 | 2022-01-01 | NaN |
1323500 | 1323500 | HOMBRE | 34 | MÉXICO | NaN | NO ESPECIFICADO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-27 | 2022-01-27 | NaN |
1319912 rows × 12 columns
Puedes combinar este método con un loop para obtener una lista de las columnas que contienen valores nulos:
nulas = []
for col in muestra_covid:
if muestra_covid[col].isnull().any(): # la función `any()` devuelve `True` si alguna de las filas contiene un valor nulo
nulas.append(col)
nulas
['municipio_residencia', 'fecha_def']
Este loop lo puedes aplicar a cualquier dataframe, sin importar la cantidad de columnas que tenga.