# Opciones globales para mi documento
knitr::opts_chunk$set(
echo = TRUE, # mostrar el codigo de R
warning = FALSE, # ocultar advertencias
message = FALSE, # ocultar mensajes de carga de paquetes
fig.align = "center", # centrar todas las figuras
fig.width = 9,
fig.height = 5,
dpi = 150,
comment = "#>"
)if (!require("pacman")) install.packages("pacman")
pacman::p_load(
readxl, # importo la base en formato Excel
janitor, # estandarizo nombres de columnas y reproduzco la depuración
tidyverse, # manipulación y gráficas (dplyr, ggplot2, tidyr, forcats, purrr)
skimr, # resumen descriptivo rápido
dlookr, # diagnóstico de calidad e imputación simple (imputate_na)
naniar, # exploración de faltantes y prueba de Little (mcar_test)
finalfit, # toolkit de faltantes: ff_glimpse, missing_plot, missing_pattern, missing_pairs, missing_compare
GGally, # soporte gráfico de missing_pairs
mice, # imputación múltiple por ecuaciones encadenadas (MICE)
gtsummary, # tablas comparativas antes y después de imputar
scales, # formato de ejes y etiquetas
flextable,
knitr
)gtsummary::theme_gtsummary_compact()
gtsummary::theme_gtsummary_language(
language = "es",
decimal.mark = ",",
big.mark = "."
)
tema_flex <- function(ft) {
ft |>
flextable::theme_vanilla() |>
flextable::bg(bg = "#EEF3F8", part = "header") |>
flextable::color(color = "#1F3B57", part = "header") |>
flextable::bold(part = "header") |>
flextable::fontsize(size = 10, part = "all") |>
flextable::padding(padding = 4, part = "all") |>
flextable::align(align = "center", part = "all") |>
flextable::autofit()
}
# tamaño estándar para los números sobre las barras (geom_text) en mis gráficas
tam_etiqueta <- 4.2
tema_gg <- function(base = 14) {
ggplot2::theme_minimal(base_size = base) +
ggplot2::theme(
text = ggplot2::element_text(colour = "#1F3B57"),
plot.title = ggplot2::element_text(face = "bold", size = base + 3, colour = "#16314A"),
plot.subtitle = ggplot2::element_text(size = base - 2, colour = "#3B5570"),
axis.title = ggplot2::element_text(size = base - 1, colour = "#1F3B57"),
axis.text = ggplot2::element_text(size = base - 2, colour = "#1F3B57"),
strip.text = ggplot2::element_text(face = "bold", size = base - 2, colour = "#1F3B57"),
legend.title = ggplot2::element_text(size = base - 2, colour = "#1F3B57"),
legend.text = ggplot2::element_text(size = base - 2, colour = "#1F3B57"),
plot.title.position = "plot"
)
}En este documento doy continuidad al trabajo de aseguramiento y control de la calidad que desarrollé en la Semana 5 sobre una base clínica observacional de pacientes hospitalizados por síndrome coronario agudo.
Allí depuré la base de forma reproducible y caractericé el patrón de los datos faltantes, pero dejé deliberadamente pendientes dos preguntas que no resolví entonces y que constituyen el objeto de este entregable de la semana 6:
cuál es el mecanismo que genera esa ausencia: si es completamente al azar (MCAR), al azar (MAR) o no al azar (MNAR), y
cómo imputar los valores faltantes de la manera más adecuada.
Sigo para ello la guía del taller sobre el problema de los datos faltantes, apoyándome en la literatura metodológica que la sostiene.
Retomo exactamente donde quedé en el taller 5:
la base depurada de la Semana 5, con sus 2.500 pacientes, en la que ya identifiqué y eliminé los registros duplicados
convertí en faltantes los seis valores biológicamente imposibles y
describí una ausencia cercana al 18% concentrada en cuatro variables: el colesterol total, la creatinina, el HDL y el tabaquismo, que resultó dispersa entre pacientes distintos.
En aquel momento concluí que esa ausencia importaba y exigía un manejo cuidadoso, pero advertí también, como limitación, que al desconocer su mecanismo los resultados de esas variables descansaban sobre los casos disponibles; ese es justamente el vacío que ahora voy a abordar.
La ruta que recorreré es la siguiente:
1. Reconstrucción de la base depurada: Reproduciré de forma compacta el flujo de limpieza de la Semana 5, consistente en cargar la base, estandarizar nombres, eliminar duplicados, convertir las categóricas a factores y marcar como faltantes los valores imposibles, para recuperar la base de 2.500 pacientes sobre la cual trabajaré, manteniendo el documento autocontenido y trazable.
2. Marco conceptual de los mecanismos de pérdida: Definiré con precisión los tres mecanismos de pérdida, como son MCAR (Missing Completely At Random, es decir, falta completamente al azar), MAR (Missing At Random, esto es, falta al azar condicionada a lo observado) y MNAR (Missing Not At Random, o falta no al azar), y explicaré las consecuencias de cada uno sobre la validez de las estimaciones, siguiendo la guía de la semana y los artículos de referencia.
3. Exploración del patrón de ausencia: Cuantificaré y visualizaré la ausencia con el conjunto de herramientas de la librería {finalfit}, para identificar en qué variables se concentra y cómo se reparte entre los pacientes.
4. Diagnóstico del mecanismo: Contrastaré la asociación entre la ausencia y las variables observadas y aplicaré una prueba formal, con el fin de decidir, sobre la evidencia y no sobre una suposición, ante cuál mecanismo me encuentro.
5. Métodos para manejar la ausencia y justificación: Revisaré el abanico de estrategias disponibles en R, como la eliminación, la imputación simple y la imputación múltiple, con sus bondades y limitaciones, y justificaré el método que elija a la luz del mecanismo que diagnostique y de la magnitud de la ausencia.
6. Imputación múltiple y comparación: Aplicaré la imputación y compararé las estadísticas originales con las obtenidas tras imputar, para medir su efecto sobre la descripción de la muestra.
7. Conclusiones y limitaciones: Sintetizaré lo aprendido y reconoceré lo que condiciona la interpretación.
Con esta hoja de ruta abordaré los cuatro elementos siguientes: — la exploración del patrón, la evidencia del mecanismo, la justificación del método y la tabla comparativa, además mantendré la trazabilidad que vengo sosteniendo desde la fase de calidad, en el taller anterior que realicé.
Antes de iniciar dejo explícitas las fuentes que sostendrán mis decisiones sobre el mecanismo de pérdida y la imputación, pues a diferencia del taller previo, donde el marco lo encabezaron las revisiones clínicas y el análisis exploratorio de datos, aquí el núcleo teórico proviene de la literatura recomendada en relación a datos faltantes, lo cual complementaré con la guía de la semana y enlazaré con el marco de limpieza que ya utilicé.
Referencia 1 — Van den Broeck J, Argeseanu Cunningham S, Eeckels R, Herbst K (2005). “Data Cleaning, Detecting, Diagnosing, and Editing Data Abnormalities”. PLoS Medicine:
Este artículo metodológico trata sobre la falta o el exceso de datos, que figura como una de las cuatro anomalías básicas que se buscan en la fase de tamizaje, dentro de un proceso de tres fases:
El aprendizaje que tomo es su principio central sobre la ausencia, a saber, que su tratamiento no es único, porque la decisión de eliminar las filas incompletas o manejar la falta variable por variable depende de cuánta ausencia hay y, sobre todo, de cómo se distribuye (Van den Broeck et al., 2005, en su descripción de la fase de tratamiento).
Considero que es justamente ese principio el que me autoriza a diagnosticar primero el mecanismo antes de decidir, en lugar de imputar por que sí; además recomienda documentar el manejo de los faltantes, que es lo que haré a lo largo del trabajo.
Referencia 2 — Dong Y, Peng CYJ (2013). “Principled missing data methods for researchers”. SpringerPlus:
Este documento explica por qué los datos faltantes importan, pues introducen sesgo en los parámetros, pérdida de información, menor potencia estadística, errores estándar más grandes y una generalización debilitada (Dong y Peng, 2013).
Establece que, antes de elegir un método, debo examinar tres cosas: la proporción de ausencia, el mecanismo y el patrón.
Sobre la proporción reúne dos umbrales de referencia que me serán útiles, ya que una tasa de faltantes del 5% o menos se considera intrascendente (Schafer, citado por los autores), mientras que por encima del 10% el análisis tiende a sesgarse (Bennett, citado por los autores), aunque advierte que el mecanismo y el patrón pesan más que el porcentaje crudo.
Sobre el mecanismo presenta los tres tipos de Rubin (1976), que son MCAR (Missing Completely At Random, es decir, falta completamente al azar), MAR (Missing At Random, esto es, falta al azar condicionada a lo observado) y MNAR (Missing Not At Random, o falta no al azar), junto con los métodos llamados “principled” (es decir, basados en principios estadísticos), esto es, la imputación múltiple, la máxima verosimilitud con información completa y el algoritmo de esperanza-maximización.
De aquí tomo una asimetría decisiva sobre cuáles mecanismos puedo verificar, pues la condición MCAR (Missing Completely At Random, es decir, falta completamente al azar) sí puede contrastarse con una prueba estadística formal, la prueba de Little, propuesta por Roderick Little en 1988, que evalúa de manera global, sobre todas las variables a la vez, si los patrones de ausencia son compatibles con un origen completamente aleatorio.
Su hipótesis nula es que los datos son MCAR (Missing Completely At Random, es decir, falta completamente al azar), de modo que un valor p alto (por encima de 0,05) significa que no encuentro evidencia para descartar esa condición, mientras que un valor p bajo me lleva a rechazarla (Little, citado por Dong y Peng, 2013).
En cambio, la condición MAR (Missing At Random, esto es, falta al azar condicionada a lo observado) es, en rigor, no comprobable a partir de los datos observados por sí solos, porque exigiría conocer los valores que precisamente faltan; por eso, como ya señalé con Bhaskaran y Smeeth (2014), MAR no se demuestra con una prueba sino que se argumenta con el conocimiento del contexto.
Un ejemplo que me ayudó a entender la falta al azar es el de un curso de cálculo con prueba inicial y final, donde los estudiantes con baja calificación inicial abandonan más y por eso les falta la prueba final, de modo que la ausencia en la final depende solo de la inicial, que sí se observó (Dong y Peng, 2013).
Usaré este artículo como columna vertebral tanto del capítulo conceptual de los mecanismos como de la revisión de métodos, porque no solo explica qué es cada método sino sus méritos relativos; por ejemplo, que la imputación múltiple maneja con más facilidad las variables categóricas y las auxiliares, mientras que los métodos basados en verosimilitud son un poco más eficientes.
Referencia 3 — Bhaskaran K, Smeeth L (2014). “What is the difference between missing completely at random and missing at random?”. International Journal of Epidemiology:
Es la fuente que encontré más clara, escrita como un diálogo entre un investigador clínico y un estadístico, y existe precisamente porque la condición de falta al azar se malinterpreta de forma constante.
De ella aprendo la distinción que está en el corazón de mi diagnóstico, a saber, que la falta completamente al azar significa que los datos ausentes son un subconjunto aleatorio, sin diferencias sistemáticas frente a los observados; que la falta al azar admite diferencias sistemáticas, pero estas quedan enteramente explicadas por las variables observadas; y que la falta no al azar ocurre cuando la ausencia depende del propio valor no observado (Bhaskaran y Smeeth, 2014).
El ejemplo que me lo aclara, es el de la presión arterial, donde los pacientes jóvenes y sanos tienden a no tener el dato y además tienen presiones más bajas, lo que hace que la distribución de los ausentes difiera de la de los observados.
El estadístico muestra que eso solo prueba que la falta no es completamente al azar, y que aún puede ser falta al azar si, dentro de estratos de edad y enfermedad cardiovascular, las distribuciones de ausentes y observados se parecen.
El contraste con la falta no al azar lo da con el índice de masa corporal, pues si el clínico lo registra justamente porque ve que el paciente tiene sobrepeso, entonces incluso dentro de un estrato el registro depende del valor mismo.
El aprendizaje que tomo es que la falta al azar es una condición condicional (si me restrinjo a un grupo similar en las variables observadas, la ausencia es aleatoria) y que se argumenta con conocimiento clínico del contexto, no se demuestra desde los datos; es exactamente el razonamiento que aplicaré al interpretar la asociación entre la ausencia y las variables observadas.
Referencia 4 — Austin PC, White IR, Lee DS, van Buuren S (2021). “Missing Data in Clinical Research: A Tutorial on Multiple Imputation”. Canadian Journal of Cardiology:
Este artículo es un manual práctico de la imputación, pues empieza por explicar por qué fallan los atajos históricos, pues el análisis de casos completos pierde precisión y puede sesgar cuando faltan covariables, y la imputación por la media reduce de forma artificial la varianza e ignora las relaciones entre variables (Austin et al., 2021).
Desarrolla el algoritmo de imputación multivariada por ecuaciones encadenadas, en el que cada variable se imputa condicionada a todas las demás, en ciclos que se repiten varias veces; y el método de emparejamiento por media predicha para variables continuas, que en lugar de extraer un valor de una distribución normal (lo que podría generar valores imposibles, como una concentración negativa) toma el valor observado de un paciente real parecido, respetando la forma de los datos.
Aporta también las reglas de Rubin para combinar los resultados, donde la estimación combinada es el promedio y la varianza total suma la incertidumbre dentro y entre imputaciones, y una regla práctica sobre cuántas imputaciones hacer, al menos tantas como el porcentaje de sujetos con algún faltante (White y colaboradores, citados por los autores).
El ejemplo que lo ilustra es su estudio de insuficiencia cardiaca con 8.338 pacientes, donde el colesterol de lipoproteína de baja densidad tenía un 73% de ausencia y, pese a ello, la imputación múltiple produjo intervalos de confianza más estrechos que el análisis de casos completos.
Usaré este artículo para justificar y ejecutar la imputación multivariada por ecuaciones encadenadas con emparejamiento por media predicha, y para decidir el número de imputaciones y qué variables incluir en el modelo.
Referencia 5 — Valencia-Orozco A. “El problema de los datos faltantes” (guía del curso, Universidad Icesi):
Es la fuente de mi práctica en R en este documento y que seguiré paso a paso, donde se plantea cinco pasos, esto es, asegurar que los datos estén bien codificados, identificar los valores que faltan en cada variable, buscar patrones de ausencia, comprobar asociaciones entre lo que falta y lo observado, y decidir cómo manejar la falta.
Toma la tipología de los mecanismos del capítulo 25 de Gelman y Hill (2007), con el ejemplo de la báscula que se quedó sin baterías para ilustrar la falta completamente al azar, donde algunos datos faltan simplemente por mala suerte.
Utilizaré, herramientas como ff_glimpse para verificar la codificación, missing_plot y missing_pattern para ver el patrón, missing_pairs y missing_compare para comprobar asociaciones, y la librería mice para la imputación múltiple junto con dlookr para la imputación simple.
El ejemplo de la guía de clase, fabricó a propósito dos variables de tabaquismo, una con falta completamente al azar y otra con falta al azar condicionada al sexo, y mostraba que missing_compare detectó la asociación entre el sexo y la ausencia del tabaquismo cuando la falta fue al azar, pero no cuando era completamente al azar, una demostración controlada de cómo el diagnóstico distinguió los dos mecanismos.
Conservo, por último, como fuentes de apoyo, el libro de Bruce, Bruce y Gedeck (2022), para el vocabulario exploratorio y las medidas robustas (mediana y rango intercuartílico) que llevaré a la tabla comparativa.
Las revisiones clínicas de Kraler (2025) y Timmis (2023) que utilicé en el taller anterior, me permitirán interpretar por qué importa la ausencia concentrada en el colesterol total, la creatinina, el colesterol de lipoproteína de alta densidad y el tabaquismo, dado que son variables que la evidencia vincula al riesgo cardiovascular.
Para diagnosticar el mecanismo de pérdida e imputar los valores faltantes necesito, como punto de partida, la base depurada que construí en el taller anterior, es decir, la versión de 2.500 pacientes sobre la que ya resolví los problemas de calidad.
Como el entorno de trabajo se reinicia entre sesiones, reproduciré aquí ese flujo de limpieza de forma compacta, con el fin de que este documento sea autocontenido y reproducible por sí mismo, sin depender de archivos intermedios del taller previo.
Lo que espero obtener con este proceso es reconstruir el objeto datos_dep, idéntico al que cerró la fase de calidad, para partir de él con plena trazabilidad.
El flujo encadena cinco pasos que ya justifiqué en su momento, apoyada en el marco de limpieza de Van den Broeck et al. (2005), y que ahora ejecuto de corrido:
El propósito de que declare estos pasos por separado es dejar constancia, de que no se trata de un atajo, sino de la misma cadena de decisiones documentada antes,además, al final verificaré las dimensiones de la base para confirmar que recuperé los 2.500 pacientes y las 23 variables.
datos_crudos <- readxl::read_excel("cardiology_dataset.xlsx") |> janitor::clean_names()
datos_sin_dup <- datos_crudos |> dplyr::distinct()
bin_vars <- c("diabetes","hypertension","heart_failure","treat_statin","treat_beta_blocker","treat_acei","mortality_30d","readmission_30d")
datos_factores <- datos_sin_dup |>
dplyr::mutate(dplyr::across(dplyr::all_of(bin_vars), ~ factor(.x, levels = c("No","Yes"), labels = c("No","S\u00ed"))))
datos_factores <- datos_factores |>
dplyr::mutate(sex = factor(sex, levels = c("Female","Male"), labels = c("Femenino","Masculino")))
datos_factores <- datos_factores |>
dplyr::mutate(smoking_status = factor(smoking_status, levels = c("Never","Former","Current"), labels = c("Nunca","Exfumador","Fumador actual")))
marcar_imposible <- function(x, minimo = -Inf, maximo = Inf) {
x[!is.na(x) & (x < minimo | x > maximo)] <- NA
x
}
datos_dep <- datos_factores |>
dplyr::mutate(age = marcar_imposible(.data$age, minimo = 0, maximo = 120),
bmi = marcar_imposible(.data$bmi, minimo = 0),
systolic_bp = marcar_imposible(.data$systolic_bp, minimo = 0),
ejection_fraction = marcar_imposible(.data$ejection_fraction, maximo = 100),
troponin = marcar_imposible(.data$troponin, minimo = 0))
dim(datos_dep)#> [1] 2500 23
Una vez reconstruida la base, presentaré un cuadro que resuma el conteo y el porcentaje de valores faltantes por variable. Con este proceso espero obtener una confirmación de que la reconstrucción reprodujo exactamente la ausencia que caractericé en el taller previo y, al mismo tiempo, dejar a la vista en qué variables se concentra la falta, de modo que entre al diagnóstico del mecanismo sabiendo con precisión dónde está el problema.
La lógica del cuadro se apoya en uno de los umbrales que recogí del marco teórico, pues coloreo cada fila según cruce o no la referencia del 5%, esto es, marco en un tono las variables cuya ausencia supera ese 5% (la falta deja de ser intrascendente y exige un manejo cuidadoso) y en otro tono las que quedan en el 5% o por debajo (ausencia mínima, que el análisis de casos completos podría tolerar), siguiendo el criterio que reúnen Dong y Peng (2013).
El color no decide el mecanismo, que aún no he diagnosticado, sino que solo me ayuda a graduar la magnitud de la ausencia para orientar mi lectura.
etiquetas_faltantes <- c(
chol_total = "Colesterol total (mg/dL)",
creatinine = "Creatinina s\u00e9rica (mg/dL)",
smoking_status = "Estado de tabaquismo",
hdl = "Colesterol HDL (mg/dL)",
troponin = "Troponina ultrasensible (ng/mL)",
bmi = "\u00cdndice de masa corporal (kg/m\u00b2)",
ldl = "Colesterol (mg/dL)",
age = "Edad (a\u00f1os)",
systolic_bp = "Presi\u00f3n arterial sist\u00f3lica (mmHg)",
ejection_fraction = "Fracci\u00f3n de eyecci\u00f3n (%)"
)
panorama_faltantes <- datos_dep |>
dplyr::summarise(dplyr::across(dplyr::everything(), ~ sum(is.na(.x)))) |>
tidyr::pivot_longer(dplyr::everything(), names_to = "variable", values_to = "faltantes") |>
dplyr::filter(.data$faltantes > 0) |>
dplyr::arrange(dplyr::desc(.data$faltantes)) |>
dplyr::mutate(
etiqueta = etiquetas_faltantes[.data$variable],
total = nrow(datos_dep),
porcentaje = .data$faltantes / .data$total * 100,
relevancia = dplyr::if_else(.data$porcentaje > 5, "Supera el 5% (manejo cuidadoso)", "Hasta el 5% (ausencia m\u00ednima)")
) |>
dplyr::select(etiqueta, faltantes, total, porcentaje, relevancia)
panorama_faltantes |>
flextable::flextable() |>
flextable::set_header_labels(
etiqueta = "Variable",
faltantes = "Faltantes (n)",
total = "Total de registros (N)",
porcentaje = "Porcentaje de faltantes (%)",
relevancia = "Clasificaci\u00f3n seg\u00fan el umbral del 5%"
) |>
flextable::colformat_double(j = "porcentaje", digits = 2, decimal.mark = ",") |>
tema_flex() |>
flextable::align(j = c("etiqueta", "relevancia"), align = "left", part = "all") |>
flextable::bg(i = ~ porcentaje > 5, bg = "#FBE4E4", part = "body") |>
flextable::bg(i = ~ porcentaje <= 5, bg = "#FDF3E0", part = "body") |>
flextable::set_caption("Panorama de valores faltantes en la base depurada reconstruida (n = 2.500)")Variable | Faltantes (n) | Total de registros (N) | Porcentaje de faltantes (%) | Clasificación según el umbral del 5% |
|---|---|---|---|---|
Colesterol total (mg/dL) | 450 | 2,500 | 18,00 | Supera el 5% (manejo cuidadoso) |
Creatinina sérica (mg/dL) | 450 | 2,500 | 18,00 | Supera el 5% (manejo cuidadoso) |
Estado de tabaquismo | 449 | 2,500 | 17,96 | Supera el 5% (manejo cuidadoso) |
Colesterol HDL (mg/dL) | 448 | 2,500 | 17,92 | Supera el 5% (manejo cuidadoso) |
Índice de masa corporal (kg/m²) | 11 | 2,500 | 0,44 | Hasta el 5% (ausencia mínima) |
Troponina ultrasensible (ng/mL) | 11 | 2,500 | 0,44 | Hasta el 5% (ausencia mínima) |
Colesterol (mg/dL) | 10 | 2,500 | 0,40 | Hasta el 5% (ausencia mínima) |
Edad (años) | 2 | 2,500 | 0,08 | Hasta el 5% (ausencia mínima) |
Presión arterial sistólica (mmHg) | 1 | 2,500 | 0,04 | Hasta el 5% (ausencia mínima) |
Fracción de eyección (%) | 1 | 2,500 | 0,04 | Hasta el 5% (ausencia mínima) |
Análisis: El cuadro confirma que la reconstrucción de la base reprodujo exactamente la ausencia que ya había caracterizado, lo cual me da la garantía de trazabilidad que buscaba para partir sobre terreno conocido.
Para leer el cuadro aclaro el criterio que apliqué, pues clasifiqué y coloreé cada variable según la referencia del 5% que recogí del marco teórico (Dong y Peng, 2013), de modo que la columna de clasificación y el color trabajan juntos:
en rosado, y señaladas como que superan el 5%, las variables cuya ausencia exige un manejo cuidadoso.
en ámbar, y señaladas como ausencia mínima, las que quedan hasta el 5%, que el análisis de casos completos podría tolerar.
Se observa que la falta se ordena en dos bloques claramente separados por su magnitud, así:
Un bloque alto, en torno al 18%: Encabezado por el colesterol total y la creatinina sérica con 450 faltantes cada una (18,00%), seguidos del estado de tabaquismo con 449 (17,96%) y el colesterol de lipoproteína de alta densidad con 448 (17,92%).
Un bloque mínimo, por debajo del 0,5%: Reúne el índice de masa corporal y la troponina con 11 faltantes (0,44%), el colesterol de lipoproteína de baja densidad con 10 (0,40%), y la edad, la presión arterial sistólica y la fracción de eyección con apenas 1 o 2 faltantes (entre 0,04% y 0,08%); estos últimos corresponden, en parte, a los valores biológicamente imposibles que convertí en faltantes durante la depuración.
Considero que esta separación es importante, pues son cuatro las variables que concentran prácticamente toda la ausencia, todas ellas laboratorios (colesterol total, creatinina y colesterol de lipoproteína de alta densidad) más un dato de anamnesis (el tabaquismo).
Según el criterio que reúnen Dong y Peng (2013), estas cuatro variables se ubican muy por encima del 5% que permitiría considerar la ausencia intrascendente, por lo que no puedo ignorarlas ni resolverlas eliminando filas sin antes entender por qué faltan; ese es justamente el motivo por el que el siguiente paso no es imputar, sino diagnosticar el mecanismo de pérdida.
Quiero dejar una precisión metodológica, y es que este cuadro mide cuánta ausencia hay y dónde se concentra, pero todavía no me dice por qué falta cada dato; el porcentaje, por sí solo, no distingue entre los tres mecanismos posibles, de modo que la magnitud orienta la prioridad, pero el mecanismo exige las pruebas que aplicaré más adelante.
Antes de explorar la ausencia en mi base, necesito entender bien los tres mecanismos que pueden producirla, por tanto,hago énfasis en esto desde el comienzo, porque lo que decide cómo debo tratar los faltantes no es cuántos hay, sino por qué faltan (Dong y Peng, 2013).
La idea central, es que los tres mecanismos se distinguen por una sola pregunta: ¿de qué depende que un dato falte?puede depender de nada, de lo que sí observé, o de lo que no alcancé a ver, por lo cual,esa es toda la diferencia, y de ella se desprende lo demás,esto es una clasificación que proviene de Rubin (1976).
Aquí la falta no depende de nada, pues todos los pacientes tienen la misma probabilidad de que un dato les falte, sin importar quiénes son ni qué valores tienen, por lo cual, los datos ausentes son, por así decirlo, una muestra al azar de toda la base (Bhaskaran y Smeeth, 2014).
El ejemplo que mejor lo explica es el de una báscula que se queda sin baterías a mitad de una jornada, donde los pesos que no se registraron se perdieron por pura mala suerte, no porque esos pacientes pesaran más o menos (Gelman y Hill, 2007).
Me pregunto entonces ¿Qué implica esto para mis resultados? y esto es el escenario más amable, porque perder estos datos me deja con menos información, pero no me engaña, dado que las estimaciones pierden precisión, pero no se sesgan (Dong y Peng, 2013). Por eso es el único caso en que puedo descartar las filas incompletas sin distorsionar nada. Y es, además, el único de los tres que puedo poner a prueba con una prueba estadística.
Aquí la falta depende de lo que sí observé, pero no del valor que se perdió; dicho de otro modo, si agrupo a los pacientes según las variables que tengo completas, dentro de cada grupo la ausencia vuelve a ser aleatoria. (Bhaskaran y Smeeth, 2014).
Lo veo mejor con un ejemplo, como el de un curso de cálculo con un examen al inicio y otro al final, donde los estudiantes que sacaron baja nota en el primero tienden a abandonar, así que les falta el examen final, luego la ausencia de la nota final depende de la nota inicial, que sí conozco, no de la nota final que habrían sacado (Dong y Peng, 2013).
En lo clínico pasa igual cuando, por ejemplo, a los pacientes jóvenes y sanos se les omite con más frecuencia la presión arterial, pues la falta depende de su edad y su estado, que son datos que tengo, no del valor de presión que no se midió (Bhaskaran y Smeeth, 2014).
Ahora mi pregunta es ¿Qué implica para mis resultados?pues si simplemente borro los incompletos, puedo estar sesgando; pero la situación tiene arreglo, porque la información que explica la ausencia está en mis propias variables observadas, y esto es justamente el terreno donde la imputación múltiple funciona bien, pues se apoya en esas variables para estimar lo que me falta (Austin et al., 2021).
Eso sí, hay un punto delicado que debo subrayar, y es que la falta al azar no se puede demostrar con una prueba, porque para comprobarla necesitaría conocer los valores que justamente me faltan, lo cual se sostiene con argumentos del contexto clínico, no con un valor p (Bhaskaran y Smeeth, 2014).
Aquí está el caso más complicado, pues la falta depende del propio valor que se perdió, y eso sigue siendo cierto aunque tenga en cuenta todas las demás variables; la razón de la ausencia es precisamente el dato que no se registró (Bhaskaran y Smeeth, 2014).
El ejemplo puede ser el de un médico que anota el índice de masa corporal solo cuando ve al paciente con sobrepeso, entonces el que el dato exista depende del valor mismo que se quería medir, y eso no lo arregla ningún grupo de comparación (Bhaskaran y Smeeth, 2014); algo parecido ocurre cuando un tratamiento incómodo hace que los pacientes más afectados abandonen el estudio, donde la ausencia depende de un malestar que nunca quedó registrado (Gelman y Hill, 2007).
¿Qué implica para mis resultados? Es el peor escenario, porque el sesgo que introduce no se puede corregir solo con los datos que tengo (Dong y Peng, 2013), por lo cual, manejarlo me exige modelar el porqué de la ausencia, lo que escapa al alcance de este trabajo.
Si tuviera que resumirlo diría que todo se reduce a de qué depende que un dato falte? puede ser, de nada (completamente al azar), de lo que veo (al azar), o de lo que no veo (no al azar).
Y esto no es solo teoría, sino que va a la acción, pues medefine qué puedo hacer con mis faltantes, como borrar filas, pero solo es seguro en el primer caso, o también puedo hacer imputación múltiple que sirve para los dos primeros, y el tercero va exigir herramientas que van más allá de este trabajo (Dong y Peng, 2013; Austin et al., 2021).
Por eso mi siguiente paso es claro, pues antes de imputar nada, tengo que reunir evidencia de cuál de estos tres mecanismos encaja mejor con mi base, y para ello combinaré la prueba formal de la falta completamente al azar con el examen de si la ausencia se relaciona con mis variables observadas; y de ese diagnóstico me ocupo enseguida
Con la base reconstruida y el panorama de magnitud ya a la vista, doy el siguiente paso en el manejo de los faltantes, que consiste en explorar el patrón de la ausencia con mayor detalle.
Mi objetivo en esta sección todavía no es diagnosticar el mecanismo, sino describir con precisión dos cosas: en qué variables se concentra la falta y, sobre todo, cómo se reparte entre los pacientes, es decir, si las celdas vacías se agrupan en los mismos pacientes o se dispersan, pues esa descripción es el insumo que luego argumentará el diagnóstico.
Para ello aplicaré el conjunto de herramientas de la librería finalfit y que corresponde a dos de los cinco pasos, como identificar los valores que faltan en cada variable y buscar patrones de ausencia, por tanto, usaré tres funciones, cada una de las cuales responde una pregunta distinta:
ff_glimpse, para verificar que cada variable esté correctamente codificada y cuantificar la ausencia por variable, separando las continuas de las categóricas.
missing_plot, para visualizar la ausencia como un mapa y observar cómo se distribuye entre los pacientes.
missing_pattern, para revelar si las variables faltan juntas, en los mismos pacientes, o por separado.
A diferencia del taller anterior, donde exploré la ausencia con las librerías naniar y visdat, aquí empleo el instrumental de finalfit, para este propósito.
Comienzo verificando la codificación de cada variable, esto es, las cuantitativas como numéricas y las cualitativas como factores.
Con la función ff_glimpse espero obtener dos cosas a la vez:
una verificación de que la codificación sea correcta y un resumen de la ausencia por variable, que la función presenta separando las variables continuas de las categóricas, y
reportando para cada una su número de datos con valor, su número y porcentaje de faltantes y, en el caso de las categóricas, sus niveles.
Todo esto para llegar al diagnóstico con la certeza de que ninguna variable está mal tipada, y para contrastar este recuento con finalfit,de modo que ambas miradas coincidan.
dependent <- "mortality_30d"
explanatory <- c(
"age", "sex", "bmi", "systolic_bp", "diastolic_bp",
"chol_total", "ldl", "hdl", "triglycerides", "troponin",
"creatinine", "ejection_fraction", "diabetes", "hypertension",
"heart_failure", "smoking_status", "treat_statin",
"treat_beta_blocker", "treat_acei", "length_of_stay", "readmission_30d"
)
datos_dep |>
finalfit::ff_glimpse(dependent, explanatory)#> $Continuous
#> label var_type n missing_n missing_percent
#> age age <dbl> 2498 2 0.1
#> bmi bmi <dbl> 2489 11 0.4
#> systolic_bp systolic_bp <dbl> 2499 1 0.0
#> diastolic_bp diastolic_bp <dbl> 2500 0 0.0
#> chol_total chol_total <dbl> 2050 450 18.0
#> ldl ldl <dbl> 2490 10 0.4
#> hdl hdl <dbl> 2052 448 17.9
#> triglycerides triglycerides <dbl> 2500 0 0.0
#> troponin troponin <dbl> 2489 11 0.4
#> creatinine creatinine <dbl> 2050 450 18.0
#> ejection_fraction ejection_fraction <dbl> 2499 1 0.0
#> length_of_stay length_of_stay <dbl> 2500 0 0.0
#> mean sd min quartile_25 median quartile_75 max
#> age 65.4 12.7 23.0 57.0 65.0 74.0 95.0
#> bmi 27.9 5.2 15.0 24.4 27.8 31.3 95.0
#> systolic_bp 130.4 19.8 90.0 117.0 130.0 144.0 198.0
#> diastolic_bp 79.8 9.9 50.0 73.0 80.0 86.0 114.0
#> chol_total 201.2 39.6 120.0 173.0 201.0 228.0 337.0
#> ldl 120.7 29.8 50.0 100.0 121.0 141.0 250.0
#> hdl 50.2 14.9 15.0 40.0 50.0 61.0 100.0
#> triglycerides 155.3 47.2 50.0 121.0 149.0 182.0 439.0
#> troponin 0.1 1.5 0.0 0.0 0.1 0.1 75.0
#> creatinine 1.0 0.3 0.4 0.8 1.0 1.2 2.3
#> ejection_fraction 54.7 9.7 18.4 47.8 54.9 61.4 75.0
#> length_of_stay 6.0 2.2 1.0 4.0 6.0 7.0 15.0
#>
#> $Categorical
#> label var_type n missing_n missing_percent
#> mortality_30d mortality_30d <fct> 2500 0 0.0
#> sex sex <fct> 2500 0 0.0
#> diabetes diabetes <fct> 2500 0 0.0
#> hypertension hypertension <fct> 2500 0 0.0
#> heart_failure heart_failure <fct> 2500 0 0.0
#> smoking_status smoking_status <fct> 2051 449 18.0
#> treat_statin treat_statin <fct> 2500 0 0.0
#> treat_beta_blocker treat_beta_blocker <fct> 2500 0 0.0
#> treat_acei treat_acei <fct> 2500 0 0.0
#> readmission_30d readmission_30d <fct> 2500 0 0.0
#> levels_n levels
#> mortality_30d 2 "No", "Sí", "(Missing)"
#> sex 2 "Femenino", "Masculino", "(Missing)"
#> diabetes 2 "No", "Sí", "(Missing)"
#> hypertension 2 "No", "Sí", "(Missing)"
#> heart_failure 2 "No", "Sí", "(Missing)"
#> smoking_status 3 "Nunca", "Exfumador", "Fumador actual", "(Missing)"
#> treat_statin 2 "No", "Sí", "(Missing)"
#> treat_beta_blocker 2 "No", "Sí", "(Missing)"
#> treat_acei 2 "No", "Sí", "(Missing)"
#> readmission_30d 2 "No", "Sí", "(Missing)"
#> levels_count levels_percent
#> mortality_30d 2276, 224 91, 9
#> sex 1160, 1340 46, 54
#> diabetes 1751, 749 70, 30
#> hypertension 994, 1506 40, 60
#> heart_failure 1863, 637 75, 25
#> smoking_status 936, 712, 403, 449 37, 28, 16, 18
#> treat_statin 734, 1766 29, 71
#> treat_beta_blocker 1038, 1462 42, 58
#> treat_acei 1248, 1252 50, 50
#> readmission_30d 2108, 392 84, 16
Análisis: La función ff_glimpse me devuelve la base partida en dos retratos, el de las variables continuas y el de las categóricas, lo cual es coherente con la naturaleza de cada grupo, pues a una variable numérica le corresponden medidas de centro y dispersión, mientras que a una categórica le corresponden sus niveles y frecuencias (Bruce, Bruce y Gedeck, 2022).
Antes de leer los faltantes verifico la codificación, que es la condición que da validez a todo lo que sigue:
En el primer bloque, el de variables continuas, cada fila es una variable numérica y las columnas describen su naturaleza y su completitud, así:
La columna var_type: registra el tipo con que R
almacena la variable, y en las doce numéricas marca
La columna n: indica cuántos pacientes tienen valor en esa variable, y missing_n y missing_percent cuántos y qué proporción no lo tienen.
Las columnas de mean, sd, min, los tres cuartiles y max: resumen el centro, la dispersión y el recorrido de cada variable.
La lectura de la ausencia en este bloque reproduce con exactitud lo que ya había cuantificado sobre: - el colesterol total y la creatinina aparecen con 2.050 datos con valor y 450 faltantes (18,0%) - el colesterol de lipoproteína de alta densidad con 2.052 y 448 (17,9%) - mientras la troponina y el índice de masa corporal registran 11 faltantes (0,4%) - el colesterol de lipoproteína de baja densidad 10 (0,4%) y la edad, la presión sistólica y la fracción de eyección apenas 1 o 2 - la presión diastólica, los triglicéridos y la estancia no pierden ningún dato.
Que este recuento, obtenido ahora con finalfit, coincida con el del panorama me da una verificación cruzada de que la base reconstruida es la correcta.
Un detalle que me confirma la coherencia clínica de la codificación es la troponina, cuya media de 0,1 ng/mL queda muy por encima de su mediana, también próxima a 0,1, con un máximo de 75,0; esa distancia entre el centro y el extremo es la firma de una distribución de cola larga, esperable en un marcador de daño miocárdico donde una minoría de pacientes concentra los valores más altos (Kraler et al., 2025). Lo señalo porque verifica que la variable está bien medida, no que ya la esté analizando.
En el segundo bloque, el de variables categóricas, cada fila es una variable cualitativa y las columnas describen su estructura, así:
La columna var_type marca
Las columnas de levels_n y levels muestran cuántas categorías tiene cada variable y cuáles son, y levels_count y levels_percent el número y el porcentaje de pacientes en cada una.
Aquí encuentro un punto que mi codificación deja a la vista, pues la lista de niveles incluye una categoría “(Missing)” que finalfit muestra de forma explícita junto a las categorías reales.
En el tabaquismo, la única categórica con ausencia, esa categoría reúne 449 pacientes (18,0%), de modo que sus niveles se reparten en “Nunca” (936), “Exfumador” (712), “Fumador actual” (403) y los 449 sin dato.
las nueve categóricas restantes no pierden ningún registro. Considero relevante que la ausencia categórica se concentre por completo en el tabaquismo, pues es un dato de anamnesis que no siempre queda consignado, a diferencia de variables como el sexo o los desenlaces, que aparecen completos.
Reuniendo los dos bloques, la verificación de la codificación resulta satisfactoria, ya que las doce variables cuantitativas se almacenan como numéricas y las diez cualitativas como factores, condición sin la cual ni el diagnóstico del mecanismo ni la imputación serían fiables (Dong y Peng, 2013).
Ahora la ausencia, vista con este instrumento, ratifica el mapa que ya conocía, esto es, cuatro variables que concentran casi toda la falta, tres de laboratorio (colesterol total, creatinina y colesterol de lipoproteína de alta densidad) y una de anamnesis (el tabaquismo), todas vinculadas al riesgo cardiovascular y, por ello, relevantes para el estudio (Kraler et al., 2025).
Con la codificación confirmada, puedo examinar cómo se reparte esa ausencia entre los pacientes.
Continúo la exploración del patrón con un mapa de la ausencia, que es la forma visual de responder una pregunta que el recuento numérico no resuelve por sí solo:
cómo se reparte la falta entre los pacientes?.
Para ello emplearé la función missing_plot de la librería finalfit, sobre el mismo desenlace y el mismo conjunto de variables que definí antes.
Con este proceso espero obtener un mapa en el que cada paciente ocupa una posición en el eje horizontal y cada variable una fila en el eje vertical, y donde una marca señala que ese paciente no tiene dato en esa variable, mientras el resto de la cuadrícula queda vacío indicando los valores presentes.
La lógica de esta gráfica está en lo que me permite observar, así:
Esa distinción importa porque la decisión de cómo manejar la falta depende no solo de cuánta hay, sino de cómo se distribuye entre los registros (Van den Broeck et al., 2005), por lo cual, la presento en un solo color, por tratarse de una exploración del patrón sin comparación entre grupos.
Aclaro que en este punto solo describiré la distribución espacial de la ausencia, no su causa; observar dónde caen las marcas es el paso previo que necesito antes de contrastar formalmente el mecanismo.
Análisis: El mapa de valores faltantes traduce la distribución de la ausencia en toda la base, por lo cual, la estructura del mapa es la siguiente:
El eje horizontal (Observation): ordena a los 2.500 pacientes según su posición en la base, de modo que cada columna vertical, por delgada que sea, corresponde a un paciente individual; la escala va de 0 a 2.500.
El eje vertical lista las 23 variables, una por fila.
El fondo oscuro marca los valores presentes y cada línea clara vertical marca un valor ausente, esto es, la celda donde un paciente determinado no tiene dato en una variable determinada.
De modo que la pregunta que esta gráfica responde es dónde, y en qué pacientes, se ubica la ausencia, lo cual complementa el recuento que ya tenía, pues una cosa es saber cuánto falta y otra distinta es ver cómo se reparte (Van den Broeck et al., 2005).
Al recorrer las filas reconozco de inmediato el patrón que ya había cuantificado, pues solo cuatro filas presentan una densidad apreciable de líneas claras, las del colesterol total, el colesterol de lipoproteína de alta densidad, la creatinina y el estado de tabaquismo, mientras el resto de las filas se ve casi enteramente oscuro.
Las demás variables apenas muestran trazos sueltos, esto es, unas pocas líneas en el índice de masa corporal, la troponina, el colesterol de lipoproteína de baja densidad y dos marcas aisladas en la edad y en la fracción de eyección, que corresponden a su ausencia mínima y, en parte, a los valores imposibles que convertí en faltantes durante la depuración.
Variables como el sexo, los signos vitales, las comorbilidades, los tratamientos y los dos desenlaces no muestran ninguna línea, confirmando que están completas.
Ahora bien, lo decisivo de este mapa no es cuántas líneas hay, sino cómo se disponen, y aquí observo el hallazgo central, esto es, que dentro de las cuatro filas con ausencia las líneas claras se reparten salpicadas a lo largo de todo el eje horizontal, sin alinearse verticalmente entre sí.
Es decir,las marcas del colesterol total no caen en las mismas posiciones que las de la creatinina, ni estas coinciden con las del tabaquismo o el colesterol de lipoproteína de alta densidad.
Interpreto que esa ausencia de alineación vertical significa que no es un mismo subgrupo de pacientes el que carece de las cuatro variables a la vez, sino que son pacientes distintos los que pierden cada una.
Por ejemplo, si la falta se concentrara en los mismos registros, esperaría ver las líneas apiladas formando columnas continuas a lo ancho de varias filas, lo cual no ocurre.
Esta distribución dispersa, repartida de manera homogénea a lo largo de toda la base y sin zonas donde la ausencia se acumule, es compatible a primera vista con un origen aleatorio de la falta, en el sentido de que no se asoma un patrón sistemático evidente (Bhaskaran y Smeeth, 2014).
Considero, además, que esta lectura tiene sentido clínico, pues las cuatro variables afectadas son tres determinaciones de laboratorio (colesterol total, creatinina y colesterol de lipoproteína de alta densidad) y un antecedente de anamnesis (el tabaquismo), justamente el tipo de dato que puede quedar sin registrar de forma puntual, ya sea porque no se solicitó el panel completo en un paciente o porque no se consignó el hábito.
Son, a la vez, variables que la evidencia vincula al riesgo cardiovascular, lo que hace que su ausencia importe y merezca un manejo cuidadoso (Kraler et al., 2025).
Debo, no obstante, ser prudente con esta lectura, pues el mapa sugiere visualmente un reparto sin sistema, pero no constituye una prueba del mecanismo, ya que la inspección visual puede mostrar que la falta parece dispersa, pero no me garantiza que sea independiente de las variables observadas (Bhaskaran y Smeeth, 2014).
Por eso esta gráfica me orienta, pero no me autoriza a concluir, y el paso siguiente es examinar si esa dispersión se confirma cuando reviso si las variables faltan juntas o por separado, y más adelante, cuando contraste formalmente la asociación entre la ausencia y lo observado.
Cierro la exploración del patrón con la función missing_pattern de la librería finalfit, que es el paso con el que la guía completa la búsqueda de patrones de ausencia.
Donde el mapa anterior me mostró la distribución de forma visual, esta función la cuantifica de manera exacta, de modo que las dos miradas se respaldan entre sí.
Con este proceso espero obtener una tabla que agrupe a los pacientes según la combinación precisa de variables que les falta, es decir, que identifique los distintos patrones de ausencia presentes en la base y cuente cuántos pacientes comparte cada uno. Su lectura funciona así:
La razón por la que este paso es importante es que el número y la estructura de los patrones de ausencia ayudan a juzgar si la falta es aleatoria o sistemática (Dong y Peng, 2013).
En concreto, espero distinguir si predominan los patrones de una sola variable ausente, lo que indicaría una falta dispersa, o si por el contrario predominan los patrones donde varias variables faltan juntas en los mismos pacientes, lo que apuntaría a una ausencia estructurada.
Esta tabla me permitirá poner número a lo que el mapa sugirió de forma visual, todavía sin afirmar el mecanismo, que reservo para el diagnóstico formal.
vars_patron <- c("chol_total", "creatinine", "hdl", "smoking_status",
"bmi", "troponin", "ldl", "age",
"systolic_bp", "ejection_fraction")
datos_dep |>
finalfit::missing_pattern(dependent, vars_patron)#> mortality_30d systolic_bp ejection_fraction age ldl bmi troponin hdl
#> 1103 1 1 1 1 1 1 1 1
#> 245 1 1 1 1 1 1 1 1
#> 256 1 1 1 1 1 1 1 1
#> 55 1 1 1 1 1 1 1 1
#> 240 1 1 1 1 1 1 1 1
#> 44 1 1 1 1 1 1 1 1
#> 59 1 1 1 1 1 1 1 1
#> 17 1 1 1 1 1 1 1 1
#> 265 1 1 1 1 1 1 1 0
#> 49 1 1 1 1 1 1 1 0
#> 34 1 1 1 1 1 1 1 0
#> 13 1 1 1 1 1 1 1 0
#> 61 1 1 1 1 1 1 1 0
#> 11 1 1 1 1 1 1 1 0
#> 6 1 1 1 1 1 1 1 0
#> 6 1 1 1 1 1 1 1 0
#> 6 1 1 1 1 1 1 0 1
#> 2 1 1 1 1 1 1 0 1
#> 1 1 1 1 1 1 1 0 1
#> 1 1 1 1 1 1 1 0 1
#> 1 1 1 1 1 1 1 0 0
#> 6 1 1 1 1 1 0 1 1
#> 2 1 1 1 1 1 0 1 1
#> 1 1 1 1 1 1 0 1 1
#> 1 1 1 1 1 1 0 1 1
#> 1 1 1 1 1 1 0 1 0
#> 4 1 1 1 1 0 1 1 1
#> 1 1 1 1 1 0 1 1 1
#> 1 1 1 1 1 0 1 1 1
#> 2 1 1 1 1 0 1 1 1
#> 1 1 1 1 1 0 1 1 1
#> 1 1 1 1 1 0 1 1 0
#> 2 1 1 1 0 1 1 1 1
#> 1 1 1 0 1 1 1 1 1
#> 1 1 0 1 1 1 1 1 1
#> 0 1 1 2 10 11 11 448
#> smoking_status chol_total creatinine
#> 1103 1 1 1 0
#> 245 1 1 0 1
#> 256 1 0 1 1
#> 55 1 0 0 2
#> 240 0 1 1 1
#> 44 0 1 0 2
#> 59 0 0 1 2
#> 17 0 0 0 3
#> 265 1 1 1 1
#> 49 1 1 0 2
#> 34 1 0 1 2
#> 13 1 0 0 3
#> 61 0 1 1 2
#> 11 0 1 0 3
#> 6 0 0 1 3
#> 6 0 0 0 4
#> 6 1 1 1 1
#> 2 1 1 0 2
#> 1 1 0 1 2
#> 1 1 0 0 3
#> 1 0 1 1 3
#> 6 1 1 1 1
#> 2 1 1 0 2
#> 1 1 0 0 3
#> 1 0 1 0 3
#> 1 1 1 0 3
#> 4 1 1 1 1
#> 1 1 1 0 2
#> 1 1 0 1 2
#> 2 0 1 1 2
#> 1 0 1 0 3
#> 1 1 1 1 2
#> 2 1 1 1 1
#> 1 1 1 1 1
#> 1 1 1 1 1
#> 449 450 450 1833
Análisis: La función missing_pattern me devuelve una matriz de patrones de ausencia, que es la representación gráfica y numérica de las combinaciones exactas en que faltan las variables; sirve para juzgar si la falta es dispersa o estructurada a partir del número y la forma de esos patrones (Dong y Peng, 2013).
Para leerla correctamente necesito primero entender qué representa cada elemento:
Cada fila es un patrón de ausencia distinto, y el número a la izquierda indica cuántos pacientes lo comparten; las filas están ordenadas de mayor a menor frecuencia.
Cada columna es una variable, y el color de la celda señala su estado en ese patrón, donde el azul indica que la variable está presente y el rosado que está ausente.
El número a la derecha de cada fila cuenta cuántas variables faltan en ese patrón, y la fila inferior totaliza cuántos valores faltan en cada variable.
Al recorrer la matriz,observo lo siguiente:
El patrón más frecuente, con mucha diferencia, es el de la fila superior, que reúne 1.103 pacientes con todas las celdas en azul y un 0 a la derecha, es decir, los casos completos que no pierden ninguna de estas variables.
Los siguientes patrones más numerosos son los de una sola variable ausente, marcados con un 1 a la derecha y una única celda rosada, esto es, 265 pacientes a quienes solo les falta el colesterol de lipoproteína de alta densidad, 256 solo el colesterol total, 245 solo la creatinina y 240 solo el tabaquismo.
Los patrones de dos o más variables ausentes son mucho menos frecuentes, con frecuencias que caen a unas pocas decenas (entre 44 y 61 pacientes en los de dos variables) y se vuelven mínimas en los de tres o cuatro, hasta el punto de que apenas 6 pacientes pierden cuatro variables a la vez.
Considero que esta estructura es la confirmación numérica de lo que el mapa anterior sugería de forma visual, y su lectura es contundente, pues la ausencia se descompone abrumadoramente en patrones de una sola variable, no en bloques donde varias falten juntas.
El argumento que considero que lo sostiene es de magnitud, ya que si las cuatro variables faltaran de manera sistemática en los mismos pacientes, esperaría un patrón dominante con esas cuatro celdas rosadas reuniendo a cientos de pacientes; en cambio, ese patrón de cuatro ausencias es de los más raros (6 pacientes), mientras los patrones de una sola variable son los que concentran a la mayoría de los registros incompletos.
Considero que la independencia entre las variables es coherente con su naturaleza clínica, pues el hecho de que a un paciente le falte el tabaquismo no lo hace más propenso a que también le falte la creatinina o el colesterol, lo que sugiere que cada dato se pierde por su propia circunstancia y no por una causa común que arrastre a varios a la vez (Van den Broeck et al., 2005). Este tipo de ausencia repartida, sin un subgrupo que concentre la falta, es la que resulta compatible a primera vista con un mecanismo aleatorio, en contraste con la ausencia monótona o estructurada que delataría un proceso sistemático (Bhaskaran y Smeeth, 2014).
Debo, sin embargo, mantener la cautela metodológica, pues esta matriz caracteriza la forma del patrón, pero no demuestra el mecanismo subyacente, ya que el número y la disposición de los patrones orientan sobre la probabilidad de que la falta sea aleatoria en lugar de sistemática, pero no la prueban (Dong y Peng, 2013).
Que la ausencia sea dispersa y no estructurada es condición favorable, mas no suficiente, para afirmar que es completamente al azar, es por eso,que con la exploración del patrón ya completa, cuento con dos evidencias convergentes, como es el mapa y la matriz, que coinciden en describir una ausencia dispersa.
Ahora el paso que seguiré es someter esa impresión a prueba, contrastando formalmente si la falta se asocia o no con las variables observadas, que es lo que abordará el diagnóstico del mecanismo.
Llego a un punto central y es que hasta aquí he descrito cuánta ausencia hay y cómo se reparte, y aunque el mapa y la matriz me sugirieron que la falta parece dispersa, dejé claro que esa es una impresión visual que todavía no prueba nada, por lo que ahora debo someterla a prueba.
Para diagnosticar el mecanismo combinaré dos aproximaciones complementarias, tal como propone la guía y respaldan los conceptos de los artículos de referencia:
El examen de las asociaciones: con la función missing_compare, que contrasta si la ausencia de cada variable se relaciona con las demás variables observadas.
y la prueba formal: con la función mcar_test, que evalúa estadísticamente si la falta es compatible con un origen completamente al azar.
En consecuencia, la falta completamente al azar es la única que puedo poner a prueba, mientras que la falta al azar se argumenta, no se demuestra, es por eso que mi estrategia es la siguiente, pues si la ausencia no se asocia con ninguna variable observada y la prueba formal no rechaza el origen aleatorio, tendré evidencia a favor de una falta completamente al azar, pero si en cambio la ausencia sí se asocia con variables observadas, eso me alejaría de ese mecanismo y me acercaría a una falta al azar (Bhaskaran y Smeeth, 2014).
Comienzo por el examen de las asociaciones,para comprobar si lo que falta se relaciona con lo observado.
vars_observadas <- c("age", "sex", "bmi", "systolic_bp", "diastolic_bp",
"triglycerides", "diabetes", "hypertension",
"heart_failure", "mortality_30d")
datos_dep |>
finalfit::missing_compare("chol_total", vars_observadas)Análisis: La función missing_compare tomó el colesterol total, separó a los pacientes en dos grupos, aquellos que tienen el dato y aquellos a quienes les falta, y comparó ambos grupos en cada una de las variables observadas, de manera que pueda ver si la ausencia se concentra en algún perfil clínico o si, por el contrario, se repartió de forma indiferente.
Para leer la tabla observo tres elementos en cada fila, esto es, la columna de los pacientes sin dato faltante (Not missing), la de los pacientes con el dato ausente (Missing), y el valor p que cuantifica si la diferencia entre ambos grupos es estadísticamente significativa, considerando que un valor p por encima de 0,05 me indica que los grupos no difieren de manera apreciable.
Recorriendo las variables una a una, encuentro lo siguiente:
En la edad, observo que los pacientes con colesterol presente promedian 65,5 años y aquellos a quienes les falta promedian 64,9 años, una diferencia de apenas medio año que, como cabría esperar, no resulta significativa (p = 0,421); por lo tanto, la edad no se relaciona con que falte el colesterol.
En el sexo, noto que la ausencia es prácticamente idéntica entre mujeres y hombres, pues a un 18,2% de las mujeres les falta el dato frente a un 17,8% de los hombres, de modo que el valor p es muy alto (p = 0,859) y confirma que el sexo no condiciona la falta.
En el índice de masa corporal y en los signos vitales, las medias de ambos grupos casi se superponen, ya que el índice de masa corporal es de 27,9 frente a 27,8, la presión sistólica de 130,2 frente a 131,7 y la diastólica de 79,7 frente a 80,0, todas con valores p elevados (0,754, 0,145 y 0,513 respectivamente), lo que me indica que ninguna de estas variables se asocia con la ausencia del colesterol.
En los triglicéridos, que son otra variable de laboratorio, las medias también se parecen mucho (155,9 frente a 152,7), con un valor p de 0,192 que descarta cualquier relación.
En las comorbilidades, observo el mismo patrón, pues la falta del colesterol es similar entre quienes tienen diabetes y quienes no (17,8% frente a 18,1%, p = 0,881), entre hipertensos y no hipertensos (16,8% frente a 19,8%, p = 0,061) y entre quienes tienen o no insuficiencia cardiaca (18,1% frente a 18,0%, p = 1,000), de manera que ninguna comorbilidad explica la ausencia.
En la mortalidad a 30 días, que es el desenlace principal, advierto la mayor diferencia numérica de toda la tabla, pues entre los pacientes que fallecieron la ausencia del colesterol alcanza un 22,3%, frente a un 17,6% entre quienes sobrevivieron; sin embargo, esa diferencia no llega a ser significativa (p = 0,094), aunque es la que más se acerca al umbral.
Reuniendo toda la tabla, considero que el resultado es claro, pues ninguna de las variables observadas se asocia de manera significativa con la ausencia del colesterol total, ya que todos los valores p superan el umbral de 0,05.
Esto significa que los pacientes a quienes les falta este dato no se distinguen clínicamente de aquellos que lo tienen, lo cual es justamente la huella que caracteriza a una falta completamente al azar, en la que la ausencia no depende de ninguna característica registrada del paciente (Bhaskaran y Smeeth, 2014).
Ahora bien, quiero detenerme en la mortalidad, porque su valor p de 0,094, aunque no significativo, es el más bajo de la tabla; por lo que al observar su magnitud, la diferencia entre un 22,3% y un 17,6% existe, pero debo recordar que, con un grupo de fallecidos reducido, una diferencia de proporciones puede aparecer sin alcanzar significación estadística; por lo tanto, no la leo como evidencia de asociación, sino como una fluctuación esperable, y con la prueba formal a continuación, me ayudará a comprenderlo mejor(Dong y Peng, 2013).
La función missing_compare tomó ahora la creatinina, separó a los pacientes en dos grupos, aquellos que tienen el dato y aquellos a quienes les falta, y comparó ambos grupos en cada una de las variables observadas, de manera que pueda ver si su ausencia se concentra en algún perfil clínico o si, por el contrario, se repartió de forma indiferente, encontrando lo siguiente:
En la edad, observo que los pacientes con creatinina presente promedian 65,7 años y aquellos a quienes les falta promedian 64,0 años, una diferencia de algo más de un año y medio que, a diferencia de lo que vi en el colesterol, sí alcanza significación estadística (p = 0,013); por lo tanto, debo revisarla.
En el sexo, noto que la ausencia es muy parecida entre mujeres y hombres, pues a un 18,5% de las mujeres les falta el dato frente a un 17,5% de los hombres, de modo que el valor p es alto (p = 0,552) y descarta que el sexo condicione la falta.
En el índice de masa corporal y en los signos vitales, las medias de ambos grupos casi se superponen, ya que el índice de masa corporal es de 27,9 frente a 27,8, la presión sistólica de 130,6 frente a 129,8 y la diastólica de 79,8 frente a 79,6, todas con valores p elevados (0,662, 0,459 y 0,696 respectivamente), lo que me indica que ninguna de estas variables se asocia con la ausencia de la creatinina.
En los triglicéridos, que son otra variable de laboratorio, las medias se parecen mucho (154,7 frente a 158,1), con un valor p de 0,170 que descarta cualquier relación.
En las comorbilidades, observo el mismo patrón, pues la falta de la creatinina es similar entre quienes tienen diabetes y quienes no (17,0% frente a 18,4%, p = 0,405), entre hipertensos y no hipertensos (17,7% frente a 18,4%, p = 0,703) y entre quienes tienen o no insuficiencia cardiaca (19,8% frente a 17,4%, p = 0,195), de manera que ninguna comorbilidad explica la ausencia.
En la mortalidad a 30 días, advierto que la ausencia es algo menor entre los fallecidos (16,5% frente a 18,1%), pero esa diferencia no llega a ser significativa (p = 0,607).
Reuniendo toda la tabla, considero que el resultado es casi tan limpio como el anterior, pues solo una variable se asocia con la ausencia de la creatinina, la edad, mientras todas las demás se comportan de forma indiferente.
Ahora bien, quiero detenerme en esa señal de la edad, porque al observar su magnitud, la diferencia entre quien tiene el dato y quien no es de poco más de un año de promedio, una distancia clínicamente intrascendente; por lo tanto, no la asumo como una verdadera relación, sino como una significación estadística sin relevancia práctica, algo que se puede esperar, cuando la muestra es grande y la prueba detecta diferencias diminutas que carecen de importancia clínica (Dong y Peng, 2013).
La función missing_compare tomó después el colesterol de lipoproteína de alta densidad, separó a los pacientes en dos grupos, aquellos que tienen el dato y aquellos a quienes les falta, y comparó ambos grupos en cada una de las variables observadas, de manera que pueda ver si su ausencia se concentra en algún perfil clínico o si, por el contrario, se repartió de forma indiferente, y encontré lo siguiente:
En la edad, observo que los pacientes con el dato presente promedian 65,6 años y aquellos a quienes les falta promedian 64,2 años, una diferencia que sí resulta significativa (p = 0,024), tal como ocurrió con la creatinina.
En el sexo, noto que la ausencia es muy parecida entre mujeres y hombres, pues a un 17,2% de las mujeres les falta el dato frente a un 18,5% de los hombres, de modo que el valor p es alto (p = 0,441) y me confirma que el sexo no condiciona la falta.
En el índice de masa corporal y en los signos vitales, las medias de ambos grupos casi se superponen, ya que el índice de masa corporal es de 27,9 frente a 27,8, la presión sistólica de 130,5 frente a 130,4 y la diastólica de 79,7 frente a 80,0, todas con valores p muy elevados (0,715, 0,979 y 0,640 respectivamente), lo que me indica que ninguna de estas variables se asocia con la ausencia.
En los triglicéridos, las medias se parecen mucho (155,2 frente a 156,1), con un valor p de 0,708 que descarta cualquier relación.
En las comorbilidades, observo el mismo patrón, pues la falta es casi idéntica entre quienes tienen diabetes y quienes no (18,0% frente a 17,9%, p = 0,975), entre hipertensos y no hipertensos (17,5% frente a 18,5%, p = 0,567) y entre quienes tienen o no insuficiencia cardiaca (18,4% frente a 17,8%, p = 0,779), de manera que ninguna comorbilidad explica la ausencia.
En la mortalidad a 30 días, considero que la ausencia es menor entre los fallecidos (13,4% frente a 18,4%), con un valor p de 0,078 que, aunque se acerca al umbral, no llega a ser significativo.
Reuniendo toda la tabla, considero que el resultado repite el de la creatinina, pues solo la edad se asocia con la ausencia, mientras el resto de las variables se muestra indiferente.
Ahora bien, esa señal de la edad vuelve a ser de apenas un grado de diferencia, una distancia sin peso clínico real; por lo tanto, mantengo la misma lectura, esto es, una significación estadística sin relevancia práctica, producto del tamaño de la muestra más que de una verdadera relación (Dong y Peng, 2013).
Por último, la función missing_compare tomó el tabaquismo, que es la única variable de anamnesis entre las cuatro con ausencia apreciable, y comparó de igual modo a quienes tienen el dato frente a quienes no lo tienen en cada variable observada.
En la edad, observo que los pacientes con el dato presente promedian 65,2 años y aquellos a quienes les falta promedian 66,1 años, una diferencia de menos de un año que no resulta significativa (p = 0,159); por lo tanto, la edad no se relaciona con que falte el tabaquismo.
En el sexo, noto que la ausencia es prácticamente idéntica entre mujeres y hombres (18,2% frente a 17,8%), de modo que el valor p es muy alto (p = 0,821) y confirma que el sexo no condiciona la falta.
En el índice de masa corporal y en los signos vitales, las medias de ambos grupos casi se superponen, ya que el índice de masa corporal es de 27,9 frente a 27,9, la presión sistólica de 130,4 frente a 130,8 y la diastólica de 79,9 frente a 79,1, todas con valores p elevados (0,961, 0,712 y 0,116 respectivamente), lo que me indica que ninguna de estas variables se asocia con la ausencia.
En los triglicéridos, las medias se parecen mucho (155,4 frente a 155,0), con un valor p de 0,890 que descarta cualquier relación.
En las comorbilidades, observo el mismo patrón, pues la falta es similar entre quienes tienen diabetes y quienes no (18,7% frente a 17,6%, p = 0,571), entre hipertensos y no hipertensos (17,5% frente a 18,7%, p = 0,458) y entre quienes tienen o no insuficiencia cardiaca (19,3% frente a 17,5%, p = 0,333), de manera que ninguna comorbilidad explica la ausencia.
En la mortalidad a 30 días, me parece que la ausencia es algo menor entre los fallecidos (14,7% frente a 18,3%), pero esa diferencia tampoco alcanza significación (p = 0,220).
Reuniendo toda la tabla, considero que este es el caso más claro de los cuatro, pues ninguna variable observada se asocia con la ausencia del tabaquismo, ya que todos los valores p superan ampliamente el umbral de 0,05.
Esto significa que los pacientes a quienes les falta este dato no se distinguen en nada de aquellos que lo tienen, lo cual es justamente la huella que caracteriza a una falta completamente al azar, en la que la ausencia no depende de ninguna característica registrada del paciente (Bhaskaran y Smeeth, 2014).
Después de examinar variable por variable si la ausencia se asociaba con las características observadas, quiero dar un paso más y poner a prueba toda la base de una sola vez, con una prueba estadística formal llamada prueba de Little, que propuso Roderick Little en 1988.
Antes de aplicarla, me detengo a entender de qué se trata y por qué la hago, pues mientras que la función missing_compare miró cada variable por separado, esta prueba me mira todas las variables al mismo tiempo, es decir, evalúa de manera global si el conjunto de la ausencia en mi base es compatible con un origen completamente al azar.
Hago esta prueba porque, después de revisar las variables una a una, quiero un resultado único que me hable de toda la base en conjunto, y no solo de cada parte por separado, y para entender lo que la prueba me dirá, necesito saber de qué parte, esto es, de su hipótesis nula, que es aquello que la prueba da por cierto mientras los datos no demuestren lo contrario, por lo cual, esa hipótesis nula dice que la falta es completamente al azar, de modo que el valor p lo interpreto así:
Si el valor p es alto (por encima de 0,05), significa que no tengo motivos para rechazar esa hipótesis, por lo que el resultado encaja con una falta completamente al azar.
Si el valor p es bajo (por debajo de 0,05), significa que debo rechazarla, lo cual me diría que la ausencia no es completamente al azar.
Hay algo que considero importante aclarar sobre hasta dónde llega esta prueba, y es que un valor p alto no demuestra que la falta sea completamente al azar, sino que me dice que mis datos no contradicen esa posibilidad; dicho de otro modo, según la literatura, la prueba me sirve para descartar ese mecanismo, pero no para probarlo con total certeza (Dong y Peng, 2013).
Aplico la prueba con la función mcar_test de la librería naniar, sobre las variables numéricas de mi base, que es como esta prueba funciona. Lo que espero obtener es un valor p único para toda la base, de manera que pueda comparar ese resultado general con lo que ya observé al revisar cada variable, y así tener una evidencia más firme antes de decidir cuál es el mecanismo.
datos_dep |>
dplyr::select(age, bmi, systolic_bp, diastolic_bp, chol_total, ldl, hdl,
triglycerides, troponin, creatinine, ejection_fraction, length_of_stay) |>
naniar::mcar_test()Análisis: La prueba de Little me devolvió cuatro valores así:
El estadístico de la prueba fue 242,83, que es la medida con la que la prueba resume cuánto se apartan los patrones de ausencia de lo que se esperaría bajo una falta completamente al azar; por sí solo no me dice mucho, pues cobra sentido al compararlo con los grados de libertad.
Los grados de libertad fueron 235, una cifra que refleja la cantidad de información que la prueba pone en juego al comparar todos los patrones de ausencia entre sí; observo que el estadístico (242,83) y los grados de libertad (235) son muy cercanos, lo cual es la primera señal de que la ausencia no se aparta demasiado de lo esperable al azar.
El valor p es 0,349, claramente por encima del umbral de 0,05, que es el dato decisivo de toda la prueba.
El número de patrones de ausencia es 24, que coincide con la variedad de combinaciones de falta que ya había observado en la matriz, lo que me confirma que la prueba trabajó sobre la misma estructura que venía analizando.
Reuniendo estos cuatro valores, considero que el resultado es contundente, pues como el valor p de 0,349 es mayor que 0,05, no tengo evidencia para rechazar la hipótesis nula, que afirmaba que la falta es completamente al azar; dicho de otro modo, los patrones de ausencia de mi base son perfectamente compatibles con un origen completamente aleatorio.
Esto significa que, mirando toda la base a la vez y no variable por variable, la ausencia no muestra una estructura sistemática que la prueba sea capaz de detectar, lo cual respalda con una prueba formal lo que ya venía observando en el mapa, en la matriz de patrones y en el examen de las asociaciones (Dong y Peng, 2013).
Algo importante,es que esta prueba tiende a volverse sensible con muestras grandes como la mía, de manera que con 2.500 pacientes podría haber rechazado la hipótesis ante desviaciones pequeñas; sin embargo, no lo hizo, sino que arrojó un valor p alto, lo cual considero una señal robusta a favor de la falta completamente al azar, justamente porque la prueba tuvo todas las condiciones para detectar una estructura y aun así no la encontró.
Así que, juntando esta prueba con todo lo que vi antes, ya tengo una idea clara y todas las señales apuntan en la misma dirección, de que el mapa me ha mostrado que la ausencia está repartida, la matriz muestra que a cada paciente le falta una sola variable y no un bloque, la comparación entre grupos no encontró diferencias que importen en lo clínico, y ahora la prueba de Little me confirma, mirando toda la base junta, que la falta encaja con un origen completamente al azar.
Con todo esto reunido, ya puedo decir cuál es el mecanismo, y eso es lo que haré antes de elegir cómo manejar los datos que faltan.
Después de todo el camino recorrido, ya tengo la evidencia suficiente para decir cuál es el mecanismo que genera la ausencia en mi base, y lo hago apoyándome en cuatro señales que apuntan todas hacia el mismo lado:
El mapa de la ausencia me mostró que las celdas vacías están repartidas por toda la base, sin que un grupo de pacientes concentre la falta.
La matriz de patrones confirmó que lo más común, con mucha diferencia, es que a un paciente le falte una sola variable y no varias a la vez.
La comparación entre grupos no encontró que los pacientes con datos faltantes se diferencien en lo clínico de los que tienen el dato completo, salvo una señal mínima con la edad que, por su tamaño, no tiene importancia práctica.
La prueba de Little confirmó, mirando toda la base de una vez, que la ausencia encaja con un origen completamente al azar, y lo hizo a pesar de que mi muestra grande le daba todas las condiciones para concluir lo contrario.
Por todo esto, concluyo que la falta en mi base se comporta como una falta completamente al azar (MCAR, Missing Completely At Random), es decir, que la probabilidad de que un dato falte no depende ni de las características que observé en el paciente ni del propio valor que se perdió.
Quiero ser honesta con el alcance de esta conclusión, pues como expliqué al hablar de los mecanismos, ninguna prueba puede demostrar con total certeza que la falta sea completamente al azar; lo que sí puedo afirmar es que todas las evidencias que reuní son compatibles con ese mecanismo y que ninguna lo contradice, lo cual me da una base sólida para tomar la siguiente decisión (Dong y Peng, 2013).
Haber llegado a este diagnóstico es importante, porque la falta completamente al azar es el único caso en el que sería válido incluso borrar las filas incompletas, y por supuesto también sirve imputar. Esto quiere decir que tengo varias opciones para manejar la ausencia, así que ahora voy a revisar cuáles son y a elegir la más adecuada, que es lo que haré enseguida.
Ya que diagnostiqué cómo se comporta la ausencia en mi base, el siguiente paso es decidir qué hago con ella. Pero antes de elegir un método, quiero conocer bien cuáles son mis opciones, porque cada una tiene sus ventajas y sus inconvenientes, y la mejor decisión depende tanto del mecanismo que diagnostiqué como de cuánta ausencia tengo.
En la literatura sobre datos faltantes se describen, en esencia, cuatro caminos para manejar la falta, que voy a explicar de menor a mayor complejidad:
Eliminar la variable que tiene los datos faltantes.
Eliminar los casos (las filas) a los que les falta algún dato.
Imputación simple, que consiste en rellenar cada dato faltante una sola vez con un valor fijo, como la media, la mediana o la moda.
Imputación múltiple, que rellena los datos faltantes varias veces para tener en cuenta la incertidumbre de no conocer el valor real.
Voy a recorrer cada uno de estos caminos, explicando en qué consiste, cuándo conviene usarlo y qué problemas tiene, para al final justificar cuál elijo para mi base y por qué. Esta decisión no la tomo al azar, sino apoyándome en lo que recomienda la literatura y en lo que ya he conocido sobre mis propios datos.
La primera opción, y la más drástica, es eliminar por completo la variable que tiene datos faltantes. Considero que este camino solo tendría sentido si una variable tuviera tantísima ausencia que fuera inservible, pero no es mi caso, pues incluso mis cuatro variables más afectadas conservan alrededor del 82% de sus datos, que es información demasiado valiosa como para desecharla; por eso descarto esta opción de entrada.
La segunda opción es eliminar las filas a las que les falta algún dato, lo que se conoce como análisis de casos completos o eliminación por lista, lo cual,consiste en quedarme solo con los pacientes que tienen todos sus datos y descartar al resto.
Su gran ventaja es la sencillez, pues no inventa ningún valor y deja los datos observados tal como están; además, como diagnostiqué una falta completamente al azar, en mi caso este método no introduciría sesgo, ya que los pacientes que se eliminarían no se diferencian de los que se conservan (Dong y Peng, 2013).Sin embargo, esta opción tiene un costo que considero demasiado alto, y para entenderlo lo voya a realizar a continuación.
n_total <- nrow(datos_dep)
n_completos <- sum(stats::complete.cases(datos_dep))
n_perdidos <- n_total - n_completos
tibble::tibble(
Concepto = c("Pacientes en la base", "Pacientes con todos los datos completos",
"Pacientes que se perder\u00edan al eliminar filas"),
Cantidad = c(n_total, n_completos, n_perdidos),
Porcentaje = c(100, round(n_completos / n_total * 100, 1), round(n_perdidos / n_total * 100, 1))
) |>
flextable::flextable() |>
flextable::set_header_labels(Concepto = "Concepto", Cantidad = "N\u00famero de pacientes", Porcentaje = "Porcentaje (%)") |>
flextable::colformat_double(j = "Porcentaje", digits = 1, decimal.mark = ",") |>
tema_flex() |>
flextable::align(j = "Concepto", align = "left", part = "all") |>
flextable::bg(i = 3, bg = "#FBE4E4", part = "body") |>
flextable::set_caption("Costo de la eliminaci\u00f3n por lista, con el n\u00famero de pacientes que se perder\u00edan")Concepto | Número de pacientes | Porcentaje (%) |
|---|---|---|
Pacientes en la base | 2,500 | 100,0 |
Pacientes con todos los datos completos | 1,103 | 44,1 |
Pacientes que se perderían al eliminar filas | 1,397 | 55,9 |
Análisis: Esta tabla muestra, con los propios números de este conjunto de datos con el que he venido trabajando, lo costoso que resultaría manejar la ausencia eliminando las filas incompletas. Para leerla, observo que la primera columna nombra el concepto que se cuenta, la segunda da el número de pacientes que le corresponde, y la tercera traduce ese número a un porcentaje sobre el total, de manera que la información se puede leer en cifras absolutas y en proporción a la vez.
Así, este conjunto de datos tiene 2.500 pacientes, que es el total con el que he venido trabajando, y de ellos solo 1.103 tienen todos sus datos completos, es decir, apenas un 44,1% de la muestra no presenta ningún faltante en ninguna de las 23 variables, lo cual significa que se perderían 1.397 pacientes, o sea un 55,9%, si se decidiera conservar únicamente los casos completos.
Además, se observa que esos 1.397 datos de pacientes, surgen de restar los completos al total (2.500 menos 1.103), y que el grupo que se descartaría es incluso mayor que el que se conservaría, de modo que la eliminación por lista se quedaría con la porción más pequeña de la base.
Considero que esta cifra es contundente, pues se estaría eliminando más de la mitad de los pacientes del estudio de síndrome coronario agudo para resolver una ausencia que se concentra en solo cuatro variables, esto es, el colesterol total, la creatinina, el colesterol de lipoproteína de alta densidad y el estado de tabaquismo, cada una con cerca del 18% de faltantes.
Por tanto, me parece una pérdida desproporcionada de información, sobre todo porque la mayoría de esos 1.397 pacientes conserva casi todos sus datos y solo carece de uno o dos, por lo cual, considero importante explicar por qué la pérdida es tan grande pese a que la ausencia parece moderada.
Respondiendo a esta inquietud que he planteado,considero que la razón es estadística, pues este conteo toma como incompleto a cualquier paciente al que le falte aunque sea un solo dato en cualquiera de las 23 variables, incluidos los faltantes mínimos como los de la edad o la presión sistólica.
De manera que las ausencias de unas y otras variables, al recaer sobre pacientes distintos, se van acumulando una sobre otra; por eso la pérdida de 1.397 pacientes es mucho mayor que la que vendría solo de las cuatro variables más afectadas, ya que exigir que todo esté completo suma todas las ausencias dispersas y termina recortando gran parte de la muestra.
A propósito de esto, la consecuencia de perder potencia importa de manera especial en una enfermedad como el síndrome coronario agudo, pues estadísticamente al conservar menos pacientes, se reduce la precisión y la potencia, tal como advierten Dong y Peng (2013).
Sin embargo, esto también importa por el lado clínico, ya que el desenlace principal del estudio es la mortalidad a 30 días, que recae sobre una porción minoritaria de la cohorte, y en este conjunto de datos los pacientes que fallecen son un grupo reducido frente al total.
Esto coincide con lo que describieron Timmis y colaboradores (2023) en su revisión sobre la epidemiología global del síndrome coronario agudo. En ese trabajo, la mortalidad por esta causa, aun siendo un desenlace de gran relevancia, afecta a una fracción de los pacientes y no a la mayoría.
De manera que, si ya se cuenta con un número limitado de fallecidos y además eliminara la mitad de la muestra, quedarían muy pocos casos para estudiar ese desenlace, por consiguiente, podrían pasar inadvertidas diferencias que en realidad existen, por lo que, sumado a lo anterior, debo revisar cuáles son las variables que más ausencia concentran, pues son marcadores que la evidencia vincula directamente al riesgo cardiovascular.
Las variables, como el colesterol total y el colesterol de lipoproteína de alta densidad (HDL) forman parte del perfil lipídico, y la creatinina refleja la función renal, por lo que autores como Kraler y colaboradores (2025), en su revisión sobre los mecanismos del síndrome coronario agudo, sitúan tanto el perfil lipídico como la función renal entre los ejes del pronóstico de esta enfermedad.
De suerte que perder pacientes precisamente en estas variables no sería una pérdida cualquiera, sino la de información clínicamente decisiva para entender el riesgo de los pacientes, por lo que, en suma, descarto la eliminación de filas como método principal, pues el costo de perder más de la mitad de la muestra es demasiado alto frente al tamaño real del problema.
Considero que tiene más sentido conservar a todos los pacientes y rellenar con cuidado los datos que faltan, que es justamente lo que hacen los métodos de imputación que revisaré a continuación.
El siguiente camino que voy a analizar, es la imputación simple, que consiste en rellenar cada dato faltante una sola vez con un valor fijo calculado a partir de los datos que sí tengo, siendo lo más habitual, usar la media o la mediana cuando la variable es numérica, y la moda, es decir, la categoría más frecuente, cuando la variable es categórica.
Este método es sencillo,pues con un solo valor se completan todos los vacíos y la base queda lista para analizar sin perder ningún paciente; sin embargo, esta facilidad esconde un problema serio que quiero verificar con este dataset de trabajo:
-El inconveniente principal, según explican Austin y colaboradores (2021) en su tutorial sobre imputación múltiple, es que rellenar con la media reduce de forma artificial la variabilidad de los datos y deforma su distribución.
La razón es intuitiva, pues si tomo todos los pacientes a quienes les falta un dato y les pongo a todos exactamente el mismo valor, estoy amontonando muchos casos en un solo punto, lo que crea un pico que no existe en la realidad y hace que los datos parezcan menos dispersos de lo que de verdad son.
Por lo cual,tomaré una de las variables con ausencia, la rellenaré con la media y compararé su distribución antes y después de imputar, de modo que pueda observarse la deformación que produce este método.
Para esta demostración elijo el colesterol total, que es una de las cuatro variables con mayor ausencia y, además, una variable de laboratorio cuyo comportamiento clínico lo manejamos en los laboratorios de forma rutinaria, para ello,con la función imputate_na de la librería dlookr rellenaré sus faltantes con la media, y enseguida graficaré el resultado para verlo.
La gráfica que voy a obtener compara dos curvas de densidad, esto es, la distribución original de la variable, calculada solo con los datos observados, y la distribución una vez que se imputó con la media.
Mi propósito al graficarlas juntas es poder examinar si la forma de la distribución cambia tras la imputación, y en qué medida, asi que, para ello observaré sobre todo qué ocurre en la zona del valor de la media, que es donde, según lo que advierte la literatura, podría concentrarse el efecto de rellenar muchos pacientes con un mismo valor.
Será la propia gráfica la que me muestre si ese efecto se produce y con qué intensidad:
imp_media <- dlookr::imputate_na(datos_dep, chol_total, method = "mean")
plot(imp_media) +
ggplot2::labs(
title = "Imputaci\u00f3n del colesterol total con la media",
subtitle = "Distribuci\u00f3n original frente a la distribuci\u00f3n tras imputar con la media"
) +
tema_gg(13)
Análisis: Esta gráfica compara la forma del colesterol
total antes y después de imputar sus faltantes con la media, y para
leerla describo primero qué representa cada elemento, pues el
eje horizontal recoge los valores de la variable, en miligramos por
decilitro, y el eje vertical mide la densidad, es decir, qué tan
concentrados están los pacientes en cada valor.
Hay dos curvas, una en verde que corresponde a la distribución original, calculada solo con los datos observados, y una en café que corresponde a la distribución una vez que se rellenó con la media.
Al observar las dos curvas, encuentro lo siguiente:
1.La curva verde, la original, tiene una forma suave y redondeada, con su parte más alta en torno a los 200 mg/dL y un descenso gradual hacia ambos lados; es la forma natural de la variable, en la que los pacientes se reparten de manera continua alrededor del centro.
2. La curva café, la imputada, sigue de cerca a la verde en casi todo su recorrido, salvo en un punto, pues justo en el valor de la media desarrolla un pico alto y estrecho. En la curva original (verde) la densidad en esa zona central llega a cerca de 0,010, mientras que en la curva imputada (café) se dispara hasta 0,020, es decir, el doble de altura.
Para comprenderlo, encuentro en el eje vertical que esta midiendo la densidad, esto es, qué proporción de los datos se concentra en cada valor del colesterol; de modo que, cuanto más alta está la curva en un punto, más pacientes tienen un valor cercano a ese.
Por eso, que la curva café alcance 0,020 frente al 0,010 de la verde significa que, tras imputar con la media, hay aproximadamente el doble de concentración de pacientes justo en el valor promedio, una acumulación que la distribución real no tenía.
Considero que ese pico es la clave de toda la gráfica,pues como rellené con la media a los 450 pacientes a quienes les faltaba el colesterol, a todos se les asignó exactamente el mismo número; de modo que esos 450 casos se amontonan en un solo valor y crean esa torre estrecha que no existe en los datos reales, es decir, lo que la gráfica muestra es una concentración artificial de pacientes en el promedio, inventada por el método y no presente en la realidad.
Lo que esta gráfica revela, entonces, es exactamente lo que advierten Austin y colaboradores (2021) en su tutorial sobre imputación, esto es, que rellenar con la media reduce de forma artificial la variabilidad de los datos. Aquí lo veo con mis propios ojos, pues la curva café es más alta y picuda en el centro y, en compensación, ligeramente más baja en los costados; dicho de otro modo, los datos imputados parecen menos dispersos y más agrupados de lo que en realidad están.
Por otro lado,más allá del pico en la gráfica, la imputación por la media aplana la riqueza de la distribución original, ya que todos los pacientes imputados pierden su individualidad y quedan reducidos a un único valor; así, si esos pacientes tenían en realidad colesteroles variados, altos y bajos, esa variación desaparece y se reemplaza por un promedio uniforme que no distingue a unos de otros.
Desde el punto de vista estadístico, esta deformación tiene una consecuencia seria, pues al estrechar artificialmente la distribución, la imputación por la media subestima la verdadera variabilidad de la variable, lo que se traduce en una desviación estándar más pequeña de la real y en intervalos de confianza demasiado estrechos; en consecuencia, el método transmite una falsa sensación de precisión, como si se conociera la variable con más certeza de la que en verdad se tiene (Austin et al., 2021).
Desde el punto de vista epidemiológico y clínico, el problema es igual de relevante, pues el colesterol total es un marcador del riesgo cardiovascular que la evidencia vincula al pronóstico del síndrome coronario agudo (Kraler et al., 2025). De manera que amontonar a 450 pacientes en el valor promedio borraría justamente la diversidad de perfiles lipídicos que interesa estudiar, ya que un paciente con colesterol muy alto y otro con colesterol bajo terminarían representados por la misma cifra, lo que ocultaría diferencias clínicas que podrían ser importantes para entender su riesgo.
En suma, esta demostración me confirma con datos propios que la imputación simple por la media, pese a su comodidad, distorsiona la forma real de la variable y no es un método adecuado para esta base, es por eso que necesito un método que rellene los datos faltantes respetando la variabilidad y la forma original de la distribución, que es justamente lo que ofrece la imputación múltiple, hacia la que me dirijo a continuación.
Llego al método que considero más adecuado para esta base, la imputación múltiple, pues a diferencia de la imputación simple, que rellena cada vacío una sola vez con un valor fijo, la imputación múltiple rellena los datos faltantes varias veces, generando varias versiones completas de la base, para luego combinarlas en un solo resultado.
Según explican Austin y colaboradores (2021) en su tutorial sobre imputación, busca resolver justamente el problema que observé con la media, esto es, la pérdida de variabilidad; ya que en lugar de fingir que conozco con certeza el valor que falta, la imputación múltiple reconoce que ese valor es incierto, y por eso lo estima varias veces con pequeñas variaciones, de modo que el resultado final conserva esa incertidumbre en lugar de borrarla.
El procedimiento se desarrolla en tres fases, tal como describen Austin y colaboradores (2021):
Para aplicarla usaré la librería mice, cuyo nombre corresponde a la imputación multivariada por ecuaciones encadenadas (Multivariate Imputation by Chained Equations). Su lógica consiste en imputar cada variable con faltantes a partir de las demás variables de la base, en ciclos que se repiten hasta estabilizarse, de manera que cada dato ausente se estima usando la información del resto del paciente y no un simple promedio general (Austin et al., 2021).
Antes de ejecutar la imputación debo tomar dos decisiones que debo justificar:
La primera es el método de imputación para las variables numéricas, y elijo el emparejamiento por media predicha (Predictive Mean Matching). Lo prefiero porque, en lugar de generar un valor a partir de una fórmula, que podría producir cifras imposibles como un colesterol negativo, este método busca pacientes reales con características parecidas y toma de ellos un valor observado; de este modo, los datos imputados siempre son valores plausibles y se respeta la forma original de la distribución, justo lo que la imputación por la media no logró (Austin et al., 2021).
La segunda decisión es cuántas veces repetir la imputación, es decir, cuántos conjuntos completos generar, por lo que, seguiré la regla práctica que recogen Austin y colaboradores (2021), según la cual conviene hacer al menos tantas imputaciones como el porcentaje de pacientes que tienen algún dato faltante.
Como en esta base ese porcentaje es del 55,9%, fijaré el número de imputaciones en 56, de modo que cumpla con esa recomendación y la imputación sea estable.
Con estas dos decisiones tomadas, ejecuto la imputación múltiple sobre la base:
set.seed(2025)
imp_multiple <- mice::mice(
datos_dep,
m = 56,
method = "pmm",
printFlag = FALSE
)
imp_multiple#> Class: mids
#> Number of multiple imputations: 56
#> Imputation methods:
#> patient_id age sex bmi
#> "" "pmm" "" "pmm"
#> systolic_bp diastolic_bp chol_total ldl
#> "pmm" "" "pmm" "pmm"
#> hdl triglycerides ejection_fraction troponin
#> "pmm" "" "pmm" "pmm"
#> creatinine diabetes hypertension heart_failure
#> "pmm" "" "" ""
#> smoking_status treat_statin treat_beta_blocker treat_acei
#> "pmm" "" "" ""
#> length_of_stay mortality_30d readmission_30d
#> "" "" ""
#> PredictorMatrix:
#> patient_id age sex bmi systolic_bp diastolic_bp chol_total ldl hdl
#> patient_id 0 1 1 1 1 1 1 1 1
#> age 1 0 1 1 1 1 1 1 1
#> sex 1 1 0 1 1 1 1 1 1
#> bmi 1 1 1 0 1 1 1 1 1
#> systolic_bp 1 1 1 1 0 1 1 1 1
#> diastolic_bp 1 1 1 1 1 0 1 1 1
#> triglycerides ejection_fraction troponin creatinine diabetes
#> patient_id 1 1 1 1 1
#> age 1 1 1 1 1
#> sex 1 1 1 1 1
#> bmi 1 1 1 1 1
#> systolic_bp 1 1 1 1 1
#> diastolic_bp 1 1 1 1 1
#> hypertension heart_failure smoking_status treat_statin
#> patient_id 1 1 1 1
#> age 1 1 1 1
#> sex 1 1 1 1
#> bmi 1 1 1 1
#> systolic_bp 1 1 1 1
#> diastolic_bp 1 1 1 1
#> treat_beta_blocker treat_acei length_of_stay mortality_30d
#> patient_id 1 1 1 1
#> age 1 1 1 1
#> sex 1 1 1 1
#> bmi 1 1 1 1
#> systolic_bp 1 1 1 1
#> diastolic_bp 1 1 1 1
#> readmission_30d
#> patient_id 1
#> age 1
#> sex 1
#> bmi 1
#> systolic_bp 1
#> diastolic_bp 1
Análisis: Esta salida es el resumen del objeto de imputación que generó la librería mice, y me confirma que el procedimiento se ejecutó tal como lo planteé, asi que voy a recorrer cada una de sus partes para entender qué hizo:
Enseguida aparece el bloque de los métodos de imputación (Imputation methods), donde cada variable de la base tiene asignado, debajo de su nombre, el método con el que se imputó, escrito entre comillas, y significa que:
Cuando aparece “pmm”, significa que esa variable se imputó con el emparejamiento por media predicha (Predictive Mean Matching).
este valor aparece en las variables que tenían datos faltantes, esto es: la edad (age), el índice de masa corporal (bmi), la presión arterial sistólica (systolic_bp), el colesterol total (chol_total), el colesterol de lipoproteína de baja densidad (ldl), el colesterol de lipoproteína de alta densidad (hdl), la troponina (troponin), la creatinina (creatinine), la fracción de eyección (ejection_fraction) y el estado de tabaquismo (smoking_status).
Cuando aparece el valor vacío (las comillas sin nada dentro, ““), significa que esa variable no se imputó, lo cual ocurre en todas las variables que ya estaban completas, como el sexo (sex), la presión arterial diastólica (diastolic_bp), los triglicéridos (triglycerides), las comorbilidades, los tratamientos y los dos desenlaces; esto tiene sentido, pues mice no necesita rellenar lo que no falta, de manera que deja esas variables intactas.
Considero importante detenerme en un acierto de este resultado, y es que el estado de tabaquismo (smoking_status), que es una variable categórica, también recibió el método de emparejamiento por media predicha y fue imputado sin problema; esto confirma que las cuatro variables con mayor ausencia, las tres de laboratorio y la de anamnesis, quedaron todas incluidas en la imputación.
Después aparece la matriz de predicción (PredictorMatrix), que es la que define qué variables se usaron para estimar cada una, por lo que su estructura es la siguiente:
Observo que casi toda la matriz está llena de unos, con una sola excepción sistemática, la diagonal, que vale 0; esto se debe a que una variable no se predice a sí misma, de modo que, por ejemplo, en la fila de la edad (age) la columna de la edad vale 0, pero todas las demás columnas valen 1.
Esto significa que cada variable con faltantes se imputó aprovechando la información de todas las demás variables de la base, que es precisamente la esencia de la imputación por ecuaciones encadenadas, en la que cada dato ausente se estima a partir del resto del perfil del paciente y no de un simple promedio general (Austin et al., 2021).
Reuniendo todo, considero que esta salida me confirma que la imputación múltiple se realizó correctamente y como esperaba, pues se generaron las 56 versiones de la base, se imputaron únicamente las variables con ausencia mediante un método que respeta los valores plausibles, y cada una se estimó usando el resto de la información del paciente.
Con la base ya imputada, el paso siguiente es comprobar el efecto de esta imputación, comparando las estadísticas antes y después, que es lo que haré a continuación:
Una vez realizada la imputación múltiple, el último paso es comprobar su efecto, comparando las estadísticas de las variables antes y después de rellenar los datos faltantes.
Esta comparación es importante por dos razones, pues por un lado me permite verificar que la imputación se comportó de manera razonable, y por otro me deja ver cuánto cambian los resúmenes de las variables al pasar de los casos observados a la base completa.
Para hacer esta comparación necesito, primero, consolidar las 56 versiones imputadas en una sola base completa, para ello,la librería mice ofrece una función que reúne los conjuntos imputados y entrega una base lista para analizar, sobre la cual podré calcular las estadísticas finales y contrastarlas con las originales.
Voy a centrar la comparación en las cuatro variables que concentraban la mayor ausencia, esto es, el colesterol total, la creatinina, el colesterol de lipoproteína de alta densidad y el estado de tabaquismo, porque son las que de verdad recibieron una cantidad apreciable de valores imputados, y por tanto las que mejor muestran el efecto del método.
Para las variables numéricas compararé la mediana y el rango intercuartílico, que son las medidas robustas que vengo usando en todo el trabajo, calculadas antes (solo con los datos observados) y después de imputar (con la base completa); con este proceso espero observar si esos resúmenes se mantienen estables o si cambian de manera importante tras la imputación.
Debo anticipar una expectativa, pues como diagnostiqué una falta completamente al azar, y dado que en el taller previo comprobé que las variables de esta base tienen muy poca relación entre sí, es razonable esperar que las medianas y los rangos apenas se modifiquen; esto se debe a que, sin variables fuertemente relacionadas de las cuales tomar información, la imputación tiende a reproducir la distribución de los datos observados.
De ser así, esa estabilidad no sería un defecto, sino la señal de que la imputación respetó la estructura de los datos en lugar de inventar valores extraños, por lo que será la tabla la que me confirme si esto ocurre:
datos_imputados <- mice::complete(imp_multiple)
vars_num_comp <- c("chol_total", "creatinine", "hdl")
resumen_antes <- datos_dep |>
dplyr::select(dplyr::all_of(vars_num_comp)) |>
tidyr::pivot_longer(dplyr::everything(), names_to = "variable", values_to = "valor") |>
dplyr::filter(!is.na(.data$valor)) |>
dplyr::group_by(.data$variable) |>
dplyr::summarise(
momento = "Antes (observados)",
n = dplyr::n(),
mediana = stats::median(.data$valor),
q1 = stats::quantile(.data$valor, 0.25),
q3 = stats::quantile(.data$valor, 0.75),
.groups = "drop"
)
resumen_despues <- datos_imputados |>
dplyr::select(dplyr::all_of(vars_num_comp)) |>
tidyr::pivot_longer(dplyr::everything(), names_to = "variable", values_to = "valor") |>
dplyr::group_by(.data$variable) |>
dplyr::summarise(
momento = "Despu\u00e9s (imputados)",
n = dplyr::n(),
mediana = stats::median(.data$valor),
q1 = stats::quantile(.data$valor, 0.25),
q3 = stats::quantile(.data$valor, 0.75),
.groups = "drop"
)
etiquetas_comp <- c(
chol_total = "Colesterol total (mg/dL)",
creatinine = "Creatinina s\u00e9rica (mg/dL)",
hdl = "Colesterol HDL (mg/dL)"
)
dplyr::bind_rows(resumen_antes, resumen_despues) |>
dplyr::mutate(
etiqueta = etiquetas_comp[.data$variable],
med_iqr = paste0(formatC(.data$mediana, format = "f", digits = 1, decimal.mark = ","),
" [", formatC(.data$q1, format = "f", digits = 1, decimal.mark = ","),
" \u2013 ", formatC(.data$q3, format = "f", digits = 1, decimal.mark = ","), "]")
) |>
dplyr::select(etiqueta, momento, n, med_iqr) |>
dplyr::arrange(.data$etiqueta, .data$momento) |>
flextable::flextable() |>
flextable::set_header_labels(
etiqueta = "Variable",
momento = "Momento",
n = "n",
med_iqr = "Mediana [Q1 \u2013 Q3]"
) |>
tema_flex() |>
flextable::align(j = c("etiqueta", "momento"), align = "left", part = "all") |>
flextable::bg(i = ~ momento == "Despu\u00e9s (imputados)", bg = "#E3EEF7", part = "body") |>
flextable::set_caption("Comparaci\u00f3n de la mediana y el rango intercuart\u00edlico antes y despu\u00e9s de la imputaci\u00f3n m\u00faltiple")Variable | Momento | n | Mediana [Q1 – Q3] |
|---|---|---|---|
Colesterol HDL (mg/dL) | Antes (observados) | 2,052 | 50,0 [40,0 – 61,0] |
Colesterol HDL (mg/dL) | Después (imputados) | 2,500 | 50,0 [40,0 – 61,0] |
Colesterol total (mg/dL) | Antes (observados) | 2,050 | 201,0 [173,0 – 228,0] |
Colesterol total (mg/dL) | Después (imputados) | 2,500 | 200,0 [172,0 – 227,0] |
Creatinina sérica (mg/dL) | Antes (observados) | 2,050 | 1,0 [0,8 – 1,2] |
Creatinina sérica (mg/dL) | Después (imputados) | 2,500 | 1,0 [0,8 – 1,2] |
Análisis: Esta tabla compara el resumen de las tres variables numéricas con mayor ausencia antes y después de la imputación múltiple, y para leerla explico primero qué representa cada columna:
Lo primero que observo, y que recorre toda la tabla, es el cambio en la columna del número de pacientes, pues en todas las variables ese número pasa de alrededor de 2.050 antes de imputar a 2.500 después.
Esto significa que la imputación cumplió su objetivo principal, esto es, recuperar a los pacientes que antes quedaban fuera por tener el dato ausente, de manera que ahora las tres variables cuentan con la muestra completa de 2.500 pacientes en lugar de los poco más de 2.000 que tenían dato observado.
Recorriendo ahora variable por variable los resúmenes, encuentro lo siguiente:
1.En el colesterol de lipoproteína de alta densidad, la mediana se mantiene idéntica en 50,0 miligramos por decilitro antes y después, y su rango intercuartílico tampoco cambia, pues permanece en 40,0 a 61,0 en ambos momentos; de modo que el resumen es exactamente el mismo pese a haber sumado 448 pacientes.
En el colesterol total, observo un cambio mínimo, pues la mediana pasa de 201,0 a 200,0 miligramos por decilitro, apenas un punto de diferencia, y el rango intercuartílico se desplaza muy ligeramente, de 173,0 a 228,0 hacia 172,0 a 227,0; una variación tan pequeña que resulta clínicamente despreciable.
En la creatinina sérica, el resumen se mantiene completamente estable, pues la mediana sigue en 1,0 miligramo por decilitro y el rango intercuartílico en 0,8 a 1,2 antes y después de imputar.
Desde el punto de vista estadístico, la enorme estabilidad de las medianas y los rangos, pese a haber añadido cerca de 450 pacientes en cada variable, no es un resultado casual, sino la consecuencia esperable de dos cosas que ya conocía.
Por un lado, diagnostiqué una falta completamente al azar, lo que implica que los pacientes con dato ausente no se diferenciaban de los que tenían el dato.
Por otro lado, en el taller de la semana 5, comprobé que las variables de esta base tienen muy poca relación entre sí, de manera que la imputación, al no disponer de variables fuertemente asociadas de las cuales tomar información, reprodujo la distribución de los datos observados, y por eso los resúmenes apenas se movieron (Austin et al., 2021).
Quiero subrayar que esta estabilidad no es un defecto ni una señal de que la imputación “no hizo nada”, sino todo lo contrario, pues es la prueba de que el método se comportó de forma correcta y prudente.
La imputación múltiple respetó la forma real de las variables y no introdujo valores extraños ni desplazó artificialmente el centro de la distribución, que es precisamente lo que se esperaría de un método que conserva la variabilidad, a diferencia de la imputación por la media que examiné antes, la cual sí deformaba la distribución (Austin et al., 2021).
Desde el punto de vista clínico, este comportamiento es valioso, pues el colesterol total, el colesterol de lipoproteína de alta densidad y la creatinina son marcadores del riesgo cardiovascular y del pronóstico en el síndrome coronario agudo (Kraler et al., 2025); de modo que conservar sus medianas y rangos significa que el perfil lipídico y la función renal de la cohorte se mantienen fieles a lo observado, ahora con la ventaja de contar con la muestra completa, en otras palabras, gané pacientes sin distorsionar la realidad clínica de las variables.
En suma, esta comparación me confirma que la imputación múltiple logró su propósito, esto es, completar la base recuperando a todos los pacientes y, al mismo tiempo, preservar las características de las variable; de manera que ahora dispongo de una base completa y fiable sobre la cual podrían sustentarse análisis posteriores con mayor potencia y sin el sesgo que habría supuesto descartar a los pacientes incompletos.
Para completar la comparación incluyo ahora el estado de tabaquismo, que es la única variable categórica entre las cuatro con mayor ausencia. Como se trata de una variable de categorías y no de números, no puedo resumirla con la mediana, sino que la comparo a través de la frecuencia de cada una de sus categorías antes y después de imputar.
Con este proceso espero observar si la proporción de pacientes en cada categoría, esto es, quienes nunca fumaron, los exfumadores y los fumadores actuales, se mantiene estable tras la imputación o si cambia de manera apreciable.
Al igual que con las variables numéricas, dado el mecanismo de falta completamente al azar que diagnostiqué, es razonable esperar que la distribución de las categorías se conserve.
tabaco_antes <- datos_dep |>
dplyr::filter(!is.na(.data$smoking_status)) |>
dplyr::count(.data$smoking_status, name = "frecuencia") |>
dplyr::mutate(
momento = "Antes (observados)",
porcentaje = .data$frecuencia / sum(.data$frecuencia) * 100
) |>
dplyr::rename(categoria = "smoking_status")
tabaco_despues <- datos_imputados |>
dplyr::count(.data$smoking_status, name = "frecuencia") |>
dplyr::mutate(
momento = "Despu\u00e9s (imputados)",
porcentaje = .data$frecuencia / sum(.data$frecuencia) * 100
) |>
dplyr::rename(categoria = "smoking_status")
dplyr::bind_rows(tabaco_antes, tabaco_despues) |>
dplyr::select(categoria, momento, frecuencia, porcentaje) |>
dplyr::arrange(.data$categoria, .data$momento) |>
flextable::flextable() |>
flextable::set_header_labels(
categoria = "Categor\u00eda de tabaquismo",
momento = "Momento",
frecuencia = "Frecuencia (n)",
porcentaje = "Porcentaje (%)"
) |>
flextable::colformat_double(j = "porcentaje", digits = 2, decimal.mark = ",") |>
tema_flex() |>
flextable::align(j = c("categoria", "momento"), align = "left", part = "all") |>
flextable::bg(i = ~ momento == "Despu\u00e9s (imputados)", bg = "#E3EEF7", part = "body") |>
flextable::set_caption("Comparaci\u00f3n de la distribuci\u00f3n del estado de tabaquismo antes y despu\u00e9s de la imputaci\u00f3n m\u00faltiple")Categoría de tabaquismo | Momento | Frecuencia (n) | Porcentaje (%) |
|---|---|---|---|
Nunca | Antes (observados) | 936 | 45,64 |
Nunca | Después (imputados) | 1,116 | 44,64 |
Exfumador | Antes (observados) | 712 | 34,71 |
Exfumador | Después (imputados) | 898 | 35,92 |
Fumador actual | Antes (observados) | 403 | 19,65 |
Fumador actual | Después (imputados) | 486 | 19,44 |
Análisis: Esta tabla compara la distribución del estado de tabaquismo antes y después de la imputación múltiple, y para leerla explico primero qué representa cada columna.
Recorriendo la tabla categoría por categoría, encuentro lo siguiente:
Lo primero que observo, mirando la columna de frecuencia, es que las tres categorías ganaron pacientes, lo cual es coherente con que la imputación repartió los 449 valores que faltaban entre los tres niveles, completando así la muestra hasta los 2.500 pacientes, además la suma de los pacientes añadidos en cada categoría (180, 186 y 83) corresponde justamente a esos 449 datos que antes estaban ausentes.
Considero que el hallazgo central está en la columna del porcentaje, ya que desde, el punto de vista estadístico, observo que la distribución relativa de las tres categorías se mantiene muy estable, pues los porcentajes apenas se mueven en torno a un punto, conservando el mismo orden y las mismas proporciones que tenían los datos observados, esto es, “nunca fumó” como categoría mayoritaria, seguida de “exfumador” y, en último lugar, “fumador actual”.
Esta estabilidad es la consecuencia esperable del mecanismo de falta completamente al azar que diagnostiqué, ya que, al no diferenciarse los pacientes con dato ausente de los que tenían el dato, la imputación reprodujo la misma estructura de categorías que ya existía (Austin et al., 2021).
Quiero subrayar que esta estabilidad confirma el buen comportamiento del método, pues la imputación múltiple no inventó una distribución distinta ni infló artificialmente ninguna categoría, sino que respetó las proporciones reales del tabaquismo en la cohorte, completando la muestra sin distorsionarla.
Desde el punto de vista clínico, conservar esta distribución es valioso, pues el tabaquismo es un factor de riesgo cardiovascular reconocido en el síndrome coronario agudo (Kraler et al., 2025); de manera que mantener el peso relativo de fumadores, exfumadores y no fumadores significa que el perfil de exposición al tabaco de la cohorte se conserva fiel a lo observado, ahora con la ventaja de contar con el antecedente completo en los 2.500 pacientes.
En consecuencia, esta comparación me ha confirmado, que también para la variable categórica,la imputación múltiple cumplió su doble propósito, esto es, recuperar a los pacientes que carecían del dato y, al mismo tiempo, preservar la distribución original de las categorías; de modo que el tabaquismo queda completo y fiel a la realidad de la muestra.
Al cerrar este trabajo, considero que logré el objetivo que me propuse, esto es, diagnosticar por qué faltaban los datos en esta cohorte de síndrome coronario agudo y resolver esa ausencia de la manera más adecuada.
Recogiendo todo el recorrido, llego a las siguientes conclusiones:
En primer lugar, la exploración del patrón me mostró que la ausencia se concentraba en cuatro variables, esto es, el colesterol total, la creatinina, el colesterol de lipoproteína de alta densidad y el estado de tabaquismo, cada una con cerca del 18% de faltantes, mientras el resto de las variables apenas tenían vacíos. De manera que supe desde el principio dónde estaba el problema y que no podía ignorarlo.
En segundo lugar, el diagnóstico del mecanismo fue el eje de todo el trabajo, y reuní cuatro evidencias que apuntaron en la misma dirección. El mapa mostró una ausencia dispersa, la matriz reveló que a cada paciente le faltaba una sola variable y no un bloque, el examen de las asociaciones no encontró que la falta dependiera de las características clínicas de los pacientes, y la prueba de Little confirmó, mirando toda la base a la vez, que la ausencia era compatible con un origen completamente al azar, asi que por consiguiente, concluí que la falta en esta base se comporta como una falta completamente al azar.
En tercer lugar, ese diagnóstico me permitió elegir el método de manejo con criterio. pues descarté eliminar las filas incompletas, porque habría perdido más de la mitad de la muestra, y descarté la imputación simple por la media, porque comprobé con una gráfica que deformaba la distribución de los datos; asi que opté por la imputación múltiple, que rellena los datos faltantes respetando su variabilidad.
En cuarto lugar, la comparación de las estadísticas antes y después confirmó que la imputación se comportó correctamente, pues recuperó a los pacientes que antes quedaban fuera, completando la muestra hasta los 2.500, y al mismo tiempo conservó las medianas, los rangos y las proporciones de las variables.
De modo que terminé con una base completa y fiel a la realidad clínica de la cohorte; en suma, considero que este trabajo me permitió comprender que el manejo de los datos faltantes no es un trámite técnico, sino una decisión que depende del mecanismo que los origina, y que diagnosticar ese mecanismo, antes de imputar, es lo que da validez a todo lo que se realice posteriormente.
Aunque considero que el trabajo cumplió su objetivo, debo reconocer con honestidad varias limitaciones que conviene tener presentes al interpretar sus resultados:
Esto tiene una consecuencia directa sobre la imputación, ya que la imputación múltiple rinde mejor cuando existen variables relacionadas de las cuales tomar información para estimar los valores ausentes; de manera que, al no contar con esas relaciones, la imputación se limitó a reproducir la distribución de los datos observados.
Por consiguiente, en una base real, con correlaciones clínicas verdaderas entre los marcadores, el método habría podido aprovechar mucho mejor su potencial.
La prueba de Little y el examen de asociaciones permiten descartar una asociación con lo observado, pero no pueden descartar por completo que la ausencia dependa de los propios valores no registrados, esto es, un mecanismo de falta no al azar, por lo que mi conclusión debe entenderse como la más compatible con la evidencia y no como una certeza absoluta.
La tercera limitación es metodológica, pues para las comparaciones descriptivas antes y después trabajé sobre una de las versiones imputadas, lo cual es adecuado para describir el efecto de la imputación; sin embargo, si en un análisis posterior se quisieran estimar asociaciones o ajustar modelos, lo correcto sería combinar las 56 imputaciones siguiendo las reglas establecidas para ello, de modo que la incertidumbre de la imputación quede reflejada en los resultados finales (Austin et al., 2021).
La cuarta limitación se relaciona con la validez externa pues los resultados de este ejercicio describen el comportamiento de la ausencia en esta cohorte particular, y no necesariamente se trasladan a otras poblaciones de pacientes con síndrome coronario agudo.
De manera que las decisiones que tomé sobre el manejo de los faltantes son válidas para esta base, pero en otro conjunto de datos el mecanismo de la ausencia podría ser distinto y exigir un abordaje diferente.
Pese a estas limitaciones, considero que con el ejercicio pude recorrer de principio a fin el proceso de diagnosticar y manejar los datos faltantes de manera fundamentada.
Austin, P. C., White, I. R., Lee, D. S., & van Buuren, S. (2021). Missing data in clinical research: A tutorial on multiple imputation. Canadian Journal of Cardiology, 37(9), 1322–1331. https://doi.org/10.1016/j.cjca.2020.11.010
Bhaskaran, K., & Smeeth, L. (2014). What is the difference between missing completely at random and missing at random? International Journal of Epidemiology, 43(4), 1336–1339. https://doi.org/10.1093/ije/dyu080
Bruce, P., Bruce, A., & Gedeck, P. (2022). Estadística práctica para ciencia de datos con R y Python (2.ª ed.). Marcombo.
Dong, Y., & Peng, C().-Y. J. (2013). Principled missing data methods for researchers. SpringerPlus, 2, Artículo 222. https://doi.org/10.1186/2193-1801-2-222
Kraler, S., Wenzl, F. A., Georgiopoulos, G., Obeid, S., Liberale, L., von Eckardstein, A., Muller, O., Mach, F., Räber, L., Losdat, S., Schmiady, M. O., Stellos, K., Stamatelopoulos, K., Camici, G. G., Srdic, A., Paneni, F., Akhmedov, A., & Lüscher, T. F. (2025). [Referencia sobre mecanismos y pronóstico del síndrome coronario agudo].
Timmis, A., Vardas, P., Townsend, N., Torbica, A., Katus, H., De Smedt, D., Gale, C. P., Maggioni, A. P., Petersen, S. E., Huculeci, R., Kazakiewicz, D., Rubio, V., Ignatiuk, B., Raisi-Estabragh, Z., Pawlak, A., Karagiannidis, E., Treskes, R., Gaita, D., Beltrame, J. F., … Bardinet, I. (2023). **European Society of Cardiology: Cardiovascular disease statistics 2023. *European Heart Journal.**