knitr::opts_chunk$set(
  echo    = TRUE,
  message = FALSE,
  warning = FALSE,
  fig.align = "center",
  fig.width = 9,
  fig.height = 5.5
)
# --- Carga de paquetes ---
library(readxl)      # Leer archivos Excel (.xlsx)
library(dplyr)       # Manipulación de datos (filter, mutate, summarise)
library(tidyr)       # Reestructuración de datos
library(ggplot2)     # Gráficas de alta calidad
library(kableExtra)  # Tablas elegantes en HTML
library(epitools)    # Cálculos epidemiológicos (OR, RR, IC 95%)
library(scales)      # Formato de ejes (porcentajes)

# --- Paleta de colores para todo el documento ---
col_cnaf   <- "#2E86C1"   # Azul — Cánula nasal de alto flujo
col_tco    <- "#E74C3C"   # Rojo — Terapia convencional de oxígeno
col_accent <- "#1B4F72"   # Azul oscuro — títulos
col_fondo  <- "#EBF5FB"   # Azul claro — fondos de tablas

1 PARTE I: ANÁLISIS INTERINO

*El análisis interino es una evaluación programada que se realiza durante la ejecución de un ensayo clínico**, antes de completar el reclutamiento. Su propósito es doble:

(1) evaluar la seguridad de los participantes y (2) determinar si ya existe evidencia suficiente de eficacia o futilidad para justificar la detención temprana.

En el ensayo HiFLo-Covid, el Comité Independiente de Monitoreo de Datos y Seguridad (DSMB, por sus siglas en inglés: Data and Safety Monitoring Board) realizó este análisis con los primeros 100 pacientes, utilizando los límites de detención de Haybittle-Peto.*

1.1 Cargo y exploro datos interinos

Comienzo por importar la hoja “Interino” del archivo Excel. Me parece esencial explorar la estructura completa de los datos antes de cualquier cálculo, para poder verificar dimensiones, identificar el tipo de cada variable, detectar valores faltantes y comprender qué representa cada columna en el contexto clínico del estudio.

1.2 Cargo base interina

# --- Lectura de la hoja "Interino" ---
interino_raw <- read_excel("BD_HIFLO.xlsx", sheet = "Interino")

# --- Verifico dimensiones ---
cat("Dimensiones:", nrow(interino_raw), "filas ×", ncol(interino_raw), "columnas\n")
## Dimensiones: 100 filas × 16 columnas

verifico nombres originales y los estandarizo

# --- verifico cómo vienen los nombres del Excel ---
cat("Nombres originales:\n")
## Nombres originales:
names(interino_raw)
##  [1] "record_id"              "Terapia"                "edad"                  
##  [4] "sexo"                   "peso"                   "talla"                 
##  [7] "imc"                    "dias_sintomas"          "ingreso_spo2"          
## [10] "sop_res_pre_pao2fio2"   "Interleuquina 6"        "Ventilación mecánica"  
## [13] "Ingreso a UCI"          "Muerte"                 "Duración de la terapia"
## [16] "Tiempo a la intubación"

Los nombres originales traen tildes, espacios y mayúsculas que me dificultan trabajar en R. Por lo cual los estandarizo a nombres cortos y sin caracteres especiales.

# --- Estandarización de nombres ---
names(interino_raw) <- c(
  "record_id",          # Identificador del paciente

  "terapia",            # 1 = CNAF; 0 = TCO
  "edad",               # Años
  "sexo",               # 0 = Femenino; 1 = Masculino
  "peso",               # Kilogramos
  "talla",              # Centímetros
  "imc",                # Índice de masa corporal (kg/m²)
  "dias_sintomas",      # Días de síntomas previos
  "ingreso_spo2",       # Saturación O₂ al ingreso (%)
  "pao2fio2",           # Relación PaO₂/FiO₂
  "il6",                # Interleucina 6 (pg/mL)
  "vent_mecanica",      # 0 = No; 1 = Sí
  "ingreso_uci",        # 0 = No; 1 = Sí
  "muerte",             # 0 = No; 1 = Sí
  "duracion_terapia",   # Días
  "tiempo_intubacion"   # Días hasta intubación
)

cat("Nombres estandarizados:\n")
## Nombres estandarizados:
names(interino_raw)
##  [1] "record_id"         "terapia"           "edad"             
##  [4] "sexo"              "peso"              "talla"            
##  [7] "imc"               "dias_sintomas"     "ingreso_spo2"     
## [10] "pao2fio2"          "il6"               "vent_mecanica"    
## [13] "ingreso_uci"       "muerte"            "duracion_terapia" 
## [16] "tiempo_intubacion"

1.3 Estructura interna

# --- me pregunto ¿Qué tipo de dato tiene cada variable en R? ---
glimpse(interino_raw)
## Rows: 100
## Columns: 16
## $ record_id         <chr> "74-1", "74-2", "74-3", "74-4", "74-5", "74-6", "74-…
## $ terapia           <dbl> 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0…
## $ edad              <dbl> 60, 74, 55, 36, 42, 65, 51, 36, 63, 54, 43, 57, 27, …
## $ sexo              <dbl> 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0…
## $ peso              <dbl> 71.0, 85.0, 96.0, 75.0, 99.0, 76.0, 84.4, 108.3, 68.…
## $ talla             <dbl> 175, 176, 168, 157, 168, 173, 166, 174, 165, 165, 17…
## $ imc               <dbl> 23.2, 27.4, 34.0, 30.4, 35.1, 25.4, 30.6, 35.8, 25.0…
## $ dias_sintomas     <dbl> 14, 3, 9, 3, 9, 5, 8, 11, 10, 2, 10, 5, 8, 7, 10, 9,…
## $ ingreso_spo2      <dbl> 85, 95, 92, 85, 91, 85, 92, 90, 76, 77, 95, 91, 85, …
## $ pao2fio2          <dbl> 137.6, 95.4, 131.8, 128.2, 101.2, 132.9, 103.5, 68.2…
## $ il6               <dbl> 7.2600000, 23.2900000, NA, 59.3300000, 77.4200000, 2…
## $ vent_mecanica     <dbl> 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1…
## $ ingreso_uci       <dbl> 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1…
## $ muerte            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ duracion_terapia  <dbl> 8, 12, 11, 8, 1, 9, 1, 10, 13, 11, 1, 7, 1, 2, 1, 12…
## $ tiempo_intubacion <dbl> 0, 0, 0, 0, 13, 32, 5, 0, 0, 0, 6, 0, 19, 13, 5, 0, …

Con la función glimpse() observo tipo de dato que R asignó a cada variable. Todas las numéricas aparecieron como dbl (número decimal). Pero variables como terapia, sexo, vent_mecanica, muerte e ingreso_uci son realmente categóricas aunque R las está viendo como números, por tanto, si no las convierto a factor, R las seguirá tratando como continuas y los análisis serán conceptualmente incorrectos.

1.4 Clasificación de variables y conversión a factores

# ═══════════════════════════════════════════════════════════════
# CLASIFICACIÓN DE VARIABLES Y CONVERSIÓN A FACTORES
# ═══════════════════════════════════════════════════════════════

# --- Tabla de clasificación ---
clasificacion <- data.frame(
  Variable = names(interino_raw),
  Tipo = c(
    "Identificador",
    "Categórica dicotómica", "Cuantitativa continua",
    "Categórica dicotómica", "Cuantitativa continua",
    "Cuantitativa continua", "Cuantitativa continua",
    "Cuantitativa discreta", "Cuantitativa continua",
    "Cuantitativa continua", "Cuantitativa continua",
    "Categórica dicotómica", "Categórica dicotómica",
    "Categórica dicotómica", "Cuantitativa continua",
    "Cuantitativa continua"
  ),
  Rol = c(
    "—",
    "Exposición (intervención)", "Covariable / confusor",
    "Covariable / confusor", "Covariable descriptiva",
    "Covariable descriptiva", "Covariable / confusor",
    "Covariable clínica", "Covariable basal",
    "Covariable de severidad", "Biomarcador / modificador de efecto",
    "DESENLACE PRIMARIO", "Desenlace secundario",
    "Desenlace secundario", "Variable de proceso",
    "Variable de tiempo al evento"
  )
)

kable(clasificacion,
      col.names = c("Variable", "Tipo de variable", "Rol en el estudio"),
      align = "lll",
      caption = "Clasificación de variables — Base interina") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = TRUE, font_size = 12) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  row_spec(2, bold = TRUE, background = "#D5F5E3") %>%
  row_spec(12, bold = TRUE, background = "#FADBD8") %>%
  row_spec(c(13, 14), background = "#FDEBD0")
Clasificación de variables — Base interina
Variable Tipo de variable Rol en el estudio
record_id Identificador
terapia Categórica dicotómica Exposición (intervención)
edad Cuantitativa continua Covariable / confusor
sexo Categórica dicotómica Covariable / confusor
peso Cuantitativa continua Covariable descriptiva
talla Cuantitativa continua Covariable descriptiva
imc Cuantitativa continua Covariable / confusor
dias_sintomas Cuantitativa discreta Covariable clínica
ingreso_spo2 Cuantitativa continua Covariable basal
pao2fio2 Cuantitativa continua Covariable de severidad
il6 Cuantitativa continua Biomarcador / modificador de efecto
vent_mecanica Categórica dicotómica DESENLACE PRIMARIO
ingreso_uci Categórica dicotómica Desenlace secundario
muerte Categórica dicotómica Desenlace secundario
duracion_terapia Cuantitativa continua Variable de proceso
tiempo_intubacion Cuantitativa continua Variable de tiempo al evento

Resalté en verde la variable de exposición (terapia), en rojo claro el desenlace primario (ventilación mecánica) y en naranja los desenlaces secundarios.

1.5 Convierto variables categóricas a factor

# --- Convierto categóricas a factor  ---
interino <- interino_raw %>%
  mutate(
    terapia_f = factor(terapia, levels = c(0, 1),
                       labels = c("TCO", "CNAF")),
    sexo_f    = factor(sexo, levels = c(0, 1),
                       labels = c("Femenino", "Masculino")),
    vm_f      = factor(vent_mecanica, levels = c(0, 1),
                       labels = c("No", "Sí")),
    uci_f     = factor(ingreso_uci, levels = c(0, 1),
                       labels = c("No", "Sí")),
    muerte_f  = factor(muerte, levels = c(0, 1),
                       labels = c("No", "Sí"))
  )

# --- Verifico ---
cat("Terapia:\n"); table(interino$terapia_f)
## Terapia:
## 
##  TCO CNAF 
##   51   49
cat("\nSexo:\n"); table(interino$sexo_f)
## 
## Sexo:
## 
##  Femenino Masculino 
##        28        72
cat("\nVMI (desenlace primario):\n"); table(interino$vm_f)
## 
## VMI (desenlace primario):
## 
## No Sí 
## 61 39
cat("\nMuerte:\n"); table(interino$muerte_f)
## 
## Muerte:
## 
## No Sí 
## 92  8
cat("\nIngreso UCI:\n"); table(interino$uci_f)
## 
## Ingreso UCI:
## 
## No Sí 
##  6 94

1.6 Análisis con estos números:

Terapia: 51 TCO vs 49 CNAF — balance casi perfecto (51%/49%), lo que confirma que la aleatorización 1:1 funcionó bien.

Sexo: 72 hombres (72%) vs 28 mujeres (28%), noto un predominio masculino marcado, consistente con lo reportado en la literatura de COVID-19 severo donde los hombres se afectaron más gravemente.

VMI: 39 de 100 pacientes (39%) requirieron intubación,esta es la tasa global del desenlace primario en el interino.

Muerte: 8 de 100 (8%),mortalidad relativamente baja para COVID-19 severo, posiblemente por el uso de esteroides (~93% en ambos grupos según el artículo).

UCI: 94 de 100 (94%) ingresaron a UCI, lo cual es coherente con los criterios de inclusión (PaO₂/FiO₂ < 200, falla respiratoria aguda).

1.7 Tabla 1 — Características basales por grupo

# ═══════════════════════════════════════════════════════════════
# TABLA 1 — Características basales por grupo
# ═══════════════════════════════════════════════════════════════

# Primero verifico cuántos NA hay en IL-6
cat("Valores faltantes en IL-6:", sum(is.na(interino$il6)), "de", nrow(interino), "\n\n")
## Valores faltantes en IL-6: 5 de 100
tabla1 <- interino %>%
  group_by(terapia_f) %>%
  summarise(
    n        = n(),
    edad_med = median(edad, na.rm = TRUE),
    edad_p25 = quantile(edad, 0.25, na.rm = TRUE),
    edad_p75 = quantile(edad, 0.75, na.rm = TRUE),
    masc_n   = sum(sexo == 1, na.rm = TRUE),
    masc_pct = round(mean(sexo == 1, na.rm = TRUE) * 100, 1),
    imc_med  = round(median(imc, na.rm = TRUE), 1),
    imc_p25  = round(quantile(imc, 0.25, na.rm = TRUE), 1),
    imc_p75  = round(quantile(imc, 0.75, na.rm = TRUE), 1),
    dias_med = median(dias_sintomas, na.rm = TRUE),
    dias_p25 = quantile(dias_sintomas, 0.25, na.rm = TRUE),
    dias_p75 = quantile(dias_sintomas, 0.75, na.rm = TRUE),
    spo2_med = median(ingreso_spo2, na.rm = TRUE),
    spo2_p25 = quantile(ingreso_spo2, 0.25, na.rm = TRUE),
    spo2_p75 = quantile(ingreso_spo2, 0.75, na.rm = TRUE),
    pafi_med = round(median(pao2fio2, na.rm = TRUE), 1),
    pafi_p25 = round(quantile(pao2fio2, 0.25, na.rm = TRUE), 1),
    pafi_p75 = round(quantile(pao2fio2, 0.75, na.rm = TRUE), 1),
    il6_med  = round(median(il6, na.rm = TRUE), 1),
    il6_p25  = round(quantile(il6, 0.25, na.rm = TRUE), 1),
    il6_p75  = round(quantile(il6, 0.75, na.rm = TRUE), 1),
    uci_n    = sum(ingreso_uci == 1, na.rm = TRUE),
    uci_pct  = round(mean(ingreso_uci == 1, na.rm = TRUE) * 100, 1),
    .groups  = "drop"
  )

# --- Formato publicación ---
t1 <- data.frame(
  Variable = c("n",
               "Edad, mediana (RIC), años",
               "Sexo masculino, n (%)",
               "IMC, mediana (RIC), kg/m²",
               "Días de síntomas, mediana (RIC)",
               "SpO2 ingreso, mediana (RIC), %",
               "PaO2/FiO2, mediana (RIC)",
               "IL-6, mediana (RIC), pg/mL",
               "Ingreso a UCI, n (%)"),
  TCO = with(tabla1[tabla1$terapia_f == "TCO", ], c(
    n,
    paste0(edad_med, " (", edad_p25, "-", edad_p75, ")"),
    paste0(masc_n, " (", masc_pct, ")"),
    paste0(imc_med, " (", imc_p25, "-", imc_p75, ")"),
    paste0(dias_med, " (", dias_p25, "-", dias_p75, ")"),
    paste0(spo2_med, " (", spo2_p25, "-", spo2_p75, ")"),
    paste0(pafi_med, " (", pafi_p25, "-", pafi_p75, ")"),
    paste0(il6_med, " (", il6_p25, "-", il6_p75, ")"),
    paste0(uci_n, " (", uci_pct, ")")
  )),
  CNAF = with(tabla1[tabla1$terapia_f == "CNAF", ], c(
    n,
    paste0(edad_med, " (", edad_p25, "-", edad_p75, ")"),
    paste0(masc_n, " (", masc_pct, ")"),
    paste0(imc_med, " (", imc_p25, "-", imc_p75, ")"),
    paste0(dias_med, " (", dias_p25, "-", dias_p75, ")"),
    paste0(spo2_med, " (", spo2_p25, "-", spo2_p75, ")"),
    paste0(pafi_med, " (", pafi_p25, "-", pafi_p75, ")"),
    paste0(il6_med, " (", il6_p25, "-", il6_p75, ")"),
    paste0(uci_n, " (", uci_pct, ")")
  ))
)

kable(t1,
      col.names = c("Característica", "TCO (Terapia 0)", "CNAF (Terapia 1)"),
      align = "lcc",
      caption = "Tabla 1 - Características basales estratificadas por grupo
# Equivalente a la Tabla 1 del artículo de Ospina-Tascón et al. (Análisis interino, n = 100)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE, font_size = 13) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  row_spec(1, bold = TRUE, background = col_fondo) %>%
  footnote(general = "RIC = Rango intercuartilico. na.rm = TRUE que apliqué en IL-6 por valores faltantes.",
           general_title = "Nota: ")
Tabla 1 - Características basales estratificadas por grupo # Equivalente a la Tabla 1 del artículo de Ospina-Tascón et al. (Análisis interino, n = 100)
Característica TCO (Terapia 0) CNAF (Terapia 1)
n 51 49
Edad, mediana (RIC), años 56 (49-67) 57 (47-66)
Sexo masculino, n (%) 34 (66.7) 38 (77.6)
IMC, mediana (RIC), kg/m² 30.4 (26.6-34) 29.8 (26.1-32.3)
Días de síntomas, mediana (RIC) 8 (7-11) 9 (5-11)
SpO2 ingreso, mediana (RIC), % 90 (85-92) 89 (85-92)
PaO2/FiO2, mediana (RIC) 103.5 (90.6-130.6) 112.5 (89.4-132.9)
IL-6, mediana (RIC), pg/mL 8.1 (1.1-51.6) 10.6 (0-24.9)
Ingreso a UCI, n (%) 50 (98) 44 (89.8)
Nota:
RIC = Rango intercuartilico. na.rm = TRUE que apliqué en IL-6 por valores faltantes.

1.8 Interpretación de la Tabla 1 — Características basales del análisis interino

Esta Tabla 1 corresponde al análisis interino (n = 100, primeros pacientes aleatorizados), mientras que la Tabla 1 del artículo publicado corresponde al análisis final (n = 199), por lo tanto, los valores no coinciden exactamente, sino que el objetivo es poder evaluar si las tendencias y los rangos son coherentes.

1.9 Mi comparación con la tabla publicada en el artículo

Mostraré a continuación que los valores de esta muestra interina son razonablemente consistentes con los del artículo final:*

comparacion <- data.frame(
  Variable = c("n por grupo",
               "Edad mediana",
               "Sexo masculino",
               "IMC mediana",
               "PaO2/FiO2 mediana",
               "Ingreso a UCI"),
  Interino_TCO = c("51", "56 años", "34 (66.7%)", "30.4", "103.5", "50 (98%)"),
  Interino_CNAF = c("49", "57 años", "38 (77.6%)", "29.8", "112.5", "44 (89.8%)"),
  Final_TCO = c("100", "59 años", "63 (63%)", "29.4", "105", "80 (80%)"),
  Final_CNAF = c("99", "60 años", "71 (72%)", "28.7", "104", "81 (82%)")
)

kable(comparacion,
      col.names = c("Variable", "Interino TCO", "Interino CNAF",
                     "Publicado TCO", "Publicado CNAF"),
      align = "lcccc",
      caption = "Comparación: Tabla 1 interina vs. la Tabla 1 publicada") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE, font_size = 12) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  column_spec(2:3, background = "#D6EAF8") %>%
  column_spec(4:5, background = "#FDEBD0")
Comparación: Tabla 1 interina vs. la Tabla 1 publicada
Variable Interino TCO Interino CNAF Publicado TCO Publicado CNAF
n por grupo 51 49 100 99
Edad mediana 56 años 57 años 59 años 60 años
Sexo masculino 34 (66.7%) 38 (77.6%) 63 (63%) 71 (72%)
IMC mediana 30.4 29.8 29.4 28.7
PaO2/FiO2 mediana 103.5 112.5 105 104
Ingreso a UCI 50 (98%) 44 (89.8%) 80 (80%) 81 (82%)

1.10 Glosario Clínico

# ═══════════════════════════════════════════════════════════════
# GLOSARIO CLÍNICO: Resumo cada variable de la Tabla 1 con su
# significado fisiológico y relevancia en COVID-19 severo deacuerdo al artículo analizado de Ospina-Tascón et al.
# ═══════════════════════════════════════════════════════════════

glosario <- data.frame(
  Abreviatura = c("TCO", "CNAF", "IMC", "SpO2",
                  "PaO2", "FiO2", "PaO2/FiO2",
                  "IL-6", "UCI", "RIC"),
  Nombre = c(
    "Terapia Convencional de Oxígeno",
    "Cánula Nasal de Alto Flujo",
    "Índice de Masa Corporal",
    "Saturación de Oxígeno por Pulsioximetría",
    "Presión Parcial de Oxígeno Arterial",
    "Fracción Inspirada de Oxígeno",
    "Relación PaO2 sobre FiO2 (índice de oxigenación)",
    "Interleucina 6",
    "Unidad de Cuidados Intensivos",
    "Rango Intercuartílico"
  ),
  Que_es = c(
    "Oxígeno a bajo flujo (hasta 15 L/min) mediante puntas nasales, máscara simple o máscara con reservorio, por lo que el gas NO se calienta ni humidifica.",
    "Sistema que entrega oxígeno calentado y humidificado a flujos de hasta 60 L/min por prongas nasales, y genera presión positiva leve en la vía aérea.",
    "Peso (kg) dividido por talla al cuadrado (m²). Normal: 18.5-24.9; sobrepeso: 25-29.9; obesidad: ≥ 30.",
    "Porcentaje de hemoglobina saturada con oxígeno, medido de forma no invasiva con un sensor en el dedo. Normal: ≥ 95%.",
    "Cantidad de oxígeno disuelto en sangre arterial, medida por gasometría. Normal: 80-100 mmHg.",
    "Proporción de oxígeno en el gas que respira el paciente. Aire ambiente = 0.21 (21%). Oxígeno puro = 1.0 (100%).",
    "Indicador de eficiencia del intercambio gaseoso pulmonar. Se obtiene dividiendo la PaO2 entre la FiO2. Normal: > 400. Valores < 200 indican falla respiratoria severa.",
    "Citocina proinflamatoria producida por macrófagos y monocitos. Es un mediador central de la respuesta inflamatoria sistémica. Normal: < 7 pg/mL.",
    "Área hospitalaria con monitoreo continuo y soporte vital avanzado para pacientes críticamente enfermos.",
    "Rango entre el percentil 25 y el percentil 75. Contiene el 50% central de los datos. Medida de dispersión para datos no simétricos."
  ),
  Relevancia_COVID = c(
    "Grupo control del estudio. Limitada capacidad de entrega de oxígeno y no genera presión positiva, lo que puede ser insuficiente en hipoxemia severa.",
    "Grupo intervención. Ventajas fisiológicas: genera presión positiva que recluta alvéolos colapsados, reduce el trabajo respiratorio, lava el espacio muerto nasofaríngeo y mejora la relación ventilación/perfusión.",
    "La obesidad (IMC ≥ 30) fue factor de riesgo independiente para COVID-19 severo, porque causa restricción mecánica pulmonar, estado proinflamatorio crónico y predisposición a trombosis microvascular.",
    "En COVID-19 se describió la 'hipoxemia silenciosa',consistente en pacientes con SpO2 < 90% sin disnea proporcional, posiblemente por alteración de quimiorreceptores. SpO2 < 92% fue el umbral para ajustar la terapia en este estudio.",
    "Refleja directamente la capacidad del pulmón para transferir oxígeno a la sangre. En COVID-19, el daño alveolar difuso y la trombosis microvascular reducen drásticamente esta presión.",
    "A mayor FiO2 necesaria para mantener una SpO2 adecuada, peor es el estado del pulmón. Períodos prolongados con FiO2 > 0.70 pueden causar toxicidad por oxígeno y empeorar el daño pulmonar.",
    "Criterio de inclusión del estudio (< 200). Según la clasificación de Berlín del SDRA: 200-300 = leve; 100-200 = moderado; < 100 = severo. Las medianas de 103-112 indican SDRA moderado-severo.",
    "Niveles elevados (> 100 pg/mL) se asocian con 'tormenta de citocinas': daño endotelial, coagulación intravascular, reclutamiento masivo de neutrófilos y daño alveolar difuso. Será clave en el análisis de subgrupos.",
    "El 90-98% de estos pacientes ingresó a UCI, reflejo de la severidad del cuadro. Durante la pandemia, la disponibilidad de camas UCI fue un recurso limitante crítico.",
    "Se prefiere sobre la desviación estándar cuando la distribución no es simétrica (como IL-6 y días de síntomas, que tienen valores extremos)."
  )
)

kable(glosario,
      col.names = c("Abreviatura", "Nombre completo",
                     "¿Qué es y cómo se mide?",
                     "¿Por qué importa en COVID-19 severo?"),
      align = "llll",
      caption = "Glosario clínico-fisiológico de las variables del estudio") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = TRUE, font_size = 11) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  row_spec(c(7), bold = TRUE, background = "#E4C1F9") %>%
  row_spec(c(2), bold = TRUE, background = "lightyellow") %>%
  column_spec(1, bold = TRUE, width = "6em") %>%
  column_spec(2, width = "12em") %>%
  column_spec(3, width = "20em") %>%
  column_spec(4, width = "22em") %>%
  footnote(general = "SDRA = Síndrome de Dificultad Respiratoria Aguda (clasificación de Berlín, 2012). ECA-2 = Enzima Convertidora de Angiotensina 2 (receptor celular del SARS-CoV-2).",
           general_title = "Nota: ")
Glosario clínico-fisiológico de las variables del estudio
Abreviatura Nombre completo ¿Qué es y cómo se mide? ¿Por qué importa en COVID-19 severo?
TCO Terapia Convencional de Oxígeno Oxígeno a bajo flujo (hasta 15 L/min) mediante puntas nasales, máscara simple o máscara con reservorio, por lo que el gas NO se calienta ni humidifica. Grupo control del estudio. Limitada capacidad de entrega de oxígeno y no genera presión positiva, lo que puede ser insuficiente en hipoxemia severa.
CNAF Cánula Nasal de Alto Flujo Sistema que entrega oxígeno calentado y humidificado a flujos de hasta 60 L/min por prongas nasales, y genera presión positiva leve en la vía aérea. Grupo intervención. Ventajas fisiológicas: genera presión positiva que recluta alvéolos colapsados, reduce el trabajo respiratorio, lava el espacio muerto nasofaríngeo y mejora la relación ventilación/perfusión.
IMC Índice de Masa Corporal Peso (kg) dividido por talla al cuadrado (m²). Normal: 18.5-24.9; sobrepeso: 25-29.9; obesidad: ≥ 30. La obesidad (IMC ≥ 30) fue factor de riesgo independiente para COVID-19 severo, porque causa restricción mecánica pulmonar, estado proinflamatorio crónico y predisposición a trombosis microvascular.
SpO2 Saturación de Oxígeno por Pulsioximetría Porcentaje de hemoglobina saturada con oxígeno, medido de forma no invasiva con un sensor en el dedo. Normal: ≥ 95%. En COVID-19 se describió la ‘hipoxemia silenciosa’,consistente en pacientes con SpO2 < 90% sin disnea proporcional, posiblemente por alteración de quimiorreceptores. SpO2 < 92% fue el umbral para ajustar la terapia en este estudio.
PaO2 Presión Parcial de Oxígeno Arterial Cantidad de oxígeno disuelto en sangre arterial, medida por gasometría. Normal: 80-100 mmHg. Refleja directamente la capacidad del pulmón para transferir oxígeno a la sangre. En COVID-19, el daño alveolar difuso y la trombosis microvascular reducen drásticamente esta presión.
FiO2 Fracción Inspirada de Oxígeno Proporción de oxígeno en el gas que respira el paciente. Aire ambiente = 0.21 (21%). Oxígeno puro = 1.0 (100%). A mayor FiO2 necesaria para mantener una SpO2 adecuada, peor es el estado del pulmón. Períodos prolongados con FiO2 > 0.70 pueden causar toxicidad por oxígeno y empeorar el daño pulmonar.
PaO2/FiO2 Relación PaO2 sobre FiO2 (índice de oxigenación) Indicador de eficiencia del intercambio gaseoso pulmonar. Se obtiene dividiendo la PaO2 entre la FiO2. Normal: > 400. Valores < 200 indican falla respiratoria severa. Criterio de inclusión del estudio (< 200). Según la clasificación de Berlín del SDRA: 200-300 = leve; 100-200 = moderado; < 100 = severo. Las medianas de 103-112 indican SDRA moderado-severo.
IL-6 Interleucina 6 Citocina proinflamatoria producida por macrófagos y monocitos. Es un mediador central de la respuesta inflamatoria sistémica. Normal: < 7 pg/mL. Niveles elevados (> 100 pg/mL) se asocian con ‘tormenta de citocinas’: daño endotelial, coagulación intravascular, reclutamiento masivo de neutrófilos y daño alveolar difuso. Será clave en el análisis de subgrupos.
UCI Unidad de Cuidados Intensivos Área hospitalaria con monitoreo continuo y soporte vital avanzado para pacientes críticamente enfermos. El 90-98% de estos pacientes ingresó a UCI, reflejo de la severidad del cuadro. Durante la pandemia, la disponibilidad de camas UCI fue un recurso limitante crítico.
RIC Rango Intercuartílico Rango entre el percentil 25 y el percentil 75. Contiene el 50% central de los datos. Medida de dispersión para datos no simétricos. Se prefiere sobre la desviación estándar cuando la distribución no es simétrica (como IL-6 y días de síntomas, que tienen valores extremos).
Nota:
SDRA = Síndrome de Dificultad Respiratoria Aguda (clasificación de Berlín, 2012). ECA-2 = Enzima Convertidora de Angiotensina 2 (receptor celular del SARS-CoV-2).

1.11 Interpretación integrada de la Tabla 1

Ahora que he definido cada variable, puedo realizar una lectura integrada de la Tabla 1 que conecte lo estadístico con lo clínico:

Considero que estos 100 pacientes del análisis interino representan un perfil típico de COVID-19 severo durante las primeras olas pandémicas en Colombia, dado que:

los pacientes eran predominantemente masculinos (~72%), de edad mediana (~57 años), con sobrepeso u obesidad (Índice de Masa Corporal mediano ~30), que consultaron alrededor del día 8-9 desde el inicio de síntomas,justo cuando la enfermedad transita de la fase viral a la fase inflamatoria sistémica, que es cuando ocurre el deterioro respiratorio abrupto.

1.12 La severidad clínica se vé reflejada en tres indicadores convergentes:

(1) una Saturación de Oxígeno mediana de 89-90%, lo cual ubica a estos pacientes en la zona crítica de la curva de disociación de la hemoglobina donde cualquier descenso adicional precipita hipoxia tisular.

(2) una relación PaO₂/FiO₂ mediana de 103-112, que corresponde al límite entre Síndrome de Dificultad Respiratoria Aguda moderado y severo según la clasificación de Berlín.

(3) un ingreso a Unidad de Cuidados Intensivos cercano al 94%, confirmando que la inmensa mayoría requirió monitoreo avanzado.

La Interleucina 6 mediana es relativamente baja (8-10 pg/mL), pero el Rango Intercuartílico amplio (0-51 pg/mL), lo que revela una dispersión notable, pues hay pacientes con respuesta inflamatoria mínima y otros con valores muy elevados.

Esta heterogeneidad considero muy importante cuando pase a analizar los subgrupos en la Parte II, porque el artículo original demostró que pacientes con Interleucina 6 ≥ 100 pg/mL podrían no beneficiarse de la Cánula Nasal de Alto Flujo, planteando entonces la hipótesis de que una respuesta inflamatoria descontrolada genera un daño pulmonar tan extenso que ningún soporte ventilatorio no invasivo puede revertirlo.*

Desde el punto de vista estadístico, la aleatorización logró lo que debe lograr, que es distribuir de manera razonablemente equilibrada las variables pronósticas conocidas entre ambos grupos.

No observo desbalances alarmantes que sugieran un fallo en el proceso de aleatorización, de hecho, las pequeñas diferencias numéricas (como 66.7% vs. 77.6% de sexo masculino, o 98% vs. 89.8% de ingreso a Unidad de Cuidados Intensivos) considero que son compatibles con la variabilidad esperada en una muestra de solo 100 pacientes y no invalidan la comparación entre grupos.*

Esta verificación del balance basal me da confianza para proceder a la comparación de los desenlaces, sabiendo que las diferencias que encuentre entre grupos se pueden atribuir más probablemente al efecto de la terapia que a diferencias preexistentes entre los pacientes.

1.13 Comparación de ventilación mecánica invasiva entre grupos

El primer paso del análisis interino consiste en comparar la proporción de pacientes que requirieron ventilación mecánica invasiva (VMI) entre los dos grupos.

Considero que este es el punto más crítico porque la ventilación mecánica invasiva (VMI) constituye el desenlace primario del ensayo, y es el evento que se quiere prevenir con la Cánula Nasal de Alto Flujo, por lo cual, para esta comparación construiré una tabla de contingencia 2×2 que es la estructura básica sobre la cual se calculan todas las medidas de asociación epidemiológica.

# ═══════════════════════════════════════════════════════════════
# TABLA 2×2: Terapia × Ventilación mecánica invasiva
# ═══════════════════════════════════════════════════════════════

# ---Tabla cruda ---
tabla_vm <- table(interino$terapia_f, interino$vm_f)
cat("Tabla de contingencia 2×2:\n\n")
## Tabla de contingencia 2×2:
print(tabla_vm)
##       
##        No Sí
##   TCO  26 25
##   CNAF 35 14
# --- Proporciones por grupo ---
prop_vm <- interino %>%
  group_by(terapia_f) %>%
  summarise(
    Total     = n(),
    Con_VMI   = sum(vent_mecanica == 1, na.rm = TRUE),
    Sin_VMI   = sum(vent_mecanica == 0, na.rm = TRUE),
    Proporcion = round(Con_VMI / Total * 100, 1),
    .groups = "drop"
  )

kable(prop_vm,
      col.names = c("Grupo", "Total", "Con VMI", "Sin VMI", "VMI (%)"),
      align = "lcccc",
      caption = "Proporción de ventilación mecánica invasiva por grupo") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE, font_size = 13) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  row_spec(1, background = "#FAD2E1") %>%
  row_spec(2, background = "#FFF9C4")
Proporción de ventilación mecánica invasiva por grupo
Grupo Total Con VMI Sin VMI VMI (%)
TCO 51 25 26 49.0
CNAF 49 14 35 28.6

1.14 Análisis de la tabla de contingencia

Observo que en el grupo de Terapia Convencional de Oxígeno (51 pacientes), 25 de ellos terminaron requiriendo que les insertaran un tubo endotraqueal en la tráquea y fueran conectados a un ventilador mecánico.

Eso es prácticamente 1 de cada 2 pacientes (49.0%). Cada una de esas intubaciones implica un procedimiento invasivo de alto riesgo, pues el paciente debe ser sedado profundamente, se le administra un relajante neuromuscular que paraliza toda su musculatura (incluida la respiratoria), y un médico introduce un tubo a través de la boca hasta la tráquea bajo visión directa con un laringoscopio.

En el contexto de COVID-19, este procedimiento era además un momento de máximo riesgo de contagio para el equipo de salud por la generación de aerosoles.

En el grupo de Cánula Nasal de Alto Flujo (49 pacientes), solo 14 requirieron intubación y ventilación mecánica invasiva, es decir, 28.6% es decir, aproximadamente 1 de cada 3.5 pacientes.

Los 35 pacientes restantes lograron superar la crisis respiratoria sin necesidad de ser intubados, manteniéndose con el soporte de alto flujo calentado y humidificado a través de las cánulas nasales.

La diferencia entre ambos grupos es de 20.4 puntos porcentuales (49.0% menos 28.6%),lo cual significa que en la práctica clínica, si en una Unidad de Cuidados Intensivos ingresan 100 pacientes con COVID-19 severo, bajo terapia convencional se esperaría entonces intubar a 49 de ellos, mientras que con Cánula Nasal de Alto Flujo se esperaría intubar a 29.

Eso son 20 intubaciones evitadas, lo cual se traduce en:

a) 20 pacientes menos expuestos a los riesgos de la sedación prolongada (delirium, debilidad muscular adquirida en la Unidad de Cuidados Intensivos, neumonía asociada al ventilador).

b) 20 ventiladores mecánicos liberados para otros pacientes durante una pandemia donde los recursos eran escasos.

c) y 20 procedimientos de alto riesgo de contagio que el personal de salud no tuvo que realizar.

Sin embargo, debo ser cautelosa, pues estoy observando los primeros 100 pacientes de un estudio que planificó reclutar 196, por lo cual, esta es una muestra preliminar, y las proporciones observadas podrían cambiar conforme se agreguen más pacientes.

Considero que una diferencia que parece grande con 100 pacientes podría atenuarse o acentuarse con la muestra completa,y es precisamente por eso que existe el análisis interino, para poder evaluar si esta señal es lo suficientemente fuerte como para justifica una decisión temprana, o si se debe esperar a completar el reclutamiento.

Ahora procederé a someter esta diferencia observada a las pruebas estadísticas formales para determinar si puedo atribuirla al efecto real de la terapia o si es compatible con el azar.

# ═══════════════════════════════════════════════════════════════
# PRUEBAS DE HIPÓTESIS
# ═══════════════════════════════════════════════════════════════

# --- Chi-cuadrado de Pearson ---
chi_vm <- chisq.test(tabla_vm, correct = FALSE)

cat("=== PRUEBA CHI-CUADRADO DE PEARSON ===\n")
## === PRUEBA CHI-CUADRADO DE PEARSON ===
cat("H0: la proporción de VMI es igual en ambos grupos\n")
## H0: la proporción de VMI es igual en ambos grupos
cat("H1: las proporciones difieren\n\n")
## H1: las proporciones difieren
cat("Estadístico X²:", round(chi_vm$statistic, 4), "\n")
## Estadístico X²: 4.3922
cat("Grados de libertad:", chi_vm$parameter, "\n")
## Grados de libertad: 1
cat("Valor p:", round(chi_vm$p.value, 4), "\n\n")
## Valor p: 0.0361
# --- Fisher ---
fisher_vm <- fisher.test(tabla_vm)

cat("=== PRUEBA EXACTA DE FISHER ===\n")
## === PRUEBA EXACTA DE FISHER ===
cat("Valor p:", round(fisher_vm$p.value, 4), "\n")
## Valor p: 0.0422
cat("OR:", round(fisher_vm$estimate, 4), "\n")
## OR: 0.4198
cat("IC 95%:", round(fisher_vm$conf.int[1], 4), "-",
    round(fisher_vm$conf.int[2], 4), "\n")
## IC 95%: 0.1664 - 1.0262

1.15 Interpretación de las pruebas de hipótesis

La prueba de Chi-cuadrado de Pearson arroja un estadístico X² de 4.3922 con un valor p de 0.0361 lo cual significa que, bajo la hipótesis nula de que no existe diferencia entre las proporciones de ventilación mecánica invasiva de ambos grupos, la probabilidad de observar una diferencia tan grande o mayor que la encontrada (49.0% frente a 28.6%) es de apenas el 3.6% y dado que este valor se encuentra por debajo del umbral convencional de significancia (alfa = 0.05), me es posible rechazar la hipótesis nula,pues la diferencia observada es estadísticamente significativa al nivel del 5%.*

La prueba exacta de Fisher, que constituye una alternativa más conservadora y no depende de supuestos sobre frecuencias esperadas mínimas, confirma esta conclusión con un valor p de 0.0422, y además el hecho de que ambas pruebas sean concordantes, fortalece la confianza en el hallazgo, de que no se trata de un artefacto del método estadístico empleado, sino de una señal consistente en los datos.

No obstante, debo detenerme en un detalle que considero crucial, sobre la prueba de Fisher que me reporta una Razón de Momios (Odds Ratio) de 0.4198 con un Intervalo de Confianza del 95% que va de 0.1664 a 1.0262, pues Observo que el límite superior de este intervalo es 1.0262, lo cual supera ligeramente el valor nulo de 1.0.

Esto es relevante porque, en sentido estricto, un Intervalo de Confianza que incluye el 1.0 indicaría que no se puede descartar la ausencia de efecto, pero a pesar de ello, el valor p de 0.0422 sí alcanza significancia estadística, lo que pareciera una aparente contradicción entre el Intervalo de Confianza y el valor p, pero creo que se explica porque la prueba exacta de Fisher calcula el Intervalo de Confianza mediante un método diferente (exacto condicional) al que se utiliza para el valor p, y en muestras pequeñas como esta que estoy analizando (100 pacientes) puede pasar que estas discrepancias marginales puedan ocurrir.

A la luz de estos resultados preliminares, puedo afirmar que existe evidencia estadística de que la proporción de pacientes que requirieron ventilación mecánica invasiva difiere entre los dos grupos de tratamiento, con una reducción aparente en el grupo de Cánula Nasal de Alto Flujo, sin embargo, quierre ser cautelosa a la hora de interpretar, dado que,estoy evaluando una muestra interina (los primeros 100 de los 196 planificados) y las estimaciones podrían modificarse con la muestra completa; y también, porque el Intervalo de Confianza de la Razón de Momios roza el valor nulo, lo que me sugiere que la estimación aún es imprecisa.

Ahora procedo a cuantificar la magnitud de esta asociación mediante las medidas epidemiológicas formales.

2 MEDIDAS DE ASOCIACIÓN EPIDEMIOLÓGICA

# ═══════════════════════════════════════════════════════════════
# MEDIDAS DE ASOCIACIÓN EPIDEMIOLÓGICA
# ═══════════════════════════════════════════════════════════════

# Para epitools necesito la tabla con:
# Filas: exposición (0=TCO referencia, 1=CNAF)
# Columnas: desenlace (0=No VMI, 1=Sí VMI)
tabla_epi <- table(
  factor(interino$terapia, levels = c(0, 1)),
  factor(interino$vent_mecanica, levels = c(0, 1))
)

# --- 1. RIESGO RELATIVO (RR) ---
rr_vm <- riskratio(tabla_epi, method = "wald")

cat("═══ RIESGO RELATIVO (RR) ═══\n")
## ═══ RIESGO RELATIVO (RR) ═══
cat("¿Qué mide? Cuántas veces es más (o menos) probable que ocurra\n")
## ¿Qué mide? Cuántas veces es más (o menos) probable que ocurra
cat("el evento en el grupo CNAF comparado con el grupo TCO.\n\n")
## el evento en el grupo CNAF comparado con el grupo TCO.
cat("RR:", round(rr_vm$measure[2, 1], 4), "\n")
## RR: 0.5829
cat("IC 95%:", round(rr_vm$measure[2, 2], 4), "–",
    round(rr_vm$measure[2, 3], 4), "\n")
## IC 95%: 0.3452 – 0.9841
cat("Valor p:", round(rr_vm$p.value[2, 2], 4), "\n\n")
## Valor p: 0.0422
# Interpretación 
rr_val <- rr_vm$measure[2, 1]
if (rr_val < 1) {
  cat("→ Interpretación: los pacientes con CNAF tienen un",
      round((1 - rr_val) * 100, 1), "% MENOS riesgo\n",
      "  de requerir VMI comparado con los de TCO.\n\n")
} else {
  cat("→ Interpretación: los pacientes con CNAF tienen un",
      round((rr_val - 1) * 100, 1), "% MÁS riesgo de VMI.\n\n")
}
## → Interpretación: los pacientes con CNAF tienen un 41.7 % MENOS riesgo
##    de requerir VMI comparado con los de TCO.
# --- 2. ODDS RATIO (OR) ---
or_vm <- oddsratio(tabla_epi, method = "wald")

cat("═══ ODDS RATIO (OR) ═══\n")
## ═══ ODDS RATIO (OR) ═══
cat("¿Qué mide? Compara los momios (odds) de VMI entre grupos.\n")
## ¿Qué mide? Compara los momios (odds) de VMI entre grupos.
cat("Los momios = p / (1-p), es decir, la razón entre la probabilidad\n")
## Los momios = p / (1-p), es decir, la razón entre la probabilidad
cat("de que ocurra vs. que no ocurra.\n\n")
## de que ocurra vs. que no ocurra.
cat("OR:", round(or_vm$measure[2, 1], 4), "\n")
## OR: 0.416
cat("IC 95%:", round(or_vm$measure[2, 2], 4), "–",
    round(or_vm$measure[2, 3], 4), "\n")
## IC 95%: 0.1818 – 0.9521
cat("Valor p:", round(or_vm$p.value[2, 2], 4), "\n\n")
## Valor p: 0.0422
if (or_vm$measure[2, 1] < 1) {
  cat("→ Interpretación: los momios de VMI en el grupo CNAF son\n",
      " ", round((1 - or_vm$measure[2, 1]) * 100, 1),
      "% menores que en el grupo TCO.\n\n")
}
## → Interpretación: los momios de VMI en el grupo CNAF son
##    58.4 % menores que en el grupo TCO.
# --- 3. REDUCCIÓN ABSOLUTA DEL RIESGO (RAR) y NNT ---
p_tco  <- prop_vm$Con_VMI[prop_vm$terapia_f == "TCO"] /
           prop_vm$Total[prop_vm$terapia_f == "TCO"]
p_cnaf <- prop_vm$Con_VMI[prop_vm$terapia_f == "CNAF"] /
           prop_vm$Total[prop_vm$terapia_f == "CNAF"]

RAR <- p_tco - p_cnaf
NNT <- ceiling(1 / RAR)

cat("═══ REDUCCIÓN ABSOLUTA DEL RIESGO (RAR) ═══\n")
## ═══ REDUCCIÓN ABSOLUTA DEL RIESGO (RAR) ═══
cat("Riesgo en TCO:", round(p_tco * 100, 1), "%\n")
## Riesgo en TCO: 49 %
cat("Riesgo en CNAF:", round(p_cnaf * 100, 1), "%\n")
## Riesgo en CNAF: 28.6 %
cat("RAR:", round(RAR * 100, 1), "puntos porcentuales\n\n")
## RAR: 20.4 puntos porcentuales
cat("═══ NÚMERO NECESARIO A TRATAR (NNT) ═══\n")
## ═══ NÚMERO NECESARIO A TRATAR (NNT) ═══
cat("NNT = 1 / RAR =", NNT, "\n")
## NNT = 1 / RAR = 5
cat("→ Interpretación: necesitamos tratar", NNT, "pacientes con CNAF(canula nasal alto flujo)\n")
## → Interpretación: necesitamos tratar 5 pacientes con CNAF(canula nasal alto flujo)
cat("  en lugar de TCO (terapia convencional oxígeno) para evitar 1 intubación adicional.\n")
##   en lugar de TCO (terapia convencional oxígeno) para evitar 1 intubación adicional.
# ═══════════════════════════════════════════════════════════════
# MEDIDAS DE ASOCIACIÓN ( RR, OR, RAR, NNT)
# ═══════════════════════════════════════════════════════════════

# epitools : filas = exposición (0=ref, 1=exp), columnas = desenlace (0, 1)
tabla_epi <- table(
  factor(interino$terapia, levels = c(0, 1)),
  factor(interino$vent_mecanica, levels = c(0, 1))
)

rr_vm <- riskratio(tabla_epi, method = "wald")
or_vm <- oddsratio(tabla_epi, method = "wald")

p_tco  <- prop_vm$Con_VMI[prop_vm$terapia_f == "TCO"] / prop_vm$Total[prop_vm$terapia_f == "TCO"]
p_cnaf <- prop_vm$Con_VMI[prop_vm$terapia_f == "CNAF"] / prop_vm$Total[prop_vm$terapia_f == "CNAF"]
RAR <- p_tco - p_cnaf
NNT <- ceiling(1 / RAR)

# --- Tabla resumen ---
resumen_med <- data.frame(
  Medida = c(
    "Riesgo en TCO (grupo referencia)",
    "Riesgo en CNAF (grupo intervención)",
    "Riesgo Relativo (RR)",
    "Odds Ratio (OR)",
    "Reducción Absoluta del Riesgo (RAR)",
    "Número Necesario a Tratar (NNT)"
  ),
  Valor = c(
    paste0(round(p_tco * 100, 1), "%"),
    paste0(round(p_cnaf * 100, 1), "%"),
    round(rr_vm$measure[2, 1], 3),
    round(or_vm$measure[2, 1], 3),
    paste0(round(RAR * 100, 1), " puntos porcentuales"),
    NNT
  ),
  IC_95 = c("--", "--",
    paste0(round(rr_vm$measure[2, 2], 3), " - ", round(rr_vm$measure[2, 3], 3)),
    paste0(round(or_vm$measure[2, 2], 3), " - ", round(or_vm$measure[2, 3], 3)),
    "--", "--"
  ),
  Interpretacion = c(
    "Proporción de VMI en Terapia Convencional de Oxígeno",
    "Proporción de VMI en Cánula Nasal de Alto Flujo",
    paste0("CNAF modifica el riesgo de VMI en ", round((1-rr_vm$measure[2,1])*100,1), "% respecto a TCO"),
    paste0("Los momios de VMI son ", round((1-or_vm$measure[2,1])*100,1), "% menores con CNAF"),
    "Diferencia absoluta de riesgo entre los dos grupos",
    paste0("Tratar ", NNT, " pacientes con CNAF para evitar 1 intubación adicional")
  )
)

kable(resumen_med,
      col.names = c("Medida", "Valor", "IC 95%", "Interpretación clínica"),
      align = "lcll",
      caption = "Medidas de asociación - VMI en el análisis interino") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = TRUE, font_size = 12) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  row_spec(3, bold = TRUE, background = "#FCEFB4") %>%
  row_spec(4, bold = TRUE, background = "#A7FFEB") %>%
  row_spec(6, bold = TRUE, background = "#B3E5FC")
Medidas de asociación - VMI en el análisis interino
Medida Valor IC 95% Interpretación clínica
Riesgo en TCO (grupo referencia) 49% Proporción de VMI en Terapia Convencional de Oxígeno
Riesgo en CNAF (grupo intervención) 28.6% Proporción de VMI en Cánula Nasal de Alto Flujo
Riesgo Relativo (RR) 0.583 0.345 - 0.984 CNAF modifica el riesgo de VMI en 41.7% respecto a TCO
Odds Ratio (OR) 0.416 0.182 - 0.952 Los momios de VMI son 58.4% menores con CNAF
Reducción Absoluta del Riesgo (RAR) 20.4 puntos porcentuales Diferencia absoluta de riesgo entre los dos grupos
Número Necesario a Tratar (NNT) 5 Tratar 5 pacientes con CNAF para evitar 1 intubación adicional

2.1 Interpretación clínico-estadística de las medidas de asociación

Considero necesario detenerme en cada una de estas medidas porque, aunque todas describen la misma realidad (la relación entre el tipo de terapia y la necesidad de intubación), cada una lo hace desde un ángulo diferente y aporta información complementaria.

El punto de partida son las dos proporciones que calculé directamente de la tabla de contingencia, pues en el grupo de Terapia Convencional de Oxígeno, 25 de 51 pacientes fueron intubados; si divido 25 entre 51 obtengo 0.490, es decir, el 49.0% de los pacientes bajo terapia convencional terminaron conectados a un ventilador mecánico.

En el grupo de Cánula Nasal de Alto Flujo, 14 de 49 pacientes fueron intubados; al dividir 14 entre 49 obtengo 0.286, es decir, el 28.6%. Estas dos proporciones son la materia prima de todas las medidas que siguen.

2.2 Riesgo Relativo de 0.583 (Intervalo de Confianza del 95%: 0.345 – 0.984)

El Riesgo Relativo se obtiene dividiendo el riesgo del grupo de intervención entre el riesgo del grupo de referencia así:

0.286 dividido entre 0.490 da 0.583

Esto significa que los pacientes que recibieron oxígeno calentado y humidificado a alto flujo a través de cánula nasal tuvieron un riesgo de ser intubados que equivale al 58.3% del riesgo que tuvieron los pacientes con terapia convencional. Dicho de forma, la Cánula Nasal de Alto Flujo redujo el riesgo de intubación en un 41.7% en comparación con el oxígeno convencional (este porcentaje se obtiene como 1 menos 0.583, multiplicado por 100).*

El Intervalo de Confianza del 95% va de 0.345 a 0.984. Dado que el límite superior (0.984) no alcanza el valor nulo de 1.0, puedo afirmar que esta reducción del riesgo es estadísticamente significativa,pero la cercanía del límite superior al 1.0 me indica que la estimación tiene cierto grado de imprecisión, lo cual es esperable con una muestra de 100 pacientes.

En el escenario más optimista, la reducción del riesgo podría ser tan grande como el 65.5% (Riesgo Relativo de 0.345); en el escenario más conservador, podría ser tan pequeña como el 1.6% (Riesgo Relativo de 0.984). Esta amplitud del intervalo refuerza la necesidad de completar el reclutamiento para obtener una estimación más precisa.

2.3 Razón de Momios (Odds Ratio): 0.416 (Intervalo de Confianza del 95%: 0.182 – 0.952)

La Razón de Momios se calcula de manera diferente al Riesgo Relativo, pues Primero obtengo los momios de cada grupo, teniendo en cuenta que los momios son la razón entre la probabilidad de que ocurra el evento y la probabilidad de que no ocurra.

En el grupo de Terapia Convencional, los momios de intubación son 25 dividido entre 26 (los que sí fueron intubados entre los que no), lo que da 0.962.

En el grupo de Cánula Nasal de Alto Flujo, los momios son 14 dividido entre 35, es decir 0.400. La Razón de Momios resulta de dividir 0.400 entre 0.962, lo que da 0.416.

Esto significa que los momios de requerir ventilación mecánica invasiva en el grupo de Cánula Nasal de Alto Flujo son el 41.6% de los momios del grupo convencional; expresado de otra manera, los momios de intubación son un 58.4% menores con la terapia de alto flujo. En este caso, el Intervalo de Confianza (0.182 a 0.952) no incluye el 1.0, lo que confirma la significancia estadística de la asociación.*

Es importante señalar que la Razón de Momios (0.416) y el Riesgo Relativo (0.583) no son iguales, y esto no es un error, pues ambas medidas solo coinciden cuando el evento es raro (menos del 10%); en este caso, la intubación ocurrió en el 39% de los pacientes, lo cual es una frecuencia alta.

A partir de lo anterior, el Riesgo Relativo es la medida más fácil de interpretar clínicamente (pues me habla directamente de riesgo), mientras que la Razón de Momios es la medida natural de la regresión logística que emplearé en el análisis definitivo.

2.4 Reducción Absoluta del Riesgo, de 20.4 puntos porcentuales

Esta medida la obtengo simplemente restando las dos proporciones, el 49.0% menos 28.6% igual a 20.4 puntos porcentuales, y a diferencia del Riesgo Relativo (que es una medida relativa), la Reducción Absoluta del Riesgo me dice cuántos pacientes de cada 100 se benefician directamente de la intervención.

Considero que esta es la medida mejor para el clínico que está frente al paciente, pues de cada 100 pacientes con COVID-19 severo tratados con Cánula Nasal de Alto Flujo en lugar de oxígeno convencional, aproximadamente 20 evitarían la intubación.

2.5 Número Necesario a Tratar de 5

El Número Necesario a Tratar se calcula como el inverso de la Reducción Absoluta del Riesgo, es decir, 1 dividido entre 0.204 da 4.9, que redondeo a 5.

Este número tiene una interpretación clínica interesante, pues por cada 5 pacientes con COVID-19 severo que trate con Cánula Nasal de Alto Flujo en lugar de oxígeno convencional, se evita 1 intubación que de otra forma hubiera ocurrido.

En el contexto de la pandemia, este hallazgo es muy llamativo, pues un Número Necesario a Tratar de 5 se considera excelente en medicina; para ponerlo en perspectiva, muchas intervenciones farmacológicas ampliamente aceptadas (como las estatinas para prevención primaria de eventos cardiovasculares) tienen Números Necesarios a Tratar de 50 a 100.

Específicamente, un Número Necesario a Tratar de 5 implica que en un hospital con 50 pacientes con COVID-19 severo, el uso de Cánula Nasal de Alto Flujo podría evitar aproximadamente 10 intubaciones, liberando 10 ventiladores mecánicos y 10 camas de cuidado intensivo avanzado para otros pacientes.

En conjunto, las cuatro medidas cuentan la misma historia desde perspectivas complementarias:

1.la Cánula Nasal de Alto Flujo se asoció con una reducción clínicamente relevante y estadísticamente significativa en la necesidad de ventilación mecánica invasiva durante el análisis interino.

Sin embargo, debo recordar que estos son resultados preliminares de los primeros 100 pacientes; la pregunta ahora es si esta señal es lo suficientemente fuerte como para detener el ensayo o si debo esperar a la muestra completa. Para responder eso, primero debo analizar el segundo desenlace del análisis interino: la mortalidad.

2.6 Gráfica de VMI(ventilación mecánica invasiva) por grupo

# ═══════════════════════════════════════════════════════════════
# GRÁFICA: Proporción de VMI por grupo
# ═══════════════════════════════════════════════════════════════

datos_graf <- prop_vm %>%
  mutate(
    Etiqueta = paste0(Con_VMI, "/", Total, "\n(", Proporcion, "%)"),
    terapia_f = factor(terapia_f, levels = c("TCO", "CNAF"))
  )

ggplot(datos_graf, aes(x = terapia_f, y = Proporcion / 100, fill = terapia_f)) +
  geom_col(width = 0.55, color = "white", linewidth = 1) +
  geom_text(aes(label = Etiqueta), vjust = -0.3,
            size = 5, fontface = "bold", lineheight = 0.9) +
  scale_fill_manual(values = c("TCO" = col_tco, "CNAF" = col_cnaf)) +
  scale_y_continuous(labels = percent_format(),
                     limits = c(0, 0.75),
                     expand = expansion(mult = c(0, 0.05))) +
  labs(
    title    = "Proporción de Ventilación Mecánica Invasiva por Grupo",
    subtitle = "Análisis interino — Primeros 100 pacientes aleatorizados",
    x        = NULL,
    y        = "Proporción de pacientes intubados",
    caption  = paste0("RR = ", round(rr_vm$measure[2,1], 2),
                      " | OR = ", round(or_vm$measure[2,1], 2),
                      " | RAR = ", round(RAR*100, 1), " pp",
                      " | NNT = ", NNT,
                      " | p (Fisher) = ", round(fisher_vm$p.value, 4))
  ) +
  theme_minimal(base_size = 14) +
  theme(
    legend.position    = "none",
    plot.title         = element_text(face = "bold", color = col_accent, hjust = 0.5),
    plot.subtitle      = element_text(color = "gray40", hjust = 0.5),
    plot.caption       = element_text(size = 10, color = "gray50"),
    panel.grid.major.x = element_blank(),
    axis.text.x        = element_text(face = "bold", size = 14)
  )

2.7 Análisis de la gráfica de ventilación mecánica invasiva

Considero que esta gráfica condensa visualmente todo lo que he calculado hasta ahora, por lo cual me detengo a leerla con cuidado elemento por elemento.

Lo primero que capta mi atención es el contraste entre las dos barras, pues la barra roja, que representa al grupo de Terapia Convencional de Oxígeno, se eleva notablemente por encima de la barra azul, que representa al grupo de Cánula Nasal de Alto Flujo.

Este contraste visual no es decorativo, pues traduce a imagen la diferencia de 20.4 puntos porcentuales que calculé entre las proporciones de intubación de ambos grupos, por ejemplo, la barra roja alcanza prácticamente la marca del 50%, mientras que la azul se queda por debajo del 30%; esa distancia vertical entre ambas barras es, literalmente, la Reducción Absoluta del Riesgo.

Sobre cada barra se muestra la fracción que la origina, como se ve en la barra roja que se lee “25/51 (49%)”, esto me dice que de los 51 pacientes que fueron asignados por aleatorización a recibir oxígeno convencional mediante dispositivos de bajo flujo (puntas nasales, máscara simple o máscara con reservorio), 25 de ellos progresaron a tal grado de deterioro respiratorio que fue necesario intubarlos e iniciar ventilación mecánica invasiva.

Significa que prácticamente la mitad de los pacientes que recibieron la terapia estándar terminaron con un tubo en la tráquea, sedados, paralizados y conectados a una máquina que respiraba por ellos; y desde el punto de vista fisiopatológico, esto refleja que el oxígeno convencional a bajo flujo fue insuficiente para sostener la oxigenación en estos pacientes con daño alveolar difuso por COVID-19, donde el pulmón dañado necesitaba no solo oxígeno, sino también presión positiva para reclutar los alvéolos colapsados y reducir el esfuerzo respiratorio.

En la barra azul leo “14/49 (28.6%)”,significa que de los 49 pacientes que recibieron oxígeno calentado y humidificado a alto flujo a través de cánula nasal, solo 14 necesitaron ser intubados. Los 35 restantes lograron superar la crisis respiratoria sin ventilación mecánica invasiva.

Este resultado sugiere que los mecanismos fisiológicos de la cánula de alto flujo (la presión positiva leve que genera en la vía aérea, el lavado del espacio muerto nasofaríngeo, la humidificación que protege la mucosa, y la reducción del trabajo respiratorio) fueron suficientes para sostener a estos pacientes durante la fase crítica de la enfermedad.

En la parte inferior de la gráfica aparece una línea de texto que sintetiza todas las medidas de asociación calculadas, como son:

El Riesgo Relativo de 0.58 confirma que el riesgo de intubación con la cánula de alto flujo fue apenas el 58% del riesgo con terapia convencional

la Razón de Momios de 0.42 indica que los momios de intubación fueron menos de la mitad con la terapia de alto flujo.

la Reducción Absoluta del Riesgo de 20.4 puntos porcentuales cuantifica la diferencia en términos absolutos.

el Número Necesario a Tratar de 5 traduce esta diferencia a la decisión clínica individual (tratar 5 pacientes para evitar 1 intubación).

y el valor p de la prueba exacta de Fisher de 0.0422confirma que esta diferencia es estadísticamente significativa al nivel convencional del 5%.*

No obstante, debo integrar una reflexión crítica sobre lo que esta gráfica no me muestra, pues los Intervalos de Confianza no aparecen representados visualmente en las barras, lo cual podría dar una falsa sensación de precisión.

Como analicé previamente, el Intervalo de Confianza del Riesgo Relativo llega hasta 0.984, rozando el valor nulo; esto significa que, aunque la mejor estimación es una reducción del 41.7% en el riesgo de intubación, el efecto verdadero podría ser tan pequeño como una reducción del 1.6%.

De igual manera, la gráfica no refleja que estos son datos de los primeros 100 pacientes de un estudio que planificó reclutar 196, por lo cual estas proporciones podrían modificarse conforme se incorporen más participantes.

En definitiva, esta gráfica presenta una señal clínicamente relevante y estadísticamente significativa a favor de la Cánula Nasal de Alto Flujos sin embargo,la pregunta que debo responder como parte del análisis interino no es “¿hay diferencia?”, sino “¿es esta diferencia lo suficientemente contundente como para justificar la detención temprana del ensayo?”.

Para responder, necesito primero evaluar el segundo desenlace (mortalidad) y luego contrastar los valores p observados con los umbrales de detención de Haybittle-Peto.

2.8 Comparación de mortalidad entre grupos

La segunda comparación del análisis interino que haré es evaluar la mortalidad. Desde el punto de vista ético, este es el desenlace más sensible, pues un exceso de muertes en cualquier grupo constituiría la señal más fuerte para considerar la detención del ensayo, por lo que aplico el mismo procedimiento que para VMI, haciendo una tabla 2×2, pruebas de hipótesis, medidas de asociación y gráfica.

# ═══════════════════════════════════════════════════════════════
# ANÁLISIS DE MORTALIDAD — ANÁLISIS INTERINO
# ═══════════════════════════════════════════════════════════════

# --- Tabla 2×2 ---
tabla_muerte <- table(interino$terapia_f, interino$muerte_f)
cat("Tabla de contingencia 2×2 — Mortalidad\n\n")
## Tabla de contingencia 2×2 — Mortalidad
print(tabla_muerte)
##       
##        No Sí
##   TCO  46  5
##   CNAF 46  3
# --- Proporciones ---
prop_muerte <- interino %>%
  group_by(terapia_f) %>%
  summarise(
    Total     = n(),
    Muertes   = sum(muerte == 1, na.rm = TRUE),
    Proporcion = round(Muertes / Total * 100, 1),
    .groups = "drop"
  )

kable(prop_muerte,
      col.names = c("Grupo", "Total", "Muertes", "Mortalidad (%)"),
      align = "lccc",
      caption = "Proporción de mortalidad por grupo — Análisis interino") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE, font_size = 13) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  row_spec(1, background = "#FADBD8") %>%
  row_spec(2, background = "#D6EAF8")
Proporción de mortalidad por grupo — Análisis interino
Grupo Total Muertes Mortalidad (%)
TCO 51 5 9.8
CNAF 49 3 6.1
# --- Pruebas estadísticas ---
fisher_muerte <- fisher.test(tabla_muerte)
chi_muerte    <- chisq.test(tabla_muerte, correct = TRUE)

cat("\n═══ Chi-cuadrado (con corrección de Yates) ═══\n")
## 
## ═══ Chi-cuadrado (con corrección de Yates) ═══
cat("Valor p:", round(chi_muerte$p.value, 4), "\n\n")
## Valor p: 0.7568
cat("═══ Fisher ═══\n")
## ═══ Fisher ═══
cat("Valor p:", round(fisher_muerte$p.value, 4), "\n")
## Valor p: 0.7155
cat("OR:", round(fisher_muerte$estimate, 4), "\n")
## OR: 0.603
cat("IC 95%:", round(fisher_muerte$conf.int[1], 4), "–",
    round(fisher_muerte$conf.int[2], 4), "\n")
## IC 95%: 0.0885 – 3.3082

2.9 Análisis de los resultados de mortalidad

Me detengo en estos números porque la mortalidad, tal como había mencionado, es el desenlace más importante desde el punto de vista ético y humano, pues cada cifra aquí representa una persona que falleció.

En el grupo de Terapia Convencional de Oxígeno, 5 de 51 pacientes fallecieron, lo que corresponde a una mortalidad del 9.8%.

En el grupo de Cánula Nasal de Alto Flujo, 3 de 49 pacientes fallecieron, equivalente al 6.1%.

A primera vista, la diferencia parece sugerir una tendencia favorable hacia la cánula de alto flujo, pues la mortalidad es 3.7 puntos porcentuales menor en este grupo, pero la magnitud absoluta de los números me obliga a ser cuidadosa con la interpretación.

Considero que el hallazgo más revelador de este análisis no es la diferencia entre grupos, sino lo pequeños que son los números involucrados.

Estoy comparando 5 muertes contra 3 muertes, y en un total de 100 pacientes, donde ocurrieron solamente 8 fallecimientos. Cuando el número de eventos es tan bajo, las pruebas estadísticas carecen de la potencia necesaria para detectar diferencias reales; dicho de otra forma, el estudio con 100 pacientes simplemente considero que no tiene la capacidad estadística para pronunciarse de manera confiable sobre la mortalidad.

Las pruebas estadísticas confirman esta limitación, pues la prueba de Chi-cuadrado con corrección de Yates arroja un valor p de 0.7568, y la prueba exacta de Fisher un valor p de 0.7155.

Ambos valores están muy por encima del umbral convencional de 0.05, lo cual significa que la diferencia observada (9.8% frente a 6.1%) es perfectamente compatible con el azar. En términos formales, no puedo rechazar la hipótesis nula de que la mortalidad es igual en ambos grupos.

La Razón de Momios reportada por la prueba de Fisher es de 0.603, lo que en principio sugeriría que los momios de fallecer son un 39.7% menores en el grupo de cánula de alto flujo, sin embargo, el Intervalo de Confianza del 95% se extiende desde 0.0885 hasta 3.3082, siendo este intervalo extraordinariamente amplio y, lo que es más importante, cruza holgadamente el valor nulo de 1.0.

Esto tiene una interpretación muy concreta, pues con los datos disponibles, el efecto verdadero de la terapia sobre la mortalidad podría ir desde una reducción del 91% en los momios de muerte (límite inferior de 0.0885, escenario muy optimista) hasta un aumento del 230% en los momios de muerte (límite superior de 3.3082, escenario desfavorable).

Un intervalo que abarca desde un beneficio enorme hasta un daño considerable refleja una incertidumbre total; en la práctica, estos datos no me permiten concluir absolutamente nada sobre el efecto de la terapia en la mortalidad.

Es razonable preguntarme por qué ocurre esta imprecisión tan marcada, y creo que la respuesta radica en la relación entre el número de eventos y la potencia estadística, pues para detectar una diferencia de 3.7 puntos porcentuales en mortalidad (de 9.8% a 6.1%) con una potencia del 80% y un nivel de significancia del 5%, se necesitarían varios cientos de pacientes por grupo, muy por encima de los 50 que se tiene en cada brazo.

Los propios autores del ensayo reconocieron en el artículo publicado que el estudio no fue diseñado ni potenciado para evaluar diferencias en mortalidad; el cálculo del tamaño de muestra se basó exclusivamente en el desenlace de ventilación mecánica invasiva.

A pesar de la ausencia de significancia estadística, considero importante no descartar completamente la señal observada, pues el hecho de que la Razón de Momios puntual sea 0.603 (es decir, inferior a 1.0) es consistente con la dirección del efecto encontrado en el desenlace de ventilación mecánica, es decir, si la cánula de alto flujo reduce la intubación, es biológicamente plausible que también reduzca la mortalidad, dado que la ventilación mecánica invasiva se asocia con complicaciones que incrementan el riesgo de muerte (neumonía asociada al ventilador, tromboembolismo, delirium, debilidad adquirida en la unidad de cuidados intensivos).

Sin embargo, esta plausibilidad biológica no sustituye la evidencia estadística, por lo que para confirmar o refutar un efecto sobre la mortalidad, se requerirían estudios con tamaños de muestra sustancialmente mayores o metaanálisis que integren datos de múltiples ensayos.

Sintetizando lo observado en este segundo desenlace, entonces la mortalidad fue numéricamente menor en el grupo de Cánula Nasal de Alto Flujo (6.1% frente a 9.8%), pero esta diferencia no es estadísticamente significativa (valor p de 0.7155), y el Intervalo de Confianza es excesivamente amplio, además el número de eventos es demasiado pequeño para extraer conclusiones confiables.

Ahora cuento con los elementos necesarios para integrar ambos desenlaces y formular mi recomendación sobre la continuación o detención del ensayo.

# --- Gráfica de mortalidad ---
datos_muerte <- prop_muerte %>%
  mutate(
    Etiqueta = paste0(Muertes, "/", Total, "\n(", Proporcion, "%)"),
    terapia_f = factor(terapia_f, levels = c("TCO", "CNAF"))
  )

ggplot(datos_muerte, aes(x = terapia_f, y = Proporcion / 100, fill = terapia_f)) +
  geom_col(width = 0.55, color = "white", linewidth = 1) +
  geom_text(aes(label = Etiqueta), vjust = -0.3,
            size = 5, fontface = "bold", lineheight = 0.9) +
  scale_fill_manual(values = c("TCO" = col_tco, "CNAF" = col_cnaf)) +
  scale_y_continuous(labels = percent_format(),
                     limits = c(0, 0.30),
                     expand = expansion(mult = c(0, 0.05))) +
  labs(
    title    = "Proporción de Mortalidad por Grupo",
    subtitle = "Análisis interino - Primeros 100 pacientes",
    x        = NULL,
    y        = "Proporción de fallecidos",
    caption  = paste0("p (Fisher) = ", round(fisher_muerte$p.value, 4),
                      " | OR = ", round(fisher_muerte$estimate, 2))
  ) +
  theme_minimal(base_size = 14) +
  theme(
    legend.position    = "none",
    plot.title         = element_text(face = "bold", color = col_accent, hjust = 0.5),
    plot.subtitle      = element_text(color = "gray40", hjust = 0.5),
    plot.caption       = element_text(size = 10, color = "gray50"),
    panel.grid.major.x = element_blank(),
    axis.text.x        = element_text(face = "bold", size = 14)
  )

2.10 Análisis de la gráfica de mortalidad

La gráfica hace evidente lo que los números ya sugerían y analicé, pues ambas barras son pequeñas y su diferencia es mínima. La barra roja (Terapia Convencional de Oxígeno, 5 fallecidos de 51, 9.8%) apenas supera la barra azul (Cánula Nasal de Alto Flujo, 3 fallecidos de 49, 6.1%).

A diferencia de la gráfica de ventilación mecánica invasiva, donde el contraste visual entre las barras era notorio y la diferencia alcanzaba 20 puntos porcentuales, aquí las barras prácticamente se miran de frente, separadas por apenas 3.7 puntos.

El valor p de 0.7155, visible en el pie de la gráfica, confirma que esta diferencia es atribuible al azar. Con tan solo 8 muertes en 100 pacientes, el estudio sencillamente no tiene la potencia para pronunciarse sobre mortalidad; es como intentar leer un letrero a kilómetros de distancia sin lentes.

Ahora bien, lo que sí me resulta coherente es la dirección, pues tanto en ventilación mecánica invasiva como en mortalidad, los números favorecen al grupo de Cánula Nasal de Alto Flujo. Que ambos desenlaces apunten en la misma dirección refuerza la plausibilidad biológica del efecto, aunque solo el primero alcance significancia estadística.

Con estos dos análisis completados, procedo a integrarlos para formular la recomendación del análisis interino.

2.11 Recomendación con criterios Haybittle-Peto

Ahora integro los resultados de ambos desenlaces para formular una recomendación argumentada, aplicando los criterios de detención de Haybittle-Peto que fueron los establecidos en el protocolo del ensayo HiFLo-Covid.

# ═══════════════════════════════════════════════════════════════
# EVALUACIÓN DE CRITERIOS DE DETENCIÓN DE HAYBITTLE-PETO
# ═══════════════════════════════════════════════════════════════

# Umbrales del protocolo HiFLo-Covid:
umbral_seguridad <- 0.001    # Para detener por daño
umbral_eficacia  <- 0.0001   # Para detener por beneficio abrumador

# Valores p observados
p_vmi    <- fisher_vm$p.value
p_muerte <- fisher_muerte$p.value

criterios <- data.frame(
  Desenlace = c("Ventilación mecánica invasiva", "Mortalidad"),
  Valor_p = c(round(p_vmi, 4), round(p_muerte, 4)),
  Umbral_seguridad = c("< 0.001", "< 0.001"),
  Cumple_seguridad = c(
    ifelse(p_vmi < umbral_seguridad, "SÍ — DETENER", "NO — continuar"),
    ifelse(p_muerte < umbral_seguridad, "SÍ — DETENER", "NO — continuar")
  ),
  Umbral_eficacia = c("< 0.0001", "< 0.0001"),
  Cumple_eficacia = c(
    ifelse(p_vmi < umbral_eficacia, "SÍ — DETENER", "NO — continuar"),
    ifelse(p_muerte < umbral_eficacia, "SÍ — DETENER", "NO — continuar")
  )
)

kable(criterios,
      col.names = c("Desenlace", "Valor p observado",
                     "Umbral seguridad", "¿Detener por daño?",
                     "Umbral eficacia", "¿Detener por eficacia?"),
      align = "lccccc",
      caption = "Evaluación de criterios de detención de Haybittle-Peto — Análisis interino") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = TRUE, font_size = 12) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  column_spec(4, bold = TRUE, color = "darkgreen") %>%
  column_spec(6, bold = TRUE, color = "darkgreen")
Evaluación de criterios de detención de Haybittle-Peto — Análisis interino
Desenlace Valor p observado Umbral seguridad ¿Detener por daño? Umbral eficacia ¿Detener por eficacia?
Ventilación mecánica invasiva 0.0422 < 0.001 NO — continuar < 0.0001 NO — continuar
Mortalidad 0.7155 < 0.001 NO — continuar < 0.0001 NO — continuar

2.12 Análisis de la tabla de criterios de detención de Haybittle-Peto

Observo esta tabla como el momento decisivo del análisis interino, pues es aquí donde los números que he calculado se confrontan con las reglas preespecificadas en el protocolo del ensayo para determinar si el estudio debe continuar o detenerse.

Considero fundamental explicar cada columna y cada valor, porque esta decisión tiene consecuencias directas sobre la vida de los pacientes que aún no han sido reclutados.

##¿Qué son los umbrales de Haybittle-Peto y por qué son tan exigentes?

Los límites de Haybittle-Peto son reglas de detención temprana que el equipo investigador establece antes de iniciar el ensayo, precisamente para evitar que las decisiones intermedias estén influenciadas por los propios resultados.

Funcionan como semáforos muy estrictos, pues solo se enciende la luz roja (detener el estudio) cuando la evidencia es abrumadora, y en el ensayo HiFLo-Covid se definieron dos umbrales:

El umbral de seguridad (valor p inferior a 0.001) responde a la pregunta de si “¿hay evidencia tan contundente de daño que sería éticamente inaceptable seguir exponiendo a pacientes a la intervención?” pues con un valor p inferior a 0.001 significa que habría menos de 1 en 1,000 probabilidades de observar la diferencia encontrada si realmente no existiera daño.

Es un umbral muy conservador porque detener un estudio por seguridad tiene consecuencias graves, pues se abandona la investigación, se pierde la oportunidad de generar conocimiento y se alarma a la comunidad médica.

El umbral de eficacia (valor p inferior a 0.0001) responde a la pregunta opuesta, de si “¿hay evidencia tan abrumadora de beneficio que sería éticamente inaceptable seguir asignando pacientes al grupo control, privándolos de una terapia claramente superior?”

Este umbral es aún más estricto (1 en 10,000) porque detener por eficacia conlleva el riesgo adicional de sobreestimar el efecto, pues cuando un estudio se detiene tempranamente por resultados favorables, la magnitud del beneficio observado tiende a ser mayor que la que se encontraría con la muestra completa, un fenómeno bien documentado en la literatura revisada de clase.

2.13 Confrontación de los valores p con los umbrales

El valor p que se obtuvo para ventilación mecánica invasiva fue de 0.0422. Este valor, aunque significativo bajo el umbral convencional de 0.05 que usaría en un análisis final, se encuentra muy lejos de los umbrales de Haybittle-Peto.

Para dimensionar la distancia, el umbral de eficacia exige un valor p inferior a 0.0001, es decir, mi valor p tendría que ser más de 400 veces más pequeño de lo que es para justificar una detención por eficacia abrumadora.

De igual manera, está lejos del umbral de seguridad de 0.001, que es más de 40 veces más pequeño que mi valor p observado. El ensayo, en lo que respecta a la intubación, muestra una señal prometedora pero no lo suficientemente contundente como para tomar una decisión definitiva con solo la mitad de la muestra.

El valor p para mortalidad fue de 0.7155, un valor que ni siquiera se acerca a la significancia convencional, mucho menos a los umbrales de Haybittle-Peto, pues una probabilidad del 71.55% de obtener estos resultados por azar indica que los datos de mortalidad son completamente compatibles con la hipótesis nula de que no existe diferencia entre los grupos.

Esto NO significa que la Cánula Nasal de Alto Flujo no tenga efecto sobre la mortalidad; significa que con 8 muertes en 100 pacientes, el estudio carece de la potencia necesaria para detectarlo.

¿Por qué estos umbrales son tan diferentes del alfa convencional de 0.05?

Me hago esta pregunta, porque me parece esencial entender la lógica detrás de esta diferencia, pues en un análisis final (cuando se ha completado el reclutamiento), se utiliza un nivel de significancia de 0.05, lo que acepta un 5% de probabilidad de cometer un Error Tipo I (rechazar la hipótesis nula cuando es verdadera, es decir, concluir que hay efecto cuando realmente no lo hay).

Sin embargo, en un análisis interino estoy evaluando los datos cuando la muestra está incompleta, lo que introduce dos problemas:

primero, las estimaciones son más imprecisas y volátiles

segundo, si uso el mismo umbral de 0.05 cada vez que miro los datos, la probabilidad acumulada de cometer un Error Tipo I aumenta con cada mirada (problema de las comparaciones múltiples).

Los umbrales de Haybittle-Peto resuelven esto siendo tan estrictos en el análisis interino que prácticamente no consumen el nivel de significancia global, lo cual permite que el análisis final se realice con un alfa de 0.05 esencialmente intacto.

En definitiva, esta tabla me confirma lo que intuía a partir de los análisis individuales, donde la evidencia acumulada con los primeros 100 pacientes es insuficiente para justificar la detención del ensayo, tanto por seguridad como por eficacia.

La recomendación de continuar no es una conclusión decepcionante, por el contrario, es la decisión metodológicamente correcta que protege simultáneamente a los participantes actuales (no se ha detectado daño), a los participantes futuros (podrán beneficiarse de un conocimiento generado con rigor), y a la comunidad científica (las conclusiones finales se basarán en una muestra completa y estimaciones precisas).

3 PARTE II: ANÁLISIS DEFINITIVO

Una vez que el Comité Independiente de Monitoreo de Datos y Seguridad recomendó continuar el ensayo, el reclutamiento prosiguió hasta completar 220 pacientes aleatorizados.

Tras excluir 8 que retiraron su consentimiento y 13 que fueron trasladados a hospitales no participantes por razones administrativas (relacionadas con seguros de salud), la muestra final del análisis fue de 199 pacientes.

La base de datos que utilizaré a continuación corresponde a la hoja que he renombrado “BD Final” del archivo, y contiene variables adicionales que no estaban disponibles en la base interina, incluyendo las variables de subgrupo que serán esenciales para el análisis.

3.1 Carga y preparación de los datos definitivos

# ═══════════════════════════════════════════════════════════════
# CARGA DE LA BASE DE DATOS DEFINITIVA
# ═══════════════════════════════════════════════════════════════

final_raw <- read_excel("BD_HIFLO.xlsx", sheet = "BD Final")

cat("Dimensiones:", nrow(final_raw), "filas ×", ncol(final_raw), "columnas\n\n")
## Dimensiones: 202 filas × 39 columnas
cat("Nombres de las variables:\n")
## Nombres de las variables:
names(final_raw)
##  [1] "record_id"                   "crit_inc_falla_res"         
##  [3] "terapia_aleat"               "Terapia"                    
##  [5] "edad"                        "sexo"                       
##  [7] "peso"                        "talla"                      
##  [9] "imc"                         "dias_sintomas"              
## [11] "ingreso_pas"                 "ingreso_pad"                
## [13] "ingreso_pam"                 "ingreso_temp"               
## [15] "ingreso_fr"                  "ingreso_fc"                 
## [17] "ingreso_spo2"                "sop_res_pre_pao2fio2"       
## [19] "Interleuquina 6"             "Hidroxicloroquin"           
## [21] "Metilprednisolona"           "Ventilación mecánica"       
## [23] "ingreso"                     "Traqueostomía"              
## [25] "Terapia de reemplazo renal"  "Ingreso a UCI"              
## [27] "Muerte"                      "Fecha de muerte"            
## [29] "Int ingreso -aleatorización" "Duración de la terapia"     
## [31] "Tiempo a la intubación"      "Duración VM"                
## [33] "Drtación TRR"                "Intervalo a la muerte"      
## [35] "Estancia en UCI"             "Estancia total"             
## [37] "Días libres de VM"           "Días libres de TRR"         
## [39] "Durac VMI"
# ═══════════════════════════════════════════════════════════════
# PREPARACIÓN DE LA BASE DEFINITIVA
# ═══════════════════════════════════════════════════════════════

# --- Selecciono y renombro las variables que necesito ---
final <- final_raw %>%
  rename(
    terapia        = Terapia,
    terapia_label  = terapia_aleat,
    il6            = `Interleuquina 6`,
    pao2fio2       = sop_res_pre_pao2fio2,
    vent_mecanica  = `Ventilación mecánica`,
    ingreso_uci    = `Ingreso a UCI`,
    muerte         = Muerte,
    estancia_uci   = `Estancia en UCI`,
    estancia_total = `Estancia total`,
    dias_libres_vm = `Días libres de VM`,
    dias_libres_trr = `Días libres de TRR`
  )

# --- Creo las variables de subgrupo ---
final <- final %>%
  mutate(
    terapia_f = factor(terapia, levels = c(0, 1),
                       labels = c("TCO", "CNAF")),
    edad60    = ifelse(edad >= 60, 1, 0),
    pafi150   = ifelse(pao2fio2 < 150, 1, 0),
    il6_100   = ifelse(il6 >= 100, 1, 0)
  )

# --- Verifico distribuciones ---
cat("=== Grupo de tratamiento ===\n")
## === Grupo de tratamiento ===
table(final$terapia_f)
## 
##  TCO CNAF 
##  101  101
cat("\n=== Ventilación mecánica invasiva (desenlace primario) ===\n")
## 
## === Ventilación mecánica invasiva (desenlace primario) ===
table(final$vent_mecanica, useNA = "always")
## 
##    0    1 <NA> 
##  117   85    0
cat("\n=== Muerte ===\n")
## 
## === Muerte ===
table(final$muerte, useNA = "always")
## 
##    0    1 <NA> 
##  178   24    0
cat("\n=== Subgrupo edad (0: <60 años; 1: >=60 años) ===\n")
## 
## === Subgrupo edad (0: <60 años; 1: >=60 años) ===
table(final$edad60, useNA = "always")
## 
##    0    1 <NA> 
##   99  103    0
cat("\n=== Subgrupo PaO2/FiO2 (1: <150; 0: >=150) ===\n")
## 
## === Subgrupo PaO2/FiO2 (1: <150; 0: >=150) ===
table(final$pafi150, useNA = "always")
## 
##    0    1 <NA> 
##   35  167    0
cat("\n=== Subgrupo IL-6 (1: >=100; 0: <100) ===\n")
## 
## === Subgrupo IL-6 (1: >=100; 0: <100) ===
table(final$il6_100, useNA = "always")
## 
##    0    1 <NA> 
##  164   17   21

3.2 Mi análisis:

Tratamiento: 101 vs 101 — balance perfecto Ventilación mecánica invasiva: 85 intubados de 202 (42%) — sin valores faltantes Muerte: 24 fallecidos de 202 (11.9%) — sin valores faltantes

Subgrupo edad: 99 menores de 60 años, 103 de 60 o más — bien distribuido Subgrupo PaO₂/FiO₂: 167 con valores inferiores a 150 (más severos), solo 35 con valores de 150 o más — la gran mayoría tenía hipoxemia severa

Subgrupo Interleucina 6: 164 con valores bajos, solo 17 con valores de 100 o más, y 21 valores faltantes — este subgrupo tendrá pocos pacientes

3.3 Desenlace primario — Razón de Momios para ventilación mecánica invasiva

Con la muestra completa procedo a calcular la Razón de Momios (Odds Ratio)que cuantifica la asociación entre el tipo de terapia y la necesidad de intubación, siendo la medida central del análisis definitivo.

# ═══════════════════════════════════════════════════════════════
# DESENLACE PRIMARIO "OR PARA VENTILACIÓN MECÁNICA INVASIVA"
# ═══════════════════════════════════════════════════════════════

# --- Tabla 2×2 ---
tabla_vm_def <- table(final$terapia_f, 
                      factor(final$vent_mecanica, levels = c(1, 0),
                             labels = c("Sí VMI", "No VMI")))
cat("Tabla 2×2 - Muestra completa:\n\n")
## Tabla 2×2 - Muestra completa:
print(tabla_vm_def)
##       
##        Sí VMI No VMI
##   TCO      51     50
##   CNAF     34     67
# --- Proporciones ---
prop_def <- final %>%
  group_by(terapia_f) %>%
  summarise(Total = n(),
            VMI = sum(vent_mecanica == 1, na.rm = TRUE),
            Prop = round(VMI / Total * 100, 1),
            .groups = "drop")

kable(prop_def,
      col.names = c("Grupo", "Total", "Con VMI", "Proporción (%)"),
      align = "lccc",
      caption = "Ventilación mecánica invasiva - Análisis definitivo (n = 202)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE, font_size = 13) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  row_spec(1, background = "#D1C4E9") %>%
  row_spec(2, background = "#B9F6CA")
Ventilación mecánica invasiva - Análisis definitivo (n = 202)
Grupo Total Con VMI Proporción (%)
TCO 101 51 50.5
CNAF 101 34 33.7
# --- OR, RR, pruebas ---
tabla_epi_def <- table(factor(final$terapia, levels = c(0, 1)),
                       factor(final$vent_mecanica, levels = c(0, 1)))

or_def   <- oddsratio(tabla_epi_def, method = "wald")
rr_def   <- riskratio(tabla_epi_def, method = "wald")
fisher_def <- fisher.test(tabla_vm_def)

p_tco_d  <- prop_def$VMI[prop_def$terapia_f == "TCO"] / prop_def$Total[prop_def$terapia_f == "TCO"]
p_cnaf_d <- prop_def$VMI[prop_def$terapia_f == "CNAF"] / prop_def$Total[prop_def$terapia_f == "CNAF"]
RAR_d    <- p_tco_d - p_cnaf_d
NNT_d    <- ceiling(1 / RAR_d)

cat("\n=== RESULTADOS DEL ANÁLISIS DEFINITIVO ===\n\n")
## 
## === RESULTADOS DEL ANÁLISIS DEFINITIVO ===
cat("Riesgo en TCO:", round(p_tco_d * 100, 1), "%\n")
## Riesgo en TCO: 50.5 %
cat("Riesgo en CNAF:", round(p_cnaf_d * 100, 1), "%\n")
## Riesgo en CNAF: 33.7 %
cat("RR:", round(rr_def$measure[2, 1], 3),
    "  IC 95%:", round(rr_def$measure[2, 2], 3), "-",
    round(rr_def$measure[2, 3], 3), "\n")
## RR: 0.667   IC 95%: 0.477 - 0.932
cat("OR:", round(or_def$measure[2, 1], 3),
    "  IC 95%:", round(or_def$measure[2, 2], 3), "-",
    round(or_def$measure[2, 3], 3), "\n")
## OR: 0.498   IC 95%: 0.282 - 0.878
cat("RAR:", round(RAR_d * 100, 1), "puntos porcentuales\n")
## RAR: 16.8 puntos porcentuales
cat("NNT:", NNT_d, "\n")
## NNT: 6
cat("p (Fisher):", round(fisher_def$p.value, 4), "\n")
## p (Fisher): 0.0223
cat("p (Chi-cuadrado):", round(chisq.test(tabla_vm_def, correct = FALSE)$p.value, 4), "\n")
## p (Chi-cuadrado): 0.0154

3.4 Interpretación del análisis definitivo — Desenlace primario

Con la muestra completa de 202 pacientes, los resultados confirman y fortalecen la señal que había observado en el análisis interino, por lo cual, me detengo en cada hallazgo para comprenderlo en profundidad.

3.5 La tabla de contingencia, lo que cuentan los números

De los 101 pacientes asignados a Terapia Convencional de Oxígeno, 51 terminaron requiriendo intubación endotraqueal y conexión a un ventilador mecánico, lo que representa el 50.5%.

Es decir, con la muestra completa se confirma lo que el análisis interino sugería, que aproximadamente 1 de cada 2 pacientes que recibieron oxígeno convencional mediante dispositivos de bajo flujo necesitaron ser intubados, y los otros 50 lograron superar la crisis sin ventilación mecánica invasiva.

En el grupo de Cánula Nasal de Alto Flujo, también con 101 pacientes, 34 fueron intubados (33.7%) y 67 no lo requirieron, por lo que esto significa que aproximadamente **1 de cada 3 pacientes con la terapia de alto flujo necesitó intubación, frente a 1 de cada 2 con terapia convencional.

La diferencia es clínicamente significativa, pues 67 pacientes que recibieron oxígeno calentado, humidificado y a alto flujo pudieron respirar por sí mismos durante toda la crisis, evitando la sedación profunda, la parálisis neuromuscular y los riesgos asociados a tener un tubo en la tráquea durante días.

3.6 Evolución del efecto “del interino al definitivo”

Me resulta muy revelador comparar cómo se comportaron las medidas al pasar de 100 a 202 pacientes, pues en el análisis interino, las proporciones eran 49.0% frente a 28.6%, con una diferencia de 20.4 puntos porcentuales.

En el análisis definitivo, las proporciones son 50.5% frente a 33.7%, con una diferencia de 16.8 puntos porcentuales, donde observo que la diferencia se redujo ligeramente al agregar más pacientes, lo cual es un comportamiento esperado, pues los análisis interinos tienden a capturar estimaciones algo más extremas que las definitivas, precisamente porque las muestras pequeñas son más susceptibles a fluctuaciones aleatorias.

A pesar de esta atenuación, considero que el efecto se mantiene clínicamente relevante y estadísticamente significativo.

3.7 Riesgo Relativo de 0.667 (Intervalo de Confianza del 95%: 0.477 – 0.932)

Este valor se obtiene dividiendo la proporción de intubación en el grupo de cánula de alto flujo (0.337) entre la proporción en el grupo de terapia convencional (0.505): el resultado es 0.667.

Esto significa que los pacientes tratados con oxígeno a alto flujo tuvieron un riesgo de ser intubados que equivale al 66.7% del riesgo de los que recibieron terapia convencional; dicho de otra forma, la cánula de alto flujo redujo el riesgo de intubación en un 33.3%.

Comparo esto con el interino, donde la reducción era del 41.7%, por lo cual el efecto se atenuó pero sigue siendo sustancial.

El Intervalo de Confianza va de 0.477 a 0.932, donde a diferencia del análisis interino, donde el límite superior rozaba peligrosamente el 1.0 (era 0.984), ahora el límite superior es 0.932, lo cual se aleja con mayor claridad del valor nulo.

Esto refleja que la mayor cantidad de pacientes produjo una estimación más precisa, y en el escenario más conservador, la reducción del riesgo sería de al menos el 6.8%; en el más optimista, de hasta el 52.3%.

3.8 Razón de Momios (Odds Ratio) 0.498 y un (Intervalo de Confianza del 95%: 0.282 – 0.878)

La Razón de Momios se calcula a partir de los momios de cada grupo, por ejemplo en el grupo de Terapia Convencional de Oxígeno, los momios de intubación son 51 dividido entre 50 (los intubados entre los no intubados), lo que da 1.02; prácticamente los momios son de 1 a 1, es decir, era igualmente probable ser intubado que no serlo.

En el grupo de Cánula Nasal de Alto Flujo, los momios son 34 dividido entre 67, es decir 0.507; aquí los momios están a favor de no ser intubado, con una proporción de aproximadamente 1 a 2.

La Razón de Momios resulta de dividir 0.507 entre 1.02, lo que da 0.498.

Este valor de 0.498 tiene una interpretación precisa, pues los momios de requerir ventilación mecánica invasiva en el grupo de cánula de alto flujo son aproximadamente la mitad de los momios del grupo convencional, lo que representa una reducción del 50.2% en los momios de intubación.

El Intervalo de Confianza (0.282 a 0.878) no incluye el 1.0 y ambos límites están por debajo de este valor nulo, lo que confirma la significancia estadística con mayor solidez que en el análisis interino.

Comparo con el artículo publicado, donde los autores reportaron una Razón de Riesgo (Hazard Ratio) de 0.62 mediante un modelo de riesgos proporcionales de Cox.

La diferencia con la Razón de Momios calculada de 0.498 se explica porque son medidas distintas, pues la Razón de Riesgo del modelo de Cox incorpora el tiempo hasta el evento y está ajustada por severidad de la hipoxemia, edad y comorbilidades, mientras que la Razón de Momios es cruda la que he calculado (sin ajustar) y no considera la dimensión temporal, pero ambas apuntan en la misma dirección, pues la cánula de alto flujo reduce significativamente la probabilidad de intubación.

3.9 Reducción Absoluta del Riesgo, de 16.8 puntos porcentuales y Número Necesario a Tratar de 6

La diferencia absoluta entre las proporciones pasó de 20.4 puntos en el interino a 16.8 puntos en el definitivo.

Consecuentemente, el Número Necesario a Tratar se modificó de 5 a 6, lo cual significa que, con los datos completos, necesito tratar 6 pacientes con cánula nasal de alto flujo en lugar de terapia convencional para evitar 1 intubación que de otra forma hubiera ocurrido.

Considero que un Número Necesario a Tratar de 6 sigue siendo excelente en el contexto de medicina crítica, pues en un hospital con 60 pacientes con COVID-19 severo, esto representaría aproximadamente 10 intubaciones evitadas, con todo lo que eso implica en términos de recursos liberados, riesgos evitados y sufrimiento reducido.

3.10 Significancia estadística

El valor p de la prueba exacta de Fisher es 0.0223, y el de la prueba de Chi-cuadrado de Pearson es 0.0154, donde ambos valores se encuentran por debajo del umbral convencional de 0.05, lo que me permite rechazar la hipótesis nula y concluir que la diferencia observada en la proporción de ventilación mecánica invasiva entre los dos grupos es estadísticamente significativa.

A diferencia del análisis interino, donde el valor p de Fisher era 0.0422 (apenas por debajo de 0.05), ahora los valores p son más pequeños, lo que refleja la mayor potencia estadística conferida por la muestra completa.

En definitiva, el análisis definitivo confirma con mayor precisión y robustez lo que el análisis interino sugería, que la Cánula Nasal de Alto Flujo reduce significativamente la necesidad de ventilación mecánica invasiva en pacientes con COVID-19 severo.

Ahora procedo al análisis de subgrupos para explorar si este beneficio es homogéneo o si varía según las características de los pacientes.

4 Análisis de subgrupos

El análisis de subgrupos es una herramienta exploratoria que me permite evaluar si el efecto de una intervención varía según características específicas de los pacientes.

El taller solicita desarrollar al menos uno de los tres subgrupos propuestos, sin embargo, poraprendizaje desarrollaré los tres para compararlos y construir el gráfico de bosque (forest plot) completo, tal como aparece en la Figura 3 del artículo original.

4.1 ¿Qué es una prueba de interacción y por qué la necesito?

Cuando observo que la Razón de Momios es diferente entre dos subgrupos (por ejemplo, menor en pacientes jóvenes que en mayores), necesito determinar si esa diferencia entre las Razones de Momios es real o se debe al azar.

Para eso utilizo una prueba de interacción, que consiste en incluir un término multiplicativo (terapia × variable de subgrupo) en un modelo de regresión logística, y si el coeficiente de este término es estadísticamente significativo, concluyo que el efecto de la terapia realmente difiere entre los subgrupos; si no lo es, la diferencia observada es compatible con el azar.

# ═══════════════════════════════════════════════════════════════
# SUBGRUPO 1 de EDAD (< 60 años vs. ≥ 60 años)
# ═══════════════════════════════════════════════════════════════

cat("============================================\n")
## ============================================
cat("  SUBGRUPO de Pacientes MENORES de 60 años\n")
##   SUBGRUPO de Pacientes MENORES de 60 años
cat("============================================\n\n")
## ============================================
sub_joven <- final %>% filter(edad60 == 0)
cat("n =", nrow(sub_joven), "\n")
## n = 99
t_joven <- table(factor(sub_joven$terapia, levels = c(0, 1)),
                 factor(sub_joven$vent_mecanica, levels = c(0, 1)))
or_joven <- oddsratio(t_joven, method = "wald")

cat("VMI en TCO:", sum(sub_joven$vent_mecanica[sub_joven$terapia == 0] == 1),
    "/", sum(sub_joven$terapia == 0),
    "(", round(mean(sub_joven$vent_mecanica[sub_joven$terapia == 0]) * 100, 1), "%)\n")
## VMI en TCO: 27 / 52 ( 51.9 %)
cat("VMI en CNAF:", sum(sub_joven$vent_mecanica[sub_joven$terapia == 1] == 1),
    "/", sum(sub_joven$terapia == 1),
    "(", round(mean(sub_joven$vent_mecanica[sub_joven$terapia == 1]) * 100, 1), "%)\n")
## VMI en CNAF: 11 / 47 ( 23.4 %)
cat("OR:", round(or_joven$measure[2, 1], 3),
    "  IC 95%:", round(or_joven$measure[2, 2], 3), "-",
    round(or_joven$measure[2, 3], 3), "\n")
## OR: 0.283   IC 95%: 0.119 - 0.673
cat("\n============================================\n")
## 
## ============================================
cat("  SUBGRUPO de Pacientes de 60 años o MÁS\n")
##   SUBGRUPO de Pacientes de 60 años o MÁS
cat("============================================\n\n")
## ============================================
sub_mayor <- final %>% filter(edad60 == 1)
cat("n =", nrow(sub_mayor), "\n")
## n = 103
t_mayor <- table(factor(sub_mayor$terapia, levels = c(0, 1)),
                 factor(sub_mayor$vent_mecanica, levels = c(0, 1)))
or_mayor <- oddsratio(t_mayor, method = "wald")

cat("VMI en TCO:", sum(sub_mayor$vent_mecanica[sub_mayor$terapia == 0] == 1),
    "/", sum(sub_mayor$terapia == 0),
    "(", round(mean(sub_mayor$vent_mecanica[sub_mayor$terapia == 0]) * 100, 1), "%)\n")
## VMI en TCO: 24 / 49 ( 49 %)
cat("VMI en CNAF:", sum(sub_mayor$vent_mecanica[sub_mayor$terapia == 1] == 1),
    "/", sum(sub_mayor$terapia == 1),
    "(", round(mean(sub_mayor$vent_mecanica[sub_mayor$terapia == 1]) * 100, 1), "%)\n")
## VMI en CNAF: 23 / 54 ( 42.6 %)
cat("OR:", round(or_mayor$measure[2, 1], 3),
    "  IC 95%:", round(or_mayor$measure[2, 2], 3), "-",
    round(or_mayor$measure[2, 3], 3), "\n")
## OR: 0.773   IC 95%: 0.355 - 1.682
# --- Prueba de interacción ---
modelo_int_edad <- glm(vent_mecanica ~ terapia * edad60,
                       data = final, family = binomial)

cat("\n============================================\n")
## 
## ============================================
cat("  PRUEBA DE INTERACCIÓN: Terapia × Edad\n")
##   PRUEBA DE INTERACCIÓN: Terapia × Edad
cat("============================================\n")
## ============================================
cat("p de interacción:",
    round(summary(modelo_int_edad)$coefficients["terapia:edad60", 4], 4), "\n")
## p de interacción: 0.0908

4.2 Análisis del subgrupo por edad, los menores de 60 años frente a 60 años o más

Este primer subgrupo me permite explorar una pregunta clínicamente relevante:

¿el beneficio de la cánula nasal de alto flujo es igual en pacientes más jóvenes que en pacientes mayores? Los resultados revelan un contraste llamativo:

4.3 Pacientes menores de 60 años (99 pacientes)

En este grupo de pacientes más jóvenes, 27 de los 52 asignados a terapia convencional de oxígeno fueron intubados (51.9%), mientras que solo 11 de los 47 asignados a cánula de alto flujo necesitaron intubación (23.4%).

La diferencia es de 28.5 puntos porcentuales, notablemente mayor que la diferencia global de 16.8 puntos que observé en la muestra completa.

La Razón de Momios de 0.283 indica que los momios o chances de requerir ventilación mecánica invasiva en los pacientes jóvenes tratados con cánula de alto flujo fueron apenas el 28.3% de los momios del grupo convencional; expresado de otro modo, la reducción en los momios de intubación alcanza un impresionante 71.7%.

El Intervalo de Confianza (0.119 a 0.673) no incluye el valor nulo de 1.0, lo que confirma que este efecto es estadísticamente significativo dentro de este subgrupo.

Desde la perspectiva fisiopatológica, este hallazgo tiene sentido, pues los pacientes menores de 60 años generalmente poseen mayor reserva cardiopulmonar, pues su tejido pulmonar mantiene mejor elasticidad, sus músculos respiratorios tienen mayor capacidad para sostener un trabajo ventilatorio elevado durante períodos prolongados, y su capacidad de reclutamiento alveolar en respuesta a la presión positiva generada por la cánula de alto flujo es probablemente superior.

En otras palabras, el pulmón más joven tiene mayor capacidad de “responder” al soporte que ofrece el alto flujo, permitiendo que muchos de estos pacientes superen la fase crítica de la neumonitis por COVID-19 sin necesidad de intubación.

4.4 Pacientes de 60 años o más (103 pacientes)

El panorama en los pacientes mayores es sustancialmente diferente, pues de los 49 asignados a terapia convencional, 24 fueron intubados (49.0%), y de los 54 asignados a cánula de alto flujo, 23 requirieron intubación (42.6%).

La diferencia es de apenas 6.4 puntos porcentuales, considerablemente menor que los 28.5 puntos observados en los pacientes jóvenes.

La Razón de Momios de 0.773 indica una reducción de solo el 22.7% en los momios de intubación, y su Intervalo de Confianza (0.355 a 1.682) cruza ampliamente el valor nulo de 1.0, lo que significa que este resultado no es estadísticamente significativo, por lo que en este subgrupo, no puedo afirmar que la cánula de alto flujo reduzca la necesidad de intubación.

La explicación clínica resulta igualmente coherente, pues los pacientes de 60 años o más llegan a la crisis respiratoria con desventajas fisiológicas acumuladas, como menor compliance pulmonar (el pulmón es más rígido y responde peor al reclutamiento alveolar), mayor prevalencia de comorbilidades como hipertensión, diabetes y enfermedad pulmonar obstructiva crónica que comprometen adicionalmente el intercambio gaseoso, sarcopenia de los músculos respiratorios que limita la capacidad de sostener el esfuerzo ventilatorio, y un sistema inmune envejecido (inmunosenescencia) que puede generar una respuesta inflamatoria más desregulada.

A partir de lo anterior, me resulta razonable suponer que en estos pacientes el daño pulmonar al momento de la presentación ya sea tan extenso que el soporte no invasivo (incluso con las ventajas fisiológicas de la cánula de alto flujo) resulte insuficiente con mayor frecuencia.

4.5 La prueba de interacción con p = 0.0908

Ahora bien, la pregunta crítica que me hago, no es si las Razones de Momios son diferentes entre subgrupos (a simple vista lo son: 0.283 frente a 0.773), sino si esa diferencia es estadísticamente significativa.

La prueba de interacción arroja un valor p de 0.0908, que se encuentra por encima del umbral convencional de 0.05, lo cual significa que, formalmente, no puedo concluir que el efecto de la terapia sea significativamente diferente entre pacientes jóvenes y mayores.

Sin embargo, considero que este valor p merece una lectura más matizada que un simple “significativo o no significativo”, pues un valor de 0.0908 se ubica en lo que la literatura llama una “zona gris”, donde no alcanza el umbral convencional, pero tampoco está tan lejos como para descartarlo por completo.

Es interesante compararlo con el artículo original, donde los autores reportaron un valor p de interacción de 0.04 para el análisis de subgrupo por edad utilizando un modelo de riesgos proporcionales de Cox con la Razón de Riesgo (Hazard Ratio).

La diferencia entre el valor que obtuve de 0.0908 y el reportado por los autores de 0.04 se explica porque estoy usando medidas diferentes (Razón de Momios frente a Razón de Riesgo), modelos diferentes (regresión logística sin ajustar frente a modelo de Cox ajustado por severidad, edad y comorbilidades), y una muestra ligeramente distinta (202 frente a 199 pacientes).

En definitiva, el subgrupo de edad sugiere (sin confirmar definitivamente) que los pacientes más jóvenes podrían beneficiarse más de la cánula de alto flujo que los pacientes mayores.

Esta hipótesis tiene plausibilidad biológica, es consistente con lo reportado en el artículo original, y me genera una pregunta que podría abordarse en estudios futuros diseñados específicamente para evaluarla.

# ═══════════════════════════════════════════════════════════════
# SUBGRUPO 2 de PaO2/FiO2 (< 150 vs. ≥ 150)
# ═══════════════════════════════════════════════════════════════

cat("============================================\n")
## ============================================
cat("  SUBGRUPO de PaO2/FiO2 < 150 (más severo)\n")
##   SUBGRUPO de PaO2/FiO2 < 150 (más severo)
cat("============================================\n\n")
## ============================================
sub_severo <- final %>% filter(pafi150 == 1)
cat("n =", nrow(sub_severo), "\n")
## n = 167
t_severo <- table(factor(sub_severo$terapia, levels = c(0, 1)),
                  factor(sub_severo$vent_mecanica, levels = c(0, 1)))
or_severo <- oddsratio(t_severo, method = "wald")

cat("VMI en TCO:", sum(sub_severo$vent_mecanica[sub_severo$terapia == 0] == 1),
    "/", sum(sub_severo$terapia == 0),
    "(", round(mean(sub_severo$vent_mecanica[sub_severo$terapia == 0]) * 100, 1), "%)\n")
## VMI en TCO: 42 / 81 ( 51.9 %)
cat("VMI en CNAF:", sum(sub_severo$vent_mecanica[sub_severo$terapia == 1] == 1),
    "/", sum(sub_severo$terapia == 1),
    "(", round(mean(sub_severo$vent_mecanica[sub_severo$terapia == 1]) * 100, 1), "%)\n")
## VMI en CNAF: 31 / 86 ( 36 %)
cat("OR:", round(or_severo$measure[2, 1], 3),
    "  IC 95%:", round(or_severo$measure[2, 2], 3), "-",
    round(or_severo$measure[2, 3], 3), "\n")
## OR: 0.523   IC 95%: 0.282 - 0.972
cat("\n============================================\n")
## 
## ============================================
cat("  SUBGRUPO de PaO2/FiO2 >= 150 (menos severo)\n")
##   SUBGRUPO de PaO2/FiO2 >= 150 (menos severo)
cat("============================================\n\n")
## ============================================
sub_leve <- final %>% filter(pafi150 == 0)
cat("n =", nrow(sub_leve), "\n")
## n = 35
t_leve <- table(factor(sub_leve$terapia, levels = c(0, 1)),
                factor(sub_leve$vent_mecanica, levels = c(0, 1)))
or_leve <- oddsratio(t_leve, method = "wald")

cat("VMI en TCO:", sum(sub_leve$vent_mecanica[sub_leve$terapia == 0] == 1),
    "/", sum(sub_leve$terapia == 0),
    "(", round(mean(sub_leve$vent_mecanica[sub_leve$terapia == 0]) * 100, 1), "%)\n")
## VMI en TCO: 9 / 20 ( 45 %)
cat("VMI en CNAF:", sum(sub_leve$vent_mecanica[sub_leve$terapia == 1] == 1),
    "/", sum(sub_leve$terapia == 1),
    "(", round(mean(sub_leve$vent_mecanica[sub_leve$terapia == 1]) * 100, 1), "%)\n")
## VMI en CNAF: 3 / 15 ( 20 %)
cat("OR:", round(or_leve$measure[2, 1], 3),
    "  IC 95%:", round(or_leve$measure[2, 2], 3), "-",
    round(or_leve$measure[2, 3], 3), "\n")
## OR: 0.306   IC 95%: 0.065 - 1.428
# --- Prueba de interacción ---
modelo_int_pafi <- glm(vent_mecanica ~ terapia * pafi150,
                       data = final, family = binomial)

cat("\n============================================\n")
## 
## ============================================
cat("  PRUEBA DE INTERACCIÓN: Terapia × PaO2/FiO2\n")
##   PRUEBA DE INTERACCIÓN: Terapia × PaO2/FiO2
cat("============================================\n")
## ============================================
cat("p de interacción:",
    round(summary(modelo_int_pafi)$coefficients["terapia:pafi150", 4], 4), "\n")
## p de interacción: 0.5255

4.6 Análisis del subgrupo por severidad de la hipoxemia, sobre la relación entre presión parcial de oxígeno arterial y fracción inspirada de oxígeno

Este segundo subgrupo evalúa si el beneficio de la cánula de alto flujo varía según qué tan severa era la hipoxemia del paciente al momento de ingresar al estudio.

El punto de corte de 150 divide a los pacientes en aquellos con compromiso más grave del intercambio gaseoso (por debajo de 150) frente a aquellos con compromiso menos severo (150 o más).

4.7 Pacientes con hipoxemia más severa, sobre la relación inferior a 150 (167 pacientes)

Este es, por mucho, el subgrupo más grande, lo cual refleja que la inmensa mayoría de los pacientes reclutados en el ensayo tenían un compromiso pulmonar grave, pues de los 81 pacientes con terapia convencional, 42 requirieron intubación (51.9%).

Ahora de los 86 con cánula de alto flujo, 31 fueron intubados (36.0%). La Razón de Momios de 0.523 indica que los momios de intubación se redujeron en un 47.7% con la cánula de alto flujo, y el Intervalo de Confianza (0.282 a 0.972) no incluye el valor nulo de 1.0, confirmando significancia estadística dentro de este subgrupo.

Desde el punto de vista clínico, este hallazgo es particularmente alentador,pues los pacientes con una relación inferior a 150 se encuentran en el terreno del síndrome de dificultad respiratoria aguda moderado a severo según la clasificación de Berlín, lo cual implica que una proporción considerable de sus alvéolos están inundados de líquido inflamatorio, colapsados o con membranas hialinas que impiden el intercambio gaseoso.

Pero,a pesar de esta gravedad, la cánula de alto flujo logró evitar la intubación en un número significativo de pacientes. Esto sugiere que los mecanismos fisiológicos de la cánula (la presión positiva que recluta alvéolos colapsados, la reducción del trabajo respiratorio y el lavado del espacio muerto) operan incluso en pulmones con daño extenso, siempre que el paciente conserve suficiente capacidad de esfuerzo ventilatorio espontáneo.

4.8 Pacientes con hipoxemia menos severa, consistente en la relación de 150 o más (35 pacientes)

Este subgrupo es considerablemente más pequeño, con solo 35 pacientes, donde de los 20 asignados a terapia convencional, 9 fueron intubados (45.0%); de los 15 con cánula de alto flujo, solo 3 necesitaron intubación (20.0%).

La Razón de Momios de 0.306 sugiere una reducción del 69.4% en los momios de intubación, lo cual a primera vista parece un efecto aún mayor que en el subgrupo más severo, pero el Intervalo de Confianza (0.065 a 1.428) cruza el valor nulo de 1.0, por lo que este resultado no alcanza significancia estadística.

La ausencia de significancia no se debe necesariamente a que no exista efecto, sino a que el tamaño del subgrupo es demasiado pequeño, pues con solo 35 pacientes y 12 eventos de intubación, la potencia estadística es insuficiente para detectar diferencias con confianza.

La amplitud del intervalo lo confirma, pues el efecto verdadero podría ir desde una reducción del 93.5% en los momios (límite inferior de 0.065, enormemente beneficioso) hasta un aumento del 42.8% (límite superior de 1.428, perjudicial), lo cual,esta incertidumbre extrema es consecuencia directa del escaso número de pacientes, no necesariamente de la ausencia de efecto.

4.9 La prueba de interacción con p = 0.5255

El valor p de interacción de 0.5255 está muy lejos del umbral de 0.05, lo que indica que no existe evidencia estadística de que el efecto de la cánula de alto flujo difiera según la severidad de la hipoxemia.

En otras palabras, las Razones de Momios de 0.523 y 0.306 no son estadísticamente diferentes entre sí; la variación observada es compatible con el azar.

Esto es, en realidad, un hallazgo tranquilizador, pues significa que el beneficio de la cánula de alto flujo parece ser relativamente homogéneo independientemente de qué tan comprometido estuviera el pulmón al momento del ingreso.

No hay evidencia de que los pacientes más graves se beneficien menos, ni de que los menos graves se beneficien más, y dado que este resultado coincide con lo reportado por los autores en el artículo original, donde el valor p de interacción para este subgrupo fue de 0.97 (utilizando el modelo de Cox ajustado), confirma entonces la ausencia de modificación de efecto por la severidad de la hipoxemia.

A diferencia del subgrupo de edad, donde la prueba de interacción se acercaba a la significancia (p = 0.0908) y las Razones de Momios mostraban un contraste marcado (0.283 frente a 0.773, aquí ambas Razones de Momios apuntan en la misma dirección y con magnitudes más comparables (0.523 y 0.306).

Consecuentemente, la severidad de la hipoxemia no parece ser un modificador de efecto clínicamente relevante para la decisión de usar cánula nasal de alto flujo.

# ═══════════════════════════════════════════════════════════════
# SUBGRUPO 3 de INTERLEUCINA 6 (< 100 vs. ≥ 100 pg/mL)
# ═══════════════════════════════════════════════════════════════

final_il6 <- final %>% filter(!is.na(il6_100))
cat("Pacientes con datos de IL-6:", nrow(final_il6),
    "(excluidos", nrow(final) - nrow(final_il6), "por datos faltantes)\n\n")
## Pacientes con datos de IL-6: 181 (excluidos 21 por datos faltantes)
cat("============================================\n")
## ============================================
cat("  SUBGRUPO de IL-6 < 100 pg/mL (menor inflamación)\n")
##   SUBGRUPO de IL-6 < 100 pg/mL (menor inflamación)
cat("============================================\n\n")
## ============================================
sub_il6_bajo <- final_il6 %>% filter(il6_100 == 0)
cat("n =", nrow(sub_il6_bajo), "\n")
## n = 164
t_il6_bajo <- table(factor(sub_il6_bajo$terapia, levels = c(0, 1)),
                    factor(sub_il6_bajo$vent_mecanica, levels = c(0, 1)))
or_il6_bajo <- oddsratio(t_il6_bajo, method = "wald")

cat("VMI en TCO:", sum(sub_il6_bajo$vent_mecanica[sub_il6_bajo$terapia == 0] == 1),
    "/", sum(sub_il6_bajo$terapia == 0),
    "(", round(mean(sub_il6_bajo$vent_mecanica[sub_il6_bajo$terapia == 0]) * 100, 1), "%)\n")
## VMI en TCO: 44 / 86 ( 51.2 %)
cat("VMI en CNAF:", sum(sub_il6_bajo$vent_mecanica[sub_il6_bajo$terapia == 1] == 1),
    "/", sum(sub_il6_bajo$terapia == 1),
    "(", round(mean(sub_il6_bajo$vent_mecanica[sub_il6_bajo$terapia == 1]) * 100, 1), "%)\n")
## VMI en CNAF: 21 / 78 ( 26.9 %)
cat("OR:", round(or_il6_bajo$measure[2, 1], 3),
    "  IC 95%:", round(or_il6_bajo$measure[2, 2], 3), "-",
    round(or_il6_bajo$measure[2, 3], 3), "\n")
## OR: 0.352   IC 95%: 0.183 - 0.677
cat("\n============================================\n")
## 
## ============================================
cat("  SUBGRUPO de IL-6 >= 100 pg/mL (mayor inflamación)\n")
##   SUBGRUPO de IL-6 >= 100 pg/mL (mayor inflamación)
cat("============================================\n\n")
## ============================================
sub_il6_alto <- final_il6 %>% filter(il6_100 == 1)
cat("n =", nrow(sub_il6_alto), "\n")
## n = 17
t_il6_alto <- table(factor(sub_il6_alto$terapia, levels = c(0, 1)),
                    factor(sub_il6_alto$vent_mecanica, levels = c(0, 1)))
or_il6_alto <- oddsratio(t_il6_alto, method = "wald")

cat("VMI en TCO:", sum(sub_il6_alto$vent_mecanica[sub_il6_alto$terapia == 0] == 1),
    "/", sum(sub_il6_alto$terapia == 0),
    "(", round(mean(sub_il6_alto$vent_mecanica[sub_il6_alto$terapia == 0]) * 100, 1), "%)\n")
## VMI en TCO: 5 / 7 ( 71.4 %)
cat("VMI en CNAF:", sum(sub_il6_alto$vent_mecanica[sub_il6_alto$terapia == 1] == 1),
    "/", sum(sub_il6_alto$terapia == 1),
    "(", round(mean(sub_il6_alto$vent_mecanica[sub_il6_alto$terapia == 1]) * 100, 1), "%)\n")
## VMI en CNAF: 8 / 10 ( 80 %)
cat("OR:", round(or_il6_alto$measure[2, 1], 3),
    "  IC 95%:", round(or_il6_alto$measure[2, 2], 3), "-",
    round(or_il6_alto$measure[2, 3], 3), "\n")
## OR: 1.6   IC 95%: 0.168 - 15.273
# --- Prueba de interacción ---
modelo_int_il6 <- glm(vent_mecanica ~ terapia * il6_100,
                      data = final_il6, family = binomial)

cat("\n============================================\n")
## 
## ============================================
cat("  PRUEBA DE INTERACCIÓN de Terapia × IL-6\n")
##   PRUEBA DE INTERACCIÓN de Terapia × IL-6
cat("============================================\n")
## ============================================
cat("p de interacción:",
    round(summary(modelo_int_il6)$coefficients["terapia:il6_100", 4], 4), "\n")
## p de interacción: 0.2062

4.10 Análisis del subgrupo por Interleucina 6, con menor inflamación frente a mayor inflamación sistémica.

Este tercer subgrupo es, desde mi perspectiva, el más revelador a nivel fisiopatológico, porque aborda directamente una pregunta central en el manejo del COVID-19 severo:

¿importa el grado de inflamación sistémica a la hora de decidir el soporte ventilatorio? Los resultados muestran un fenómeno que me llama profundamente la atención, pues el efecto de la cánula de alto flujo se invierte según el nivel de Interleucina 6.

Antes de interpretar, debo señalar que 21 pacientes (de los 202 totales) no tenían datos disponibles de Interleucina 6, por lo cual este análisis que realizo, se basa en 181 pacientes, dado que la pérdida del 10.4% de la muestra introduce una limitación que debo tener presente.

4.11 Pacientes con Interleucina 6 inferior a 100 pg/mL, con menor inflamación (164 pacientes)

En los pacientes con respuesta inflamatoria más contenida, el efecto de la cánula de alto flujo es contundente, pues de los 86 asignados a terapia convencional de oxígeno, 44 fueron intubados (51.2%); de los 78 asignados a cánula de alto flujo, solo 21 requirieron intubación (26.9%).

La Razón de Momios de 0.352 indica que los momios de intubación se redujeron en un 64.8% con la cánula de alto flujo, y el Intervalo de Confianza (0.183 a 0.677) se aleja claramente del valor nulo de 1.0, confirmando una significancia estadística robusta, por lo cual, esta es, de hecho, la Razón de Momios más favorable de todos los subgrupos que he analizado.

Clínicamente, este resultado tiene una explicación coherente, pues los pacientes con niveles bajos de Interleucina 6 se encuentran probablemente en una fase de la enfermedad donde el daño pulmonar, aunque severo, aún no ha desencadenado la cascada inflamatoria descontrolada que destruye irreversiblemente el tejido alveolar.

En estos pacientes, el pulmón conserva suficiente tejido funcional como para responder a los mecanismos fisiológicos de la cánula de alto flujo,donde la presión positiva recluta alvéolos que están colapsados pero no destruidos, el gas calentado y humidificado protege la mucosa bronquial, y la reducción del esfuerzo respiratorio previene el daño pulmonar autoinfligido por el paciente.

En resumen, la cánula de alto flujo funciona mejor cuando todavía hay pulmón que rescatar.

4.12 Pacientes con Interleucina 6 de 100 pg/mL o más, con mayor inflamación (17 pacientes)

Aquí es donde la historia cambia radicalmente, pues este subgrupo es muy pequeño (apenas 17 pacientes: 7 con terapia convencional y 10 con cánula de alto flujo), pero lo que observo es inquietante, pues de los 7 pacientes con terapia convencional, 5 fueron intubados (71.4%); de los 10 con cánula de alto flujo, 8 fueron intubados (80.0%).

La Razón de Momios es de 1.6, lo que significa que los momios de intubación fueron un 60% mayores en el grupo de cánula de alto flujo que en el grupo convencional.

La dirección del efecto se invirtió por completo, pues mientras que en los pacientes con menor inflamación la cánula de alto flujo protegía (Razón de Momios de 0.352), en los pacientes con mayor inflamación parece no solo no proteger, sino asociarse con peores resultados.

No obstante, debo ser extremadamente cautelosa al interpretar este hallazgo, pues el Intervalo de Confianza es absurdamente amplio, de 0.168 a 15.273.

Un intervalo así, que abarca desde una reducción del 83.2% en los momios hasta un aumento de más de 15 veces refleja una incertidumbre total, consecuencia directa de tener solo 17 pacientes con 13 eventos.

Con números tan pequeños, la diferencia de 1 o 2 pacientes intubados más o menos en cualquier grupo cambiaría dramáticamente la Razón de Momios, por lo cual con este resultado, no me permite ninguna conclusión firme sobre el efecto de la terapia en pacientes con inflamación severa.

A pesar de ello, la hipótesis fisiopatológica que plantea es interesante, porque los pacientes con Interleucina 6 superior a 100 pg/mL se encuentran en plena “tormenta de citocinas”, es decir, con una respuesta inflamatoria descontrolada donde los macrófagos alveolares liberan cantidades masivas de mediadores inflamatorios que reclutan neutrófilos, activan la coagulación intravascular y producen daño endotelial difuso con formación de membranas hialinas.

En este escenario, el daño pulmonar es tan extenso y tan agresivo que ningún soporte ventilatorio no invasivo puede revertirlo, por lo cual, es razonable suponer que estos pacientes necesitan intubación temprana independientemente del tipo de oxigenoterapia que reciban, y que retrasar la intubación con cánula de alto flujo podría incluso ser perjudicial al permitir que el esfuerzo respiratorio excesivo del paciente genere más daño pulmonar adicional.

4.13 La prueba de interacción con una p = 0.2062

El valor p de interacción de 0.2062 no alcanza el umbral de significancia de 0.05, lo que indica que formalmente no puedo concluir que el efecto de la terapia difiera según el nivel de Interleucina 6.

Este resultado contrasta con el artículo original, donde los autores reportaron un valor p de interacción de 0.02 (significativo). La discrepancia considero que se explica por las diferencias metodológicas, pues los autores, utilizaron un modelo de Cox ajustado por múltiples covariables y con un punto de corte de 110 pg/mL (no 100), mientras que yo utilizo una regresión logística cruda con un corte de 100 pg/mL.

En conjunto, lo que este subgrupo me enseña es que el nivel de inflamación sistémica podría ser un modificador de efecto biológicamente plausible, pues la cánula de alto flujo parece beneficiar a los pacientes con inflamación controlada pero no a aquellos con tormenta de citocinas.

Sin embargo, la evidencia estadística de esta interacción es insuficiente en esta muestra, principalmente por el escasísimo número de pacientes con Interleucina 6 elevada, asi que, confirmar o refutar esta hipótesis requeriría un estudio diseñado específicamente para estratificar por biomarcadores inflamatorios, con un tamaño muestral que garantice suficientes pacientes en el estrato de mayor inflamación.

5 forest plot y la tabla resumen de los tres subgrupos

# ═══════════════════════════════════════════════════════════════
# FOREST PLOT con Los tres subgrupos en una sola gráfica
# ═══════════════════════════════════════════════════════════════

forest_data <- data.frame(
  Subgrupo = factor(c("GLOBAL (n=202)",
                       "Edad < 60 (n=99)", "Edad >= 60 (n=103)",
                       "PaO2/FiO2 < 150 (n=167)", "PaO2/FiO2 >= 150 (n=35)",
                       "IL-6 < 100 (n=164)", "IL-6 >= 100 (n=17)"),
                    levels = rev(c("GLOBAL (n=202)",
                                   "Edad < 60 (n=99)", "Edad >= 60 (n=103)",
                                   "PaO2/FiO2 < 150 (n=167)", "PaO2/FiO2 >= 150 (n=35)",
                                   "IL-6 < 100 (n=164)", "IL-6 >= 100 (n=17)"))),
  OR     = c(0.498, 0.283, 0.773, 0.523, 0.306, 0.352, 1.600),
  IC_inf = c(0.282, 0.119, 0.355, 0.282, 0.065, 0.183, 0.168),
  IC_sup = c(0.878, 0.673, 1.682, 0.972, 1.428, 0.677, 15.273),
  Categoria = c("Global", "Edad", "Edad", "PaO2/FiO2", "PaO2/FiO2", "IL-6", "IL-6"),
  p_int = c("", "", "p = 0.091", "", "p = 0.526", "", "p = 0.206")
)

# Limito el IC superior para visualización
forest_data$IC_sup_plot <- pmin(forest_data$IC_sup, 6)

ggplot(forest_data, aes(x = OR, y = Subgrupo, color = Categoria)) +
  geom_vline(xintercept = 1, linetype = "dashed", color = "gray50", linewidth = 0.7) +
  geom_errorbarh(aes(xmin = IC_inf, xmax = IC_sup_plot),
                 height = 0.25, linewidth = 1) +
  geom_point(size = 4.5) +
  geom_text(aes(label = paste0(OR, " (", IC_inf, "-", IC_sup, ")")),
            hjust = -0.1, vjust = -0.9, size = 3.2, color = "black") +
  geom_text(aes(x = 5.5, label = p_int),
            size = 3, color = "gray30", fontface = "italic") +
  scale_color_manual(values = c("Global" = col_accent, "Edad" = col_cnaf,
                                "PaO2/FiO2" = "#27AE60", "IL-6" = "#E67E22")) +
  scale_x_continuous(trans = "log2",
                     breaks = c(0.125, 0.25, 0.5, 1, 2, 4),
                     limits = c(0.05, 7)) +
  annotate("text", x = 0.08, y = 0.4,
           label = "Favorece\nCánula Alto Flujo",
           size = 3.3, color = col_cnaf, fontface = "bold") +
  annotate("text", x = 5, y = 0.4,
           label = "Favorece\nTerapia Convencional",
           size = 3.3, color = col_tco, fontface = "bold") +
  labs(title    = "Forest Plot - Análisis de Subgrupos",
       subtitle = "Razón de Momios para ventilación mecánica invasiva (CNAF vs TCO)",
       x        = "Razón de Momios (escala logarítmica)",
       y        = NULL) +
  theme_minimal(base_size = 13) +
  theme(legend.position  = "none",
        plot.title       = element_text(face = "bold", color = col_accent, hjust = 0.5),
        plot.subtitle    = element_text(color = "gray40", hjust = 0.5),
        axis.text.y      = element_text(face = "bold", size = 11),
        panel.grid.minor = element_blank())

Antes de comparar mis resultados con los del artículo, considero importante explicar cómo se lee esta gráfica, porque cada elemento visual tiene un significado estadístico preciso.

El eje horizontal representa la Razón de Momios en escala logarítmica¨, lo cual hace que las distancias sean simétricas, pues una Razón de Momios de 0.5 queda a la misma distancia visual del valor nulo que una de 2.0.

La línea vertical punteada en 1.0 es la referencia central, pues todo lo que se ubica a su izquierda favorece a la cánula nasal de alto flujo (menor riesgo de intubación), y todo lo que cae a su derecha favorece a la terapia convencional de oxígeno.

Los colores cada uno identifica una dimensión de análisis distinta, por ejemplo, el azul oscuro corresponde al efecto globalen toda la muestra (202 pacientes), y funciona como punto de referencia contra el cual comparo los demás.

El azul claro agrupa el subgrupo de edad: la línea de menores de 60 años tiene su punto estimado muy desplazado hacia la izquierda (0.283, gran beneficio), mientras que la de 60 años o más se acerca al valor nulo (0.773, beneficio atenuado).

El verde representa la estratificación por severidad de la hipoxemia: ambas líneas verdes apuntan en la misma dirección, indicando un efecto relativamente homogéneo independientemente del compromiso pulmonar.

El naranja identifica el subgrupo de Interleucina 6, y es aquí donde la gráfica se vuelve más interesante, pues la línea de Interleucina 6 baja (0.352) se mantiene firmemente a la izquierda, pero la de Interleucina 6 elevada (1.6) cruza la línea de no efecto y se desplaza hacia la derecha, señalando una inversión del efecto.

Las barras horizontales que se extienden desde cada punto representan los Intervalos de Confianza del 95%: donde se observa una relación directa entre el tamaño del subgrupo y la amplitud de estas barras, pues los subgrupos grandes (167 y 164 pacientes) tienen intervalos estrechos que reflejan estimaciones precisas, mientras que los subgrupos pequeños (35 y especialmente 17 pacientes) tienen barras que se extienden de extremo a extremo del gráfico, reflejando una incertidumbre que impide cualquier conclusión firme.

Los valores p de interacción, anotados en gris a la derecha del gráfico (0.091, 0.526 y 0.206), indican si la diferencia entre cada par de subgrupos es estadísticamente significativa; en los tres casos la respuesta es no, lo cual significa que las variaciones observadas son compatibles con el azar.

5.1 Comparación del forest plot realizado con la Figura 3 del artículo original

Considero que poner lado a lado este gráfico de bosque con el publicado en el artículo es uno de los ejercicios más enriquecedores de este taller, porque me permite entender cómo las decisiones metodológicas influyen en los resultados, aun cuando los datos provienen del mismo ensayo clínico.

comparacion_fp <- data.frame(
  Subgrupo = c("Edad < 60",
               "Edad >= 60",
               "p de interaccion EDAD",
               "Hipoxemia mas severa",
               "Hipoxemia menos severa",
               "p de interaccion PaO2/FiO2",
               "IL-6 baja (<100)",
               "IL-6 alta (>=100)",
               "p de interaccion IL-6"),
  Mi_analisis = c("OR 0.283 (0.119-0.673)",
              "OR 0.773 (0.355-1.682)",
              "0.0908",
              "OR 0.523 (0.282-0.972) [corte: <150]",
              "OR 0.306 (0.065-1.428) [corte: >=150]",
              "0.5255",
              "OR 0.352 (0.183-0.677)",
              "OR 1.600 (0.168-15.273)",
              "0.2062"),
  Articulo = c("HR 0.35 (0.18-0.72)",
               "HR 0.89 (0.50-1.59)",
               "0.04",
               "HR 0.59 (0.33-1.08) [corte: <100]",
               "HR 0.58 (0.31-1.11) [corte: >=100]",
               "0.97",
               "HR 0.45 (0.27-0.75)",
               "HR 1.80 (0.59-5.52)",
               "0.02")
)

kable(comparacion_fp,
      col.names = c("Subgrupo", "Mi analisis", "Articulo publicado"),
      align = "lll",
      caption = "Comparacion: mi forest plot vs. Figura 3 del articulo") %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = TRUE, font_size = 11) %>%
  row_spec(0, bold = TRUE, color = "white", background = col_accent) %>%
  row_spec(c(3, 6, 9), bold = TRUE, background = "#FDEBD0") %>%
  row_spec(c(1, 7), background = "#D5F5E3")
Comparacion: mi forest plot vs. Figura 3 del articulo
Subgrupo Mi analisis Articulo publicado
Edad < 60 OR 0.283 (0.119-0.673) HR 0.35 (0.18-0.72)
Edad >= 60 OR 0.773 (0.355-1.682) HR 0.89 (0.50-1.59)
p de interaccion EDAD 0.0908 0.04
Hipoxemia mas severa OR 0.523 (0.282-0.972) [corte: <150] HR 0.59 (0.33-1.08) [corte: <100]
Hipoxemia menos severa OR 0.306 (0.065-1.428) [corte: >=150] HR 0.58 (0.31-1.11) [corte: >=100]
p de interaccion PaO2/FiO2 0.5255 0.97
IL-6 baja (<100) OR 0.352 (0.183-0.677) HR 0.45 (0.27-0.75)
IL-6 alta (>=100) OR 1.600 (0.168-15.273) HR 1.80 (0.59-5.52)
p de interaccion IL-6 0.2062 0.02

Integración de mi forest plot con la Figura 3 del artículo:

Cuando coloco mi gráfico de bosque junto a la Figura 3 del artículo de Ospina-Tascón y colaboradores, lo primero que percibo no son las diferencias entre ambos, sino la coherencia narrativa que los une.

Ambos gráficos cuentan la misma historia desde marcos analíticos distintos, y esa convergencia es, en sí misma, el hallazgo más valioso de este ejercicio que se ha propuesto.

Mi gráfico utiliza la Razón de Momios calculada mediante regresión logística sin ajustar, mientras que el del artículo emplea la Razón de Riesgo derivada de un modelo de riesgos proporcionales de Cox ajustado por severidad de la hipoxemia, edad y comorbilidades.

A pesar de esta diferencia metodológica, las conclusiones cualitativas coinciden en los tres ejes de estratificación:

Donde el beneficio de la cánula de alto flujo es más pronunciado en pacientes jóvenes y con menor inflamación sistémica, y la severidad de la hipoxemia no modifica sustancialmente el efecto.

Además, que dos abordajes estadísticos distintos, aplicados a muestras ligeramente diferentes (202 pacientes en mi base frente a 199 en el artículo), resulta que si coiniciden en el mismo patrón lo que refuerza la robustez del hallazgo.

Lo que difiere, no obstante, merece atención, pues mis valores p de interacción (0.091 para edad, 0.526 para la relación entre presión parcial de oxígeno y fracción inspirada de oxígeno, y 0.206 para Interleucina 6) son sistemáticamente más altos que los del artículo (0.04, 0.97 y 0.02, respectivamente).

Me resulta revelador que en dos de los tres subgrupos (edad e Interleucina 6) la discrepancia sea tan marcada, pues lo que en el artículo alcanzó significancia estadística, en mi análisis no la alcanzó.

Esto me obliga a reflexionar sobre el peso que tiene el ajuste por covariables en la detección de interacciones, pues l controlar por variables pronósticas como la edad, la severidad de la hipoxemia y las comorbilidades, el modelo de Cox reduce la variabilidad residual y, consecuentemente, incrementa la potencia para detectar diferencias entre subgrupos que de otro modo quedarían enmascaradas por el ruido estadístico.

Mi regresión logística cruda no dispone de ese refinamiento, y por eso las interacciones se diluyen, sin embargo, un subgrupo donde ambos análisis resultan particularmente concordantes es en su mensaje clínico:

El de la Interleucina 6: Tanto mi Razón de Momios de 1.6 como la Razón de Riesgo de 1.80 del artículo señalan una inversión del efecto en pacientes con inflamación sistémica descontrolada.

Que la terapia de alto flujo, beneficiosa globalmente, parezca no solo perder su efecto sino potencialmente asociarse con peores resultados en este subgrupo plantea una pregunta clínica que trasciende los números, pues cuando el pulmón está siendo destruido por una cascada inflamatoria masiva, sostener la respiración espontánea con soporte no invasivo podría prolongar un esfuerzo respiratorio que, lejos de proteger, agrava el daño alveolar.

En estos pacientes, la intubación temprana y la ventilación mecánica protectora podrían ser la decisión más segura, independientemente del tipo de oxigenoterapia previa.

Esta hipótesis no puede confirmarse con los datos de este ensayo, dado que el subgrupo tiene apenas 17 pacientes, pero su plausibilidad biológica y la consistencia entre ambos análisis la convierten en una pregunta posible para la investigación futura.

El subgrupo de edad, por su parte, me deja una lectura más matizada, pues mi valor p de interacción de 0.091 no cruza el umbral convencional, pero tampoco lo descarta con holgura.

Si aplicara el criterio que Pocock y colaboradores que proponen en su guía sobre interpretación de valores p, clasificaría esta evidencia como “insuficiente pero no ausente”.

El artículo, con su modelo ajustado, alcanzó un valor p de 0.04 que se ubica en la categoría de “alguna evidencia”. La diferencia entre ambos radica en una sola decisión metodológica (ajustar o no por covariables), lo cual subraya que el valor p no es una propiedad intrínseca del fenómeno observado sino un producto del modelo elegido para evaluarlo.

Como señalan Wang y colaboradores en su artículo sobre reporte de análisis de subgrupos, la credibilidad de un hallazgo de subgrupo depende no solo de la significancia estadística sino de la plausibilidad biológica, la preespecificación y la consistencia entre estudios.

En el caso de la edad, los tres criterios se cumplen parcialmente, lo cual posiciona este hallazgo como una hipótesis sólida que espera confirmación.

Donde ambos análisis coinciden sin ambigüedad es en el subgrupo de severidad de la hipoxemia: ni mi valor p de 0.526 ni el 0.97 del artículo sugieren modificación de efecto.

La cánula de alto flujo beneficia tanto a los pacientes con compromiso pulmonar más grave como a los menos graves, un hallazgo que tiene implicaciones directas para la práctica clínica, pues el médico no necesita estratificar por la relación entre presión parcial de oxígeno y fracción inspirada de oxígeno para decidir si ofrece esta terapia.

Sintetizando esta comparación, considero que el ejercicio de reproducir el análisis de subgrupos con una herramienta diferente (Razón de Momios en lugar de Razón de Riesgo, sin ajuste en lugar de con ajuste) me ha enseñado que los resultados estadísticos son construcciones que dependen del modelo, de las variables incluidas y de las decisiones del analista.

Lo que permanece estable a través de esas decisiones (la dirección del efecto, la consistencia del patrón, la plausibilidad biológica) es lo que merece mayor confianza.

6 Conclusiones del taller

Al concluir este taller, considero que he comprendido tres lecciones que conectan la estadística con la práctica clínica y la ética de la investigación.

La primera lección proviene del análisis interino:

Aprendí que la decisión de continuar o detener un ensayo clínico no puede basarse en el umbral convencional de significancia, pues los límites de Haybittle-Peto exigen evidencia abrumadora precisamente porque las muestras intermedias son imprecisas y susceptibles a fluctuaciones aleatorias.

Con los primeros 100 pacientes observé una diferencia prometedora en ventilación mecánica invasiva (49.0% frente a 28.6%, p = 0.0422), pero esta señal no alcanzó los umbrales de detención.

La decisión correcta fue continuar, y los datos completos confirmaron que el efecto era real aunque ligeramente atenuado (50.5% frente a 33.7%, p = 0.0154).

Me parece que este recorrido del interino al definitivo ilustra con claridad por qué existen reglas de detención tan conservadoras, pues definitivamente protegen simultáneamente a los participantes, a la integridad del conocimiento y a la credibilidad de las conclusiones.

La segunda lección emerge del análisis definitivo:

La Razón de Momios de 0.498 con un Intervalo de Confianza del 95% que no incluye el valor nulo confirma que la cánula nasal de alto flujo reduce aproximadamente a la mitad los momios de requerir intubación endotraqueal.

El Número Necesario a Tratar de 6 traduce este efecto a un lenguaje que cualquier clínico puede llevar a la cabecera del paciente, donde por cada 6 personas tratadas con alto flujo, se evita una intubación.

En el contexto pandémico, donde cada ventilador mecánico liberado significaba una vida adicional que podía recibir soporte, este hallazgo tuvo consecuencias que trascendieron lo académico.

La tercera lección, y quizás la más formativa para mí, proviene de los análisis de subgrupos, pues en el forest plot se reveló un patrón clínicamente coherente, pero ninguna de mis pruebas de interacción alcanzó significancia estadística.

Tal como señalan Wang y colaboradores, la credibilidad de un hallazgo de subgrupo depende de que sea preespecificado, biológicamente plausible, consistente entre estudios y basado en un número limitado de comparaciones.

Al evaluar el ensayo HiFLo-Covid con estos criterios, considero que es metodológicamente superior a la media, pues los subgrupos fueron preespecificados, se reportaron las pruebas de interacción y se advirtió explícitamente que los resultados son exploratorios.

No obstante, la consistencia con otros estudios aún no ha sido establecida y los subgrupos más pequeños carecen de la potencia necesaria para conclusiones firmes.

En definitiva, este taller me permitió recorrer el ciclo completo de un ensayo clínico aleatorizado, desde la evaluación intermedia que protege a los participantes, pasando por el análisis definitivo que genera la evidencia, hasta la exploración de subgrupos que plantea las preguntas para una posible siguiente generación de estudios.

7 Referencias

  1. Ospina-Tascon GA, Calderon-Tapia LE, Garcia AF, et al. Effect of High-Flow Oxygen Therapy vs Conventional Oxygen Therapy on Invasive Mechanical Ventilation and Clinical Recovery in Patients With Severe COVID-19: A Randomized Clinical Trial. JAMA. 2021;326(21):2161-2171. doi:10.1001/jama.2021.20714

  2. Wang R, Lagakos SW, Ware JH, Hunter DJ, Drazen JM. Statistics in Medicine – Reporting of Subgroup Analyses in Clinical Trials. N Engl J Med. 2007;357(21):2189-2194. doi:10.1056/NEJMsr077003

  3. Pocock SJ, McMurray JJV, Collier TJ. Making Sense of Statistics in Clinical Trial Reports: Part 1 of a 4-Part Series on Statistics for Clinical Trials. J Am Coll Cardiol. 2015;66(22):2536-2549. doi:10.1016/j.jacc.2015.10.014