library(simputation)
library(tidyverse)

Datos faltantes

La incompletitud de datos dentro de cualquier estudio trae aparejado implicaciones muy importantes para su análisis. Sin lugar a dudas, la pérdida de datos necesariamente conlleva a la pérdida de información y a una menor precisión en la estimación de los parámetros de interés (Molenberghs 2015).

Una de las principales tareas para el análisis de datos suele ser por tanto, la evaluación de la inexistencia de datos (datos faltantes o “missing data”). La ausencia de valores en los conjuntos de datos puede tener varios efectos perjudiciales. He aquí algunos ejemplos:

  • Pueden limitar la capacidad para realizar importantes tareas de ciencia de datos, como la conversión de tipos de datos o la visualización de datos.
  • Pueden reducir la validez estadística de los modelos, lo que a su vez aumenta la probabilidad de error de tipo II. El error de tipo II es la incapacidad de rechazar una hipótesis nula falsa.
  • Los datos que faltan pueden reducir la representatividad de las muestras del conjunto de datos.
  • Los datos que faltan pueden distorsionar la validez de los ensayos científicos y llevar a conclusiones no válidas.

En R la ausencia de valores se representa por el valor “NA” lo que permite su reconocimiento y consideración en el uso de funciones sobre datos. Las tareas consisten pues en:

  • Evaluar la existencia de valores perdidos (exploración).
  • Excluir los valores ausentes.
  • Recodificar los valores ausentes (imputación).

Si bien existen funciones que incluyen las funciones como argumento “na.omit” o “na.rm = TRUE,” que permiten ejecutar funciones numéricas sobre datos NA, algunos análisis devolverán un error ante la existencia de valores NA o vacíos ("").

Las acciones que pueden llevarse a cabo frente a datos ausentes son por tanto, las que pueden o no modificar el comportamiento de los datos en su totalidad o llevar a conclusiones erróneas:

  • Eliminar las filas completas que contengan al menos un valor ausente.
  • Eliminar las filas que contengasn datos ausntes en alguna variable considerada clave para el análisis.
  • Cambiar los valores ausentes a otro valor.
  • Modificar los valores ausentes a un valor predeterminado.
  • Realizar imputación de datos.

Nota: la mejor estrategia es no contar con datos ausentes.

El problema de la ausencia

La existencia de datos en un set de datos provoca errores sobre todo en aquellas funciones estadísticas que agrupan datos para obtener un resultado.

mean(airquality$Ozone)
## [1] NA

A menos que dentro de la función se pueda especificar omitir este tipo de datos.

mean(airquality$Ozone, na.rm = TRUE)
## [1] 42.12931

Clasificación de datos

En teoría todas las variables tienen datos que tienen alguna probabilidad de estar ausentes dentro de un conjunto de datos. Se identifican 3 mecanismos que establecen datos ausentes.

👣 Estos mecanismos no son controlados por el encargado del estudio y mas bien se infieren o asumen.

MCAR

Missing Completely at Random. Si la probabilidad de estar ausentes en la misma en todos los casos, entonces se dice que poseen datos perdidos en forma completamente aleatoria. Este es el estado deseado en caso de datos perdidos, ya que indica que no hay sesgo respecto de las perdidas. Por tanto se mantendrían las medidas de normalidad y distribución estadística. La pérdidad de datos no esta relacionada a los datos mismos. Al capturar datos de una muestra los datos no ingresados en ella son evitados en forma MCAR (totalmente aleatoria, cuando el muestreo es correcto).

MAR

Missing at Random. Existe una relación sistemática entre los datos observados y la propensión a valores ausentes. Que una observación falte no tiene que ver con esos valores sino con los valores de las variables observadas. Un ejemplo claro es la edad que es más probable que los hombres la digan respecto de las mujeres. Entonces la edad es MAR.

La ausencia de datos está sesgada ya que no tienen la misma distribución, en el ejemplo anterior, las respuestas ausentes provienen mayoritariamente de mujeres. También puede originarse de una mala muestra de datos (no representativa o sesgada).

MNAR

Missing Not at Random. Pérdida de datos no aleatoria. Existe una relación entre la propensión a que falte un dato y sus valores. Esto origina un problema en el análisis de datos. Como ejemplo si la mayoría no responde una pregunta determinada puede deberse a que esa pregunta no se entendió del todo. Las personas más enfermas son las más propensas a abandonar el estudio.

En una encuesta pública las personas con carácter más tímido responderán con menos frecuencia que otras de caracter más fuerte.

👣 Cuando los datos son NMAR, casi todos los métodos de análisis estándar no son válidos. Por ejemplo, los métodos estándar basados en la verosimilitud que ignoran el mecanismo de los datos perdidos producen estimaciones sesgadas.

Es importante considerar el tipo de clasificación de datos perdidos para identificar el tipo de análisis a realizar.

Nota: Considerar que en la mayoría de los conjuntos de datos, más de una variable tendrá datos perdidos, y puede que no todas tengan el mismo mecanismo. Vale la pena diagnosticar el mecanismo para cada variable con datos perdidos antes de elegir un enfoque.

Representación gráfica de ausencias. X representa las variables observadas, Y representa una variable parcialmente ausente, Z representa el componente de las causas de ausencia no relacionadas con X e Y, y R representa la ausencia. (Schafer and Graham 2002)

Esta clasificación tiene alta incidencia respecto a cómo afrontar los valores ausentes. Los programas estadísticos como R y otros usan un análisis sobre casos completos, lo que se denomina “listwise deletion” donde por defecto se omiten los valores nulos. Esto funciona bien para datos MCAR. Donde las medidas como media, varianzas y regresiones se producen sin sesgo respecto de los datos completos. Sobre datos que no son del tipo MCAR se produce un sesgo en estas medidas.

Exploración

La primera misión de un analista es por tanto, determinar la existencia de valores ausentes dentro del conjunto de datos. Y determinar posteriormente, las acciones a tomar frente a ello.

Como siempre en R, hay más de una forma de obtener los resultados esperados.

Para determinar el patrón de datos hacemos uso de la librería mice.

library(mice)
md.pattern(airquality)

##     Wind Temp Month Day Solar.R Ozone   
## 111    1    1     1   1       1     1  0
## 35     1    1     1   1       1     0  1
## 5      1    1     1   1       0     1  1
## 2      1    1     1   1       0     0  2
##        0    0     0   0       7    37 44

Para determinar si una columna en particular contiene NAs.

is.na(airquality$Solar.R)
##   [1] FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE
##  [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [25] FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [49] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [73] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
##  [85] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
##  [97]  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [109] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [133] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [145] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

Lo usual es verificar la existencia de casos donde existan valores ausentes. Si desea aplicar una función solamente con aquellos casos con todos sus valores existe la función complete().

# mostrar solo aquellos registros que no estan completos,
# poseen algún valor ausente)
# la columna Ozone posee NA's
airquality %>%
  select(Ozone, Solar.R, Wind, Temp) %>%
  filter(!complete.cases(.)) # solo utiliza las filas que no contienes NA's

El número de valores ausentes por cada variable es:

colSums(is.na(airquality))
##   Ozone Solar.R    Wind    Temp   Month     Day 
##      37       7       0       0       0       0

Valoración de datos perdidos

Un umbral determinado para tolerar datos perdidos suele ser de un 5% para grandes volumenes de datos. Si el porcentaje es mucho mayor tal vez se deba omitir esa propiedad. O en se defecto considerar realizar imputación de datos.

# determinación del porcentaje de valores perdidos respecto del total de datos
# para cada columna
porcentajeMiss <- function(x) {sum(is.na(x)) / length(x)*100}
# por columna
apply(airquality, 2, porcentajeMiss)
##     Ozone   Solar.R      Wind      Temp     Month       Day 
## 24.183007  4.575163  0.000000  0.000000  0.000000  0.000000
# por filas
# apply(airquality, 1, porcentajeMiss)

La columna “Ozone” tiene cerca de un 25% de datos perdidos, por tanto no debería considerarse para mediciones futuras.

Determinar que valores deben ser cambiados por NA.

No basta con la búsqueda de valores vacíos o nulos que rápidamente se pueden detectar y cambiar por NA para ser incorporados dentro de las acciones de funciones (mediante omisión de valores NA).

¿Cómo detectar qué valores no son correctos y por tanto deben ser cambiados/omitidos?.

La primera opción debiera ser revisar esos valores en detalle, lo que es posible solamente cuando tenemos talvez unos cientos de valores únicos. Es extremadamente dificil y costoso cuando son miles de variantes.

# contabilidad de datos únicos en cada columna
airquality %>% summarise_all(funs(n_distinct(.)))
##   Ozone Solar.R Wind Temp Month Day
## 1    68     118   31   40     5  31

Determinar los valores existentes en cada columna del set de datos.

unique(airquality$Ozone)
##  [1]  41  36  12  18  NA  28  23  19   8   7  16  11  14  34   6  30   1   4  32
## [20]  45 115  37  29  71  39  21  20  13 135  49  64  40  77  97  85  10  27  48
## [39]  35  61  79  63  80 108  52  82  50  59   9  78  66 122  89 110  44  65  22
## [58]  31 168  73  76 118  84  96  91  47  24  46
unique(airquality$Wind)
##  [1]  7.4  8.0 12.6 11.5 14.3 14.9  8.6 13.8 20.1  6.9  9.7  9.2 10.9 13.2 12.0
## [16] 18.4 16.6  5.7 16.1 20.7 10.3  6.3  1.7  4.6  4.1  5.1  4.0 15.5  3.4  2.3
## [31]  2.8

Reemplazar valores nulos u otros a “NA.”

En muchas ocasiones tendremos en lugar de valores normales NA, valores vacíos del tipo "" o de otro tipo indicando errores. Para tratarlos correctamente en R deben ser cambiados a NA que si es reconocido como un valor.

# modifica aquellos valores vacíos por NA.
airquality$Ozone[airquality$Ozone == ""] <- NA

airquality$Ozone[airquality$Ozone == 0] <- NA

# modifica una columna de factores para agregar un NA
pacientes$sexo <- factor(pacientes$sexo, levels = c("M", "F", NA))

Reemplazar los valores ausentes por otro valor.

datos <- read.csv(file="", 
          sep = ",", dec = ".",
          na.strings = "") # esto reemplazará los espacios en blancos por 'NA'
# altera los valores NA y los cambia por "0"
airquality %>%
  select(Ozone, Wind, Temp) %>%
  # "replace_na"  reemplaza los NA por "0" en Ozone
  mutate(Ozone = replace_na(Ozone, "0")) %>%
  # no contabiliza los NA en columna Ozone, pero como se modificaron por "0"
  # igual mostrará todos los registros (153)
  drop_na(Ozone) 

Donde tambien se puede buscar valores vacíos con is.empty()

Reemplazar ciertos valores (“0” en este caso) por NA. Esto es relevante para detectar valores sin sentido.

# Reemplaza los valores "0" en Ozone por NA.
airquality %>%
  select(Ozone, Wind, Temp, Solar.R) %>%
  # efectua el reemplazo de los valores '0' por NA
  mutate(Ozone = na_if(Ozone, 0)) %>%
  # filtrar para mostrar solamente los que posean valor NA en Ozone
  filter(is.na(Ozone)) %>%
  View() # cambiar por: head()

Trabajar con funciones que permiten omitir valores NA.

# incidencia de valores NA en el cálculo de algunas funciones
# la primera indicará un error por contener valores NA
mean(airquality$Ozone)
## [1] NA
# al omitir los valores NA presentará el valor correcto
mean(airquality$Ozone, na.rm = TRUE)
## [1] 42.12931

is.na()

Es la función más sencilla para evaluar los valores ausentes ya que presenta un valor lógico de TRUE si existe un valor ausente n una fila (funciona en vector, lista, matrices y data frame).

is.na(airquality) %>%
  head()
##      Ozone Solar.R  Wind  Temp Month   Day
## [1,] FALSE   FALSE FALSE FALSE FALSE FALSE
## [2,] FALSE   FALSE FALSE FALSE FALSE FALSE
## [3,] FALSE   FALSE FALSE FALSE FALSE FALSE
## [4,] FALSE   FALSE FALSE FALSE FALSE FALSE
## [5,]  TRUE    TRUE FALSE FALSE FALSE FALSE
## [6,] FALSE    TRUE FALSE FALSE FALSE FALSE

Otra forma de evaluar cuantos NA hay en cada columna de un data frame.

colSums(is.na(airquality))
##   Ozone Solar.R    Wind    Temp   Month     Day 
##      37       7       0       0       0       0

na.omit()

Permite omitir (eliminar) los registros que posean los valores “NA” de un conjunto de datos para su inclusión como argumento de otras funciones.

na.omit(airquality)

sapply

La gracia de sapply es la no dependencia de otros paquetes. Aunque debido a que no es estable respecto a los tipos de datos, se utiliza más bien en modo interactivo que sobre rutinas de programas.

# Determinar cuantos valores NA hay en cada columna.
sapply(airquality, function(x) sum(is.na(x)))
##   Ozone Solar.R    Wind    Temp   Month     Day 
##      37       7       0       0       0       0

dplyr

Del paquete Tydyverse. El siguiente ejemplo toma todas las columnas de “airquality” y las resume (summarise) tomando todas las columnas y aplicando la función sum(is.na(.)). El punto indica que toma la salida del paso anterior dentro de la tubería (pipe) creada con %>%.

# Determinar cuantos valores NA hay en cada columna.
airquality %>%
  select(everything()) %>%
  summarise_all(funs(sum(is.na(.))))
##   Ozone Solar.R Wind Temp Month Day
## 1    37       7    0    0     0   0

apply

Para contabilizar los ‘NA’ fila a fila en un formato caso a caso, aplica una función a cada fila de un dataframe.

apply posee los siguientes parámetros

apply(data, margen, funcion)
  • data: matriz u objeto que puede destinarse a un matriz, por lo regular un data frame.

  • margen: dimensión que agrupa a los elementos de la matriz para aplicar la función: 1 renglones, 2 columnas.

  • funcion: la función que se aplicará a la matriz en la dimensión margen.

Buscar valores en blanco y cambiarlos por NA.

# Determinar cuantos valores NA hay en cada columna.
apply(airquality, MARGIN = -1, function(x) sum(is.na(x))) 
##   Ozone Solar.R    Wind    Temp   Month     Day 
##      37       7       0       0       0       0

Resumen de datos de set de datos airquality. Las columnas Ozone y Solar.R poseen datos NA.

summary(airquality)
##      Ozone           Solar.R           Wind             Temp      
##  Min.   :  1.00   Min.   :  7.0   Min.   : 1.700   Min.   :56.00  
##  1st Qu.: 18.00   1st Qu.:115.8   1st Qu.: 7.400   1st Qu.:72.00  
##  Median : 31.50   Median :205.0   Median : 9.700   Median :79.00  
##  Mean   : 42.13   Mean   :185.9   Mean   : 9.958   Mean   :77.88  
##  3rd Qu.: 63.25   3rd Qu.:258.8   3rd Qu.:11.500   3rd Qu.:85.00  
##  Max.   :168.00   Max.   :334.0   Max.   :20.700   Max.   :97.00  
##  NA's   :37       NA's   :7                                       
##      Month            Day      
##  Min.   :5.000   Min.   : 1.0  
##  1st Qu.:6.000   1st Qu.: 8.0  
##  Median :7.000   Median :16.0  
##  Mean   :6.993   Mean   :15.8  
##  3rd Qu.:8.000   3rd Qu.:23.0  
##  Max.   :9.000   Max.   :31.0  
## 
# carga de datos de Titanic
titanic <- read.csv("data/titanic3.csv")
#cantidad de valores NA por cada columna. En forma inicial antes del cambio
apply(titanic, MARGIN = 2, function(x) sum(is.na(x)))
##    pclass  survived      name       sex       age     sibsp     parch    ticket 
##         0         0         0         0       263         0         0         0 
##      fare     cabin  embarked      boat      body home.dest 
##         1         0         0         0      1188         0
# cambiar los valores en blanco ("") por NA
titanic <- titanic %>%
  mutate(Ozone = replace_na(boat, "")) %>%
  mutate(Ozone = replace_na(home.dest, "")) %>%
  mutate(Ozone = replace_na(cabin, ""))

# cantidad de valores NA después de cambiar los valores "".
apply(titanic, MARGIN = 1, function(x) sum(is.na(x)))
##    [1] 1 1 1 0 1 1 1 1 1 0 0 1 1 1 1 2 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1
##   [38] 2 1 0 2 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 2 0 1 1 1 1 1 1 1 1 2 2 1 1 1
##   [75] 2 1 1 1 1 1 2 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 1 1 2 2 2 1 1
##  [112] 1 1 1 1 1 1 1 2 1 1 2 1 1 1 2 1 1 0 1 1 1 1 1 2 1 1 1 0 1 1 1 1 1 1 1 1 2
##  [149] 1 1 0 1 2 1 0 1 1 2 1 1 1 1 0 1 1 1 2 1 1 1 1 0 1 0 0 1 2 1 1 2 1 1 1 1 2
##  [186] 1 1 1 1 0 1 1 1 1 1 1 2 1 1 1 0 0 1 1 2 0 0 1 1 1 1 1 1 1 1 0 1 0 1 2 1 0
##  [223] 0 2 0 1 1 1 1 1 1 1 0 1 1 2 0 2 1 1 1 2 1 0 1 1 1 1 0 1 1 1 1 1 2 1 2 1 1
##  [260] 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 2 1 1 1 1 1 2 1 0 1 0 1 1 1 1 1 2 1 1
##  [297] 1 2 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1
##  [334] 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 2 0 1 1 0 0 1
##  [371] 1 1 1 1 1 1 1 1 1 1 1 1 2 1 2 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
##  [408] 1 1 0 2 1 0 1 1 1 1 1 1 1 1 0 0 1 0 0 0 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0
##  [445] 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 2 1 1 1 2 0 1 1 2 1 1 1
##  [482] 1 1 2 1 1 0 1 0 1 0 2 1 1 1 2 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 0 1
##  [519] 0 0 1 1 1 1 2 1 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  [556] 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 0 1 1 1 1 1 1
##  [593] 1 1 1 2 1 2 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 1 1 1 1 0 1 0 0 1 1 1 1 1 1 1 1
##  [630] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  [667] 1 1 1 1 1 1 2 1 1 1 1 1 1 1 2 2 2 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
##  [704] 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1
##  [741] 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 2 1
##  [778] 1 1 1 1 0 1 1 1 1 1 1 1 2 1 1 1 1 1 2 0 0 2 1 2 2 2 1 2 2 1 1 2 1 1 1 2 2
##  [815] 1 2 2 0 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 0 1 1 1 1 2 2 1 1 1 0 1 1 0
##  [852] 1 2 1 2 1 2 1 2 1 1 1 1 0 1 2 1 1 1 1 1 2 2 0 2 1 2 1 1 2 1 1 2 1 1 1 2 2
##  [889] 0 1 0 0 1 1 1 1 1 0 1 1 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 0 2 2 2 2 0
##  [926] 1 2 2 2 2 2 2 1 1 1 1 1 1 1 1 2 1 2 1 2 2 2 1 2 1 1 1 1 1 2 2 2 2 2 1 0 2
##  [963] 2 1 1 1 1 1 1 1 1 2 1 2 1 1 1 1 1 1 1 1 2 2 2 1 1 2 2 2 1 2 0 2 2 1 1 2 2
## [1000] 2 2 2 2 2 2 2 2 1 1 2 1 0 2 2 2 0 2 1 2 1 1 1 2 2 0 1 1 2 2 2 2 1 2 2 2 2
## [1037] 2 2 2 2 1 2 2 2 2 1 1 1 1 1 1 1 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 1 1 2 2 2 2
## [1074] 2 2 1 2 2 2 1 2 2 1 0 1 2 1 1 1 0 1 1 1 1 1 2 0 1 1 1 0 1 1 1 1 1 1 1 1 2
## [1111] 1 1 1 1 2 2 2 1 1 1 1 2 2 2 2 1 1 1 2 1 1 1 2 1 1 2 2 2 2 1 1 1 1 1 1 1 0
## [1148] 1 1 2 2 2 0 0 2 2 1 1 1 2 1 1 2 2 2 1 2 2 2 0 2 0 2 2 2 2 2 2 2 2 2 1 1 1
## [1185] 2 2 2 1 1 1 1 1 0 2 2 2 1 2 2 2 2 1 2 1 1 1 1 1 1 1 1 1 2 2 2 2 2 1 1 2 1
## [1222] 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 2 2 2 1 2 2 2 1 2 2 0 1 2 1 2 1 1
## [1259] 1 1 1 1 2 0 0 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 0 1 1 0 1 1 2 2 2 0
## [1296] 1 0 2 1 1 1 0 2 2 0 2 0 1 1

Omisión de columnas

# como boat, body y home.dest tienen muchos valores NA se omitiran del dataset.
#titanic %>%
#  select(-boat, -body, -home.dest)

str(titanic)
## 'data.frame':    1309 obs. of  15 variables:
##  $ pclass   : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ survived : int  1 1 0 0 0 1 1 0 1 0 ...
##  $ name     : chr  "Allen, Miss. Elisabeth Walton" "Allison, Master. Hudson Trevor" "Allison, Miss. Helen Loraine" "Allison, Mr. Hudson Joshua Creighton" ...
##  $ sex      : chr  "female" "male" "female" "male" ...
##  $ age      : num  29 0.917 2 30 25 ...
##  $ sibsp    : int  0 1 1 1 1 0 1 0 2 0 ...
##  $ parch    : int  0 2 2 2 2 0 0 0 0 0 ...
##  $ ticket   : chr  "24160" "113781" "113781" "113781" ...
##  $ fare     : num  211 152 152 152 152 ...
##  $ cabin    : chr  "B5" "C22 C26" "C22 C26" "C22 C26" ...
##  $ embarked : chr  "S" "S" "S" "S" ...
##  $ boat     : chr  "2" "11" "" "" ...
##  $ body     : int  NA NA NA 135 NA NA NA NA NA 22 ...
##  $ home.dest: chr  "St Louis, MO" "Montreal, PQ / Chesterville, ON" "Montreal, PQ / Chesterville, ON" "Montreal, PQ / Chesterville, ON" ...
##  $ Ozone    : chr  "B5" "C22 C26" "C22 C26" "C22 C26" ...

Esta función entonces, suma todos los valores de cada columna que sean NA.

# Determinar cuantos valores NA hay en cada columna.
apply(airquality, MARGIN = 2, function(x) sum(is.na(x)))
##   Ozone Solar.R    Wind    Temp   Month     Day 
##      37       7       0       0       0       0

Resumen de datos de set de datos airquality. Las columnas Ozone y Solar.R poseen datos NA.

summary(airquality)
##      Ozone           Solar.R           Wind             Temp      
##  Min.   :  1.00   Min.   :  7.0   Min.   : 1.700   Min.   :56.00  
##  1st Qu.: 18.00   1st Qu.:115.8   1st Qu.: 7.400   1st Qu.:72.00  
##  Median : 31.50   Median :205.0   Median : 9.700   Median :79.00  
##  Mean   : 42.13   Mean   :185.9   Mean   : 9.958   Mean   :77.88  
##  3rd Qu.: 63.25   3rd Qu.:258.8   3rd Qu.:11.500   3rd Qu.:85.00  
##  Max.   :168.00   Max.   :334.0   Max.   :20.700   Max.   :97.00  
##  NA's   :37       NA's   :7                                       
##      Month            Day      
##  Min.   :5.000   Min.   : 1.0  
##  1st Qu.:6.000   1st Qu.: 8.0  
##  Median :7.000   Median :16.0  
##  Mean   :6.993   Mean   :15.8  
##  3rd Qu.:8.000   3rd Qu.:23.0  
##  Max.   :9.000   Max.   :31.0  
## 

Visualización

Las herramientas de visualización permiten determinar rápidamente la incidencia de valores ausentes dentro de un set de datos. Y evaluar sobre qué variables de deben realizarse las acciones necesarias. Cuando las ausencias con notorias y abundantes puede tomarse la decisión de omitir la variable completa.

Visdat y Naniar

Estas librerías permiten visualizar en forma más expedita la proporción de datos perdidos dentro de un conjunto de datos.

library(visdat) # visualización de datos
library(naniar)

Visualización gráfica de proporción de datos perdidos y donde se producen.

vis_dat(airquality)

Determinación del porcentaje de datos perdidos.

vis_miss(airquality ,sort_miss = TRUE) 

# sort_miss = TRUE: es opcional
# con sort_miss = TRUE ordena las columnas desde la que posea mayor 
# pérdida de datos (cantidad de datos faltantes) a la menor.
# argumento opcional: cluster = TRUE, que permite agrupar los datos faltantes.
# cluster agrupa los datos faltantes
vis_miss(airquality ,sort_miss = TRUE, cluster = TRUE)

airquality %>% gg_miss_upset()

Proximamente… Imputación de datos.

Referencias

Buuren, Stef van. 2018. Flexible Imputation of Missing Data. 2nd ed. Chapman & Hall/CRC. https://stefvanbuuren.name/fimd/.
Efromovich, Sam. 2018. Missing and Modified Data in Nonparametric Estimation. 1st ed. Boca Raton, Florida: CRC Press.
Gelman, Andrew. 2006. Data Analysis Using Regression and Multilevel/Hierarchical Models. 1st ed. Cambridge University Press.
Kowarik, Alexander, and Matthias Templ. 2016. “Imputation with the R Package VIM.” Journal of Statistical Software 74 (7): 1–16. https://doi.org/10.18637/jss.v074.i07.
Molenberghs, Geert. 2015. Handbook of Missing Data Methodology. 1st ed. Chapman & Hall/CRC Press.
Raghunathan, Trivellore. 2016. Missing Data Analysis in Practice. 1st ed. Chapman & Hall/CRC.
Schafer, Joseph L., and John W. Graham. 2002. “Missing Data: Our View of the State of the Art.” Psychological Methods 7 (2): 147–77. https://doi.org/10.1037/1082-989x.7.2.147.
van Buuren, Stef, and Karin Groothuis-Oudshoorn. 2011. mice: Multivariate Imputation by Chained Equations in r.” Journal of Statistical Software 45 (3): 1–67. https://www.jstatsoft.org/v45/i03/.
Wiley, Matt, and Joshua F. Wiley. 2019. Advanced r Statistical Programming and Data Models. 1st ed. APress.