6.13 Limpieza de datos

Esta sección abordará algunos tópicos de limpieza de datos o Data cleaning. Como ya se ha revisado, los valores perdidos o NA causan problemas en el cálculo de parámetros estadísticos de las bases de datos. Más aún, cuando se pretende modelar la relación de una variable Y con los valores de una variable X, es imposible hacer regresión alguna con valores perdidos. Para estos casos, limpiar la base de datos será crucial.

Siempre que necesites identificar si un elemento dentro de un objeto es NA o no, podrás utilizar la función is.na(). Esta devolverá un objeto lógico con la misma extensión que el objeto original. En aquellas posiciones donde exista un NA en la base de datos original, is.na() mostrará TRUE.

6.13.1 ¿Cuántos NA existen en la base de datos?

Ejemplo 6.24 Considerando la base de datos WHO, calcular la cantidad de NA de la base.

# Convertir WHO a tabla lógica 
# para ubicar con TRUE a los NA
WHO_logical <- is.na(WHO)

Recuerda que para las funciones estadísticas y matemáticas, como mean() o sum(), TRUE equivale a 1 y FALSE a 0. Se puede obtener la proporción de TRUE de un vector con mean(), o la suma de TRUE en el vector con sum().

# Sumando todos los TRUE (equivalentes a 1)
sum(WHO_logical)
# [1] 2563

6.13.2 ¿Cuántos NA existen en cada columna?

Hay muchas maneras de llegar a este resultado. Pero el procedimiento es similar en concepto al anterior. Se deben sumar los TRUE (celdas con NA) pero esta vez columna a columna. Como dato adicional, este objetivo también puede conseguir utilizando la función apply() (Sección 5.4 Familia apply()).

Ejemplo 6.25 Crear una función que sume los NA de un vector:

fun_na <- function(x) sum(is.na(x))

Ahora, utilizar la función aplicada a todas las columnas de la base de datos WHO:

WHO %>% 
  summarise_all(.funs = fun_na)
#   Country Year Status1 Category Level Status2 St2_categ Life_exp Ad_mort Inf_deaths
# 1       0    0       0        0     0       0         0       10      10          0
#   Alcohol Per_exp Hep_B Measles BMI U5Y Polio Tot_exp Diph AIDS GDP Pop Thin1_19
# 1     194       0   553       0  34   0    19     226   19    0 448 652       34
#   Thin5_9 Income Schooling
# 1      34    167       163

Si son demasiadas columnas para visualizar, considera seleccionar las columnas cuyos valores sean mayores de 0. Crea una función que evalúe un valor y otorgue TRUE si este es mayor que 0.

# Crear la función 
fun0 <- function(x) x > 0

La selección ahora utiliza una función que no se utilizó antes: select_if(). Como todas las funciones _if de dplyr, esta necesita condicionales para función. Allí entra en juego la función antes creada:

# Aplicarla en select_if()
WHO %>% 
  summarise_all(.funs = fun_na) %>% 
  select_if(fun0)
#   Life_exp Ad_mort Alcohol Hep_B BMI Polio Tot_exp Diph GDP Pop Thin1_19 Thin5_9
# 1       10      10     194   553  34    19     226   19 448 652       34      34
#   Income Schooling
# 1    167       163

6.13.3 ¿En qué fila o columna están los NA?

Ubicar la posición de fila y columna de los valores NA (celdas en blanco) se utiliza cuando se conoce que no deberían haber celdas vacías pero las hay. Encontrarlas permite rellenar dicho valor por el correspondiente que fue omitido en el proceso de rellenado de la base de datos.

Ejemplo 6.26 Ubicar los valores NA de la base de datos WHO. Mostrar únicamente las 10 primeras del resultado:

which(WHO_logical, arr.ind=TRUE) %>% 
  head(10)
#       row col
# 625   625   8
# 770   770   8
# 1651 1651   8
# 1716 1716   8
# 1813 1813   8
# 1910 1910   8
# 1959 1959   8
# 2168 2168   8
# 2217 2217   8
# 2714 2714   8
En inglés, row significa fila y col columna.

6.13.4 ¿Cómo reemplazar los NA por otro valor?

En ocasiones se necesita reemplazar los NA por algún valor por defecto que en el análisis sea útil. Por ejemplo, en bases que representan datos SIG (Sistemas de Información Geográficas), algunas celdas necesitan ser 9999, o -256, o algún otro valor, para que el análisis los considere bajo la categoría “no hay dato”. Otros estudios, por su parte, utilizan el rellenar los datos con el promedio o la mediana de la columna. En los siguientes ejemplos veremos su aplicación:

Ejemplo 6.27 Rellenar los valores NA de la base de datos WHO con el valor 9999999. Es excesivamente largo solo con la finalidad de hacerlo notorio, no por otra razón. Selecciona previamente las columnas Alcohol, Hep_B, Measles, Polio, Diph para que el resultado no sea amplio en la consola. Reordenar el resultado por la columna Alcohol y mostrar las últimas 6 filas de la tabla.

Aquí el truco está en una forma especial de mutate_all() para transformar todas las columnas pero utilizando ~ifelse() para reemplazar todas la NA (is.na(.x)) por 9999999, y las no NA con el mismo valor original (.x):

WHO %>% 
  dplyr::select(Alcohol, Hep_B, Measles, Polio, Diph) %>% 
  arrange(Alcohol) %>% 
  mutate_all(~ifelse(is.na(.x), 9999999, .x)) %>% 
  tail() 
#      Alcohol Hep_B Measles Polio Diph
# 2933   1e+07    64      39    65   64
# 2934   1e+07    87       0    87   87
# 2935   1e+07    97     256    97   97
# 2936   1e+07    69     468    63   69
# 2937   1e+07     9       9     9    9
# 2938   1e+07    87       0    88   87

Ejemplo 6.28 Considera el mismo ejemplo anterior 6.27. No obstante, en lugar de reemplazar NA por 9999999, utiliza la función con mean(.x, na.rm = TRUE) para que los NA se reemplacen por el promedio de la columna.

WHO %>% 
  dplyr::select(Alcohol, Hep_B, Measles, Polio, Diph) %>% 
  arrange(Alcohol) %>% 
  mutate_all(~ifelse(is.na(.x), mean(.x, na.rm = TRUE), .x))%>% 
  tail() 
#      Alcohol Hep_B Measles Polio Diph
# 2933   4.603    64      39    65   64
# 2934   4.603    87       0    87   87
# 2935   4.603    97     256    97   97
# 2936   4.603    69     468    63   69
# 2937   4.603     9       9     9    9
# 2938   4.603    87       0    88   87