Versión de impresión: se muestran todas las secciones en una sola página.
# ---- rutas relativas ----
# La base GRD original no se entrega (es pública y pesa ~570 MB). Para reproducir el informe,
# se deja en la subcarpeta GRD_PUBLICO_2024/ junto a este .Rmd, igual que en la Actividad 1.
# Como respaldo se busca también en la carpeta de la Actividad 1 (../informe-1/).
buscar_archivo <- function(rel) {
candidatos <- c(rel, file.path("..", "informe-1", rel))
f <- candidatos[file.exists(candidatos)][1]
if (is.na(f)) stop("No se encontró el archivo ", rel, " junto al .Rmd")
f
}
ruta_grd <- buscar_archivo(file.path("GRD_PUBLICO_2024", "GRD_PUBLICO_2024.txt"))
cols_diag <- paste0("DIAGNOSTICO", 1:35)
cols_usar <- c("COD_HOSPITAL", "FECHA_NACIMIENTO", "TIPO_INGRESO", "ESPECIALIDAD_MEDICA",
"TIPO_ACTIVIDAD", "FECHA_INGRESO", "FECHAALTA", "TIPOALTA", cols_diag,
"IR_29301_SEVERIDAD")
base <- fread(ruta_grd, sep = "|", encoding = "Latin-1", quote = "", na.strings = "",
select = cols_usar, colClasses = list(character = "COD_HOSPITAL"))
# ---- etapa 1 y 2: base completa y exclusión de CMA (igual que en la Actividad 1) ----
n0 <- nrow(base)
n_cma <- base[TIPO_ACTIVIDAD == "CIRUGÍA MAYOR AMBULATORIA (CMA)", .N]
hosp_all <- base[TIPO_ACTIVIDAD == "HOSPITALIZACIÓN"]
rm(base); invisible(gc())
n1 <- nrow(hosp_all)
# ---- etapa 3: validez de fechas, ahora aplicada a TODOS los egresos (corrección) ----
fecha_valida <- function(x) grepl("^[0-9]{4}-[0-9]{2}-[0-9]{2}$", x)
ok_fechas <- fecha_valida(hosp_all$FECHA_INGRESO) & fecha_valida(hosp_all$FECHA_NACIMIENTO) &
fecha_valida(hosp_all$FECHAALTA)
# cohorte tal como se construyó en la Actividad 1 (I50 en algún diagnóstico, luego depuración)
i50_all <- Reduce(`|`, lapply(cols_diag, function(cc) grepl("^I50", hosp_all[[cc]])))
n_cand_A1 <- sum(i50_all)
n_cohorte_A1 <- sum(i50_all & ok_fechas)
n_malas_omega <- sum(!ok_fechas)
n_malas_E <- sum(!ok_fechas & i50_all)
omega <- hosp_all[ok_fechas]
rm(hosp_all, i50_all, ok_fechas); invisible(gc())
N <- nrow(omega)
# ---------------- Definición de los eventos sobre Ω ----------------
E_vec <- Reduce(`|`, lapply(cols_diag, function(cc) grepl("^I50", omega[[cc]])))
omega[, E := E_vec] # I50 en cualquiera de los 35 diagnósticos
omega[, Ep := grepl("^I50", DIAGNOSTICO1)] # I50 como diagnóstico principal
omega[, Es := E & !Ep] # I50 solo como diagnóstico secundario
omega[, (cols_diag) := NULL]; rm(E_vec); invisible(gc())
omega[, Fal := TIPOALTA == "FALLECIDO"] # evento F (se evita el nombre F, que en R es FALSE)
omega[, U := TIPO_INGRESO == "URGENCIA"] # evento U
omega[, estancia := as.numeric(as.Date(FECHAALTA) - as.Date(FECHA_INGRESO))]
corte_L <- unname(quantile(omega$estancia, 0.75)) # percentil 75 de la estancia en todo Ω
omega[, L := estancia > corte_L] # evento L: estancia larga
omega[, edad := as.numeric(as.Date(FECHA_INGRESO) - as.Date(FECHA_NACIMIENTO)) / 365.25]
grupos <- c("< 45", "45-64", "65-74", "75-84", "85 y más")
omega[, grupo_etario := cut(edad, breaks = c(-Inf, 45, 65, 75, 85, Inf), right = FALSE,
labels = grupos)] # mismos cortes que en la Actividad 1
sev_tab <- suppressMessages(as.data.table(read_excel("Tablas_maestras_GRD.xlsx", sheet = "Severidad GRD")))
setnames(sev_tab, c("nivel", "etiqueta"))
niveles_sev <- c("S₁", "S₂", "S₃", "Sin severidad registrada")
omega[, sev := factor(fcase(IR_29301_SEVERIDAD == "1", "S₁",
IR_29301_SEVERIDAD == "2", "S₂",
IR_29301_SEVERIDAD == "3", "S₃",
default = "Sin severidad registrada"), levels = niveles_sev)]
nE <- sum(omega$E); pE <- nE / N
nF <- sum(omega$Fal); pF <- nF / N
n_est_neg <- sum(omega$estancia < 0)
Este informe continúa el trabajo de la Actividad 1, en el rol de analista de la Unidad de Análisis Hospitalario. La Actividad 1 dimensionó y caracterizó los episodios con insuficiencia cardíaca (CIE-10 I50) dentro de los egresos hospitalarios GRD 2024. Aquí esas mismas características se expresan como eventos sobre un espacio muestral definido, y se responden preguntas de la jefatura en lenguaje de probabilidad: probabilidades marginales, condicionales y totales, el teorema de Bayes para invertir preguntas, un marcador de registro evaluado con sensibilidad, especificidad y valores predictivos, y una simulación que muestra cómo se comportan las estimaciones cuando se trabaja con muestras de episodios.
El alcance es el cálculo e interpretación de probabilidades sobre la base GRD 2024: no se ajustan modelos predictivos ni se realizan pruebas de hipótesis.
Qué significa una probabilidad en este informe P(A) es la probabilidad de que un episodio elegido al azar entre los egresos hospitalarios de Ω cumpla la condición A. No es la probabilidad de que una persona enferme o fallezca ni una tasa poblacional: cada fila de la base es un episodio de hospitalización, y una misma persona puede aportar varios episodios.
Se utilizó Claude Code (Anthropic, modelo Claude Opus 5.5) como apoyo para: (i) escribir y depurar el código R de construcción de eventos, tablas de contingencia, aplicaciones de Bayes y simulación; (ii) redactar borradores del texto interpretativo; y (iii) revisar el cumplimiento de la pauta y de la retroalimentación de la Actividad 1. Los resultados se verificaron así: (a) ninguna cifra del texto está escrita a mano: todas se insertan desde el código y se recalculan en cada compilación; (b) cada aplicación de la ley de probabilidad total y del teorema de Bayes se contrasta en una tabla con el conteo directo de episodios, con una columna de diferencia que debe ser cero salvo redondeo; (c) la unión se verifica por fórmula y por conteo; (d) la simulación usa semilla fija y se comprobó que dos compilaciones sucesivas entregan los mismos números; y (e) las frases que comparan valores (por ejemplo, qué nivel de severidad aporta más fallecimientos) se generan a partir de los propios valores calculados, para que el texto no pueda contradecir a su tabla. La responsabilidad técnica y de contenido del informe es del autor.
RESULTADO 01 · PARTE 1
Espacio muestral Ω = egresos hospitalarios GRD 2024, sin CMA y con fechas de ingreso, nacimiento y alta válidas. N = 873.719 episodios. Este N es el denominador de toda probabilidad marginal del informe. La cohorte E (insuficiencia cardíaca en cualquier campo de diagnóstico) tiene n(E) = 52.312 episodios, P(E) = 52.312 / 873.719 = 5,99%.
Se usan la misma base, las mismas tablas auxiliares y la misma definición CIE-10 de la Actividad 1:
GRD_PUBLICO_2024.txt, base
pública de egresos hospitalarios y cirugía mayor ambulatoria del
mecanismo GRD, Fondo Nacional de Salud (FONASA), año 2024. Texto plano
delimitado por |, codificación Latin-1. Descargada desde el
portal de datos abiertos de FONASA el 21 de agosto de 2026. La base no
se entrega junto al informe por su tamaño; para reproducirlo se ubica en
la subcarpeta GRD_PUBLICO_2024/.Tablas_maestras_GRD.xlsx (se entrega):
hoja Hospitales para el nombre de cada establecimiento y hoja
Severidad GRD para las etiquetas de severidad.CIE-10.xlsx (se entrega): catálogo
oficial CIE-10, para verificar los códigos I50.cie10 <- suppressMessages(as.data.table(read_excel("CIE-10.xlsx", sheet = "CIE 10")))
tabla_html(cie10[grepl("^I50", Código), .(Código, Descripción)],
caption = "Códigos CIE-10 que definen el evento E (fuente: CIE-10.xlsx)",
label = "cie10")
| Código | Descripción |
|---|---|
| I50 | Insuficiencia cardíaca |
| I50.0 | Insuficiencia cardíaca congestiva |
| I50.1 | Insuficiencia ventricular izquierda |
| I50.9 | Insuficiencia cardíaca, no especificada |
El evento E se define con el patrón ^I50, que captura
I50 y sus subcategorías I50.0, I50.1 e I50.9 (Tabla 1), buscado en los
35 campos de diagnóstico de cada episodio.
La retroalimentación de la Actividad 1 no pidió corregir la definición de la cohorte; sus observaciones se refieren al lenguaje y a la entrega. Todas se aplicaron en este informe. Se agregó además una corrección metodológica propia, necesaria para el cálculo de probabilidades.
cambios <- data.table(
`N.º` = 1:6,
`Observación o problema detectado` = c(
"(Corrección propia) En la Actividad 1 la depuración de fechas no válidas se aplicó solo a los episodios candidatos con I50, no al total de egresos.",
"Retroalimentación: se escribió \"personas de 65 años o más\", cuando la unidad de análisis es el episodio.",
"Retroalimentación: se escribió \"en promedio\" al comparar medianas de peso GRD.",
"Retroalimentación: la explicación invernal del alza del tercer trimestre es una hipótesis que conviene dejar fuera.",
"Retroalimentación: la frase \"Fecha de extracción declarada por el estudiante\" debía reescribirse.",
"Retroalimentación: la entrega no traía el enlace al HTML publicado ni las tablas auxiliares."),
`Cambio aplicado en la Actividad 2` = c(
paste0("La misma regla de fechas válidas se aplica a todo el espacio muestral. Así la estancia (evento L) y la edad (grupos G) quedan definidas para cada episodio de Ω, y todas las probabilidades usan el mismo universo depurado."),
"Todo el texto habla de episodios. Ninguna probabilidad se presenta como característica de personas.",
"Se nombra el estadístico que se compara. En este informe se trabaja con proporciones, no con promedios.",
"No se proponen hipótesis explicativas ni estacionales: las probabilidades condicionales se describen como co-ocurrencia en los registros.",
"Se reescribió como \"Descargada desde el portal de datos abiertos de FONASA el 21 de agosto de 2026\".",
"Se entregan Tablas_maestras_GRD.xlsx y CIE-10.xlsx junto al .Rmd, y el enlace al HTML publicado."),
`Efecto sobre Ω o sobre la cohorte` = c(
paste0("Ω pasa de ", fnum(n1), " a ", fnum(N), " egresos (", fnum(n_malas_omega),
" excluidos). La cohorte no cambia: ", fnum(nE), " episodios, igual que en la Actividad 1, porque los ",
fnum(n_malas_E), " episodios con I50 y fecha no válida ya se habían excluido."),
"Ninguno (redacción).", "Ninguno (redacción).", "Ninguno (redacción).",
"Ninguno (redacción).", "Ninguno (entrega).")
)
tabla_html(cambios, caption = "Cambios respecto de la Actividad 1 y su efecto sobre el espacio muestral y la cohorte",
label = "cambios") |>
column_spec(2:4, width = "30%") |> kable_styling(full_width = TRUE)
| N.º | Observación o problema detectado | Cambio aplicado en la Actividad 2 | Efecto sobre Ω o sobre la cohorte |
|---|---|---|---|
| 1 | (Corrección propia) En la Actividad 1 la depuración de fechas no válidas se aplicó solo a los episodios candidatos con I50, no al total de egresos. | La misma regla de fechas válidas se aplica a todo el espacio muestral. Así la estancia (evento L) y la edad (grupos G) quedan definidas para cada episodio de Ω, y todas las probabilidades usan el mismo universo depurado. | Ω pasa de 873.772 a 873.719 egresos (53 excluidos). La cohorte no cambia: 52.312 episodios, igual que en la Actividad 1, porque los 3 episodios con I50 y fecha no válida ya se habían excluido. |
| 2 | Retroalimentación: se escribió "personas de 65 años o más", cuando la unidad de análisis es el episodio. | Todo el texto habla de episodios. Ninguna probabilidad se presenta como característica de personas. | Ninguno (redacción). |
| 3 | Retroalimentación: se escribió "en promedio" al comparar medianas de peso GRD. | Se nombra el estadístico que se compara. En este informe se trabaja con proporciones, no con promedios. | Ninguno (redacción). |
| 4 | Retroalimentación: la explicación invernal del alza del tercer trimestre es una hipótesis que conviene dejar fuera. | No se proponen hipótesis explicativas ni estacionales: las probabilidades condicionales se describen como co-ocurrencia en los registros. | Ninguno (redacción). |
| 5 | Retroalimentación: la frase "Fecha de extracción declarada por el estudiante" debía reescribirse. | Se reescribió como "Descargada desde el portal de datos abiertos de FONASA el 21 de agosto de 2026". | Ninguno (redacción). |
| 6 | Retroalimentación: la entrega no traía el enlace al HTML publicado ni las tablas auxiliares. | Se entregan Tablas_maestras_GRD.xlsx y CIE-10.xlsx junto al .Rmd, y el enlace al HTML publicado. | Ninguno (entrega). |
Tamaño final de la cohorte: 52.312 episodios (igual que en la Actividad 1, donde la cohorte final fue de 52.312 episodios). El único cambio que altera un conteo es el 1, que reduce Ω en 53 egresos: P(E) cambia en menos de una centésima de punto porcentual (de 5,9869% a 5,9873%).
traz <- data.table(
Etapa = c("1. Base completa GRD 2024",
"2. Excluye cirugía mayor ambulatoria (CMA)",
"3. Excluye egresos con fecha de ingreso, nacimiento o alta no válida",
"Ω: espacio muestral (egresos hospitalarios depurados)",
"E: episodios de Ω con I50 en algún diagnóstico (subconjunto, no exclusión)"),
Episodios = fnum(c(n0, n1, N, N, nE)),
`Excluidos en la etapa` = c("—", fnum(n_cma), fnum(n_malas_omega), "—", "—"))
tabla_html(traz, caption = "Trazabilidad desde la base completa hasta el espacio muestral Ω y la cohorte E",
label = "traz")
| Etapa | Episodios | Excluidos en la etapa |
|---|---|---|
|
1.085.813 | — |
|
873.772 | 212.041 |
|
873.719 | 53 |
| Ω: espacio muestral (egresos hospitalarios depurados) | 873.719 | — |
| E: episodios de Ω con I50 en algún diagnóstico (subconjunto, no exclusión) | 52.312 | — |
Tabla 3 muestra que Ω conserva el 99,994% de los egresos
hospitalarios; los 53 excluidos traen el texto
"DESCONOCIDO" en lugar de una fecha, lo que impide calcular
su estancia y su edad. No hay estancias negativas en Ω (0 casos), por lo
que no se requirió otra exclusión.
RESULTADO 01 · PARTE 2
Cada evento se construye como una columna lógica
(TRUE/FALSE) sobre Ω con la regla en R
indicada. Todas las probabilidades de esta tabla son marginales:
denominador N = 873.719.
ev_fila <- function(nombre, definicion, regla, x) {
data.table(Evento = nombre, `Definición operacional` = definicion,
# se escapan comillas y acentos graves para que pandoc no los convierta en tipográficos
`Regla en R` = paste0("<code>", gsub("`", "`", htmltools::htmlEscape(regla, attribute = TRUE)), "</code>"),
`n(evento)` = fnum(sum(x)),
`Probabilidad = n / N` = fpct(mean(x), ifelse(mean(x) < 0.001, 4, 2)))
}
tab_ev <- rbind(
ev_fila("Ω", "Egresos hospitalarios GRD 2024 sin CMA y con fechas válidas", "nrow(omega)", rep(TRUE, N)),
ev_fila("E", "I50 registrado en cualquiera de los 35 campos de diagnóstico", 'Reduce("|", lapply(paste0("DIAGNOSTICO", 1:35), function(cc) grepl("^I50", omega[[cc]])))', omega$E),
ev_fila("Eₚ", "I50 como diagnóstico principal", 'grepl("^I50", DIAGNOSTICO1)', omega$Ep),
ev_fila("Eₛ = E ∩ Ēₚ", "I50 registrado solo como diagnóstico secundario", "E & !Ep", omega$Es),
ev_fila("F", "El episodio termina en fallecimiento", 'TIPOALTA == "FALLECIDO"', omega$Fal),
ev_fila("U", "El episodio ingresa por urgencia", 'TIPO_INGRESO == "URGENCIA"', omega$U),
ev_fila("L", paste0("Estancia larga: estancia mayor que el percentil 75 de Ω (", fnum(corte_L), " días)"),
paste0("as.numeric(as.Date(FECHAALTA) - as.Date(FECHA_INGRESO)) > ", corte_L), omega$L),
ev_fila("S₁", paste0("Severidad GRD 1 (", sev_tab[nivel == 1, etiqueta], ")"), 'IR_29301_SEVERIDAD == "1"', omega$sev == "S₁"),
ev_fila("S₂", paste0("Severidad GRD 2 (", sev_tab[nivel == 2, etiqueta], ")"), 'IR_29301_SEVERIDAD == "2"', omega$sev == "S₂"),
ev_fila("S₃", paste0("Severidad GRD 3 (", sev_tab[nivel == 3, etiqueta], ")"), 'IR_29301_SEVERIDAD == "3"', omega$sev == "S₃"),
ev_fila("S sin registro", "Severidad 0 o \"DESCONOCIDO\"", '!(IR_29301_SEVERIDAD %in% c("1","2","3"))', omega$sev == "Sin severidad registrada"),
rbindlist(lapply(grupos, function(g)
ev_fila(paste0("G (", g, ")"), paste0("Grupo etario ", g, " años al ingreso"),
paste0('grupo_etario == "', g, '"'), omega$grupo_etario == g)))
)
tabla_html(tab_ev, caption = paste0("Eventos definidos sobre Ω, con su regla en R, su conteo y su probabilidad marginal (denominador N = ", fnum(N), ")"),
label = "eventos", escape = FALSE) |>
column_spec(1, bold = TRUE) |> column_spec(2, width = "28%")
| Evento | Definición operacional | Regla en R | n(evento) | Probabilidad = n / N |
|---|---|---|---|---|
| Ω | Egresos hospitalarios GRD 2024 sin CMA y con fechas válidas |
nrow(omega)
|
873.719 | 100,00% |
| E | I50 registrado en cualquiera de los 35 campos de diagnóstico |
Reduce("|", lapply(paste0("DIAGNOSTICO", 1:35), function(cc)
grepl("^I50", omega[[cc]])))
|
52.312 | 5,99% |
| Eₚ | I50 como diagnóstico principal |
grepl("^I50", DIAGNOSTICO1)
|
11.331 | 1,30% |
| Eₛ = E ∩ Ēₚ | I50 registrado solo como diagnóstico secundario |
E & !Ep
|
40.981 | 4,69% |
| F | El episodio termina en fallecimiento |
TIPOALTA == "FALLECIDO"
|
26.660 | 3,05% |
| U | El episodio ingresa por urgencia |
TIPO_INGRESO == "URGENCIA"
|
545.614 | 62,45% |
| L | Estancia larga: estancia mayor que el percentil 75 de Ω (7 días) |
as.numeric(as.Date(FECHAALTA) - as.Date(FECHA_INGRESO)) >
7
|
212.172 | 24,28% |
| S₁ | Severidad GRD 1 (Menor) |
IR_29301_SEVERIDAD == "1"
|
387.252 | 44,32% |
| S₂ | Severidad GRD 2 (Moderada) |
IR_29301_SEVERIDAD == "2"
|
268.863 | 30,77% |
| S₃ | Severidad GRD 3 (Mayor) |
IR_29301_SEVERIDAD == "3"
|
217.583 | 24,90% |
| S sin registro | Severidad 0 o "DESCONOCIDO" |
!(IR_29301_SEVERIDAD %in% c("1","2","3"))
|
21 | 0,0024% |
| G (< 45) | Grupo etario < 45 años al ingreso |
grupo_etario == "< 45"
|
442.631 | 50,66% |
| G (45-64) | Grupo etario 45-64 años al ingreso |
grupo_etario == "45-64"
|
188.401 | 21,56% |
| G (65-74) | Grupo etario 65-74 años al ingreso |
grupo_etario == "65-74"
|
118.545 | 13,57% |
| G (75-84) | Grupo etario 75-84 años al ingreso |
grupo_etario == "75-84"
|
88.466 | 10,13% |
| G (85 y más) | Grupo etario 85 y más años al ingreso |
grupo_etario == "85 y más"
|
35.676 | 4,08% |
La edad se calcula como
(FECHA_INGRESO − FECHA_NACIMIENTO) / 365,25 y los grupos
etarios usan los mismos cortes de la Actividad 1
(cut(..., right = FALSE), de modo que un episodio de 45,0
años queda en 45-64).
Interpretación (Tabla 4): la insuficiencia cardíaca está registrada en 5,99% de los egresos de Ω, y en 1,30% como diagnóstico principal: la mayor parte de E (78,3% de sus episodios) corresponde a I50 solo como diagnóstico secundario. El fallecimiento ocurre en 3,05% de los egresos de Ω y el ingreso por urgencia en 62,45%. Como la estancia se mide en días enteros, el percentil 75 de Ω (7 días) concentra muchos empates; por eso L, definido como estancia mayor que 7 días, abarca 24,28% de Ω y no exactamente el 25%. Los eventos S₁, S₂, S₃ y "S sin registro" forman una partición de Ω (suman 873.719 = N), al igual que los cinco grupos etarios.
nEF <- sum(omega$E & omega$Fal)
pEF <- nEF / N
pE_c <- 1 - pE # complemento por fórmula
pE_c_conteo <- sum(!omega$E) / N # complemento por conteo
pFgE <- nEF / nE # P(F | E)
pUnion_formula <- pE + pF - pEF # unión por fórmula
pUnion_conteo <- sum(omega$E | omega$Fal) / N # unión por conteo directo
pL <- mean(omega$L); pEL <- mean(omega$E & omega$L)
pUnion2_formula <- pE + pL - pEL
pUnion2_conteo <- mean(omega$E | omega$L)
ops <- data.table(
`Operación` = c("Complemento", "Intersección", "Unión", "Unión"),
`Evento` = c("Ē (sin I50)", "E ∩ F", "E ∪ F", "E ∪ L"),
`Cálculo por fórmula` = c(
paste0("1 − P(E) = 1 − ", f4(pE), " = ", f4(pE_c)),
paste0("P(F | E) · P(E) = ", f4(pFgE), " × ", f4(pE), " = ", f4(pFgE * pE)),
paste0("P(E) + P(F) − P(E ∩ F) = ", f4(pE), " + ", f4(pF), " − ", f4(pEF), " = ", f4(pUnion_formula)),
paste0("P(E) + P(L) − P(E ∩ L) = ", f4(pE), " + ", f4(pL), " − ", f4(pEL), " = ", f4(pUnion2_formula))),
`Conteo directo sobre Ω` = c(
paste0(fnum(sum(!omega$E)), " / ", fnum(N), " = ", f4(pE_c_conteo)),
paste0(fnum(nEF), " / ", fnum(N), " = ", f4(pEF)),
paste0(fnum(sum(omega$E | omega$Fal)), " / ", fnum(N), " = ", f4(pUnion_conteo)),
paste0(fnum(sum(omega$E | omega$L)), " / ", fnum(N), " = ", f4(pUnion2_conteo))),
`Diferencia` = formatC(c(pE_c - pE_c_conteo, pFgE * pE - pEF,
pUnion_formula - pUnion_conteo, pUnion2_formula - pUnion2_conteo),
format = "e", digits = 1)
)
tabla_html(ops, caption = paste0("Complemento, intersección y unión: cálculo por fórmula y verificación por conteo directo (denominador N = ", fnum(N), ")"),
label = "ops")
| Operación | Evento | Cálculo por fórmula | Conteo directo sobre Ω | Diferencia |
|---|---|---|---|---|
| Complemento | Ē (sin I50) | 1 − P(E) = 1 − 0,0599 = 0,9401 | 821.407 / 873.719 = 0,9401 | 0.0e+00 |
| Intersección | E ∩ F | P(F | E) · P(E) = 0,1000 × 0,0599 = 0,0060 | 5.231 / 873.719 = 0,0060 | 0.0e+00 |
| Unión | E ∪ F | P(E) + P(F) − P(E ∩ F) = 0,0599 + 0,0305 − 0,0060 = 0,0844 | 73.741 / 873.719 = 0,0844 | 0.0e+00 |
| Unión | E ∪ L | P(E) + P(L) − P(E ∩ L) = 0,0599 + 0,2428 − 0,0268 = 0,2759 | 241.102 / 873.719 = 0,2759 | 5.6e-17 |
Interpretación (Tabla 5): 94,01% de los egresos de Ω no registra insuficiencia cardíaca. La intersección E ∩ F reúne 5.231 episodios (0,60% de Ω): episodios con I50 que terminan en fallecimiento. La unión E ∪ F (episodios con I50, o que terminan en fallecimiento, o ambos) abarca 8,44% de Ω, y la fórmula de la unión coincide con el conteo directo: la diferencia es del orden del error de redondeo de la máquina. Lo mismo ocurre con E ∪ L. La intersección se resta en la fórmula porque esos 5.231 episodios están contados dos veces en P(E) + P(F).
RESULTADO 02
nEnF <- sum(omega$E & !omega$Fal)
nEcF <- sum(!omega$E & omega$Fal)
nEcnF <- sum(!omega$E & !omega$Fal)
cont_n <- data.table(
` ` = c("E (con I50)", "Ē (sin I50)", "Total"),
`F (fallece)` = fnum(c(nEF, nEcF, nF)),
`F̄ (no fallece)` = fnum(c(nEnF, nEcnF, N - nF)),
Total = fnum(c(nE, N - nE, N)))
tabla_html(cont_n, caption = "Tabla de contingencia de E contra F: conteos de episodios", label = "contEF_n") |>
column_spec(1, bold = TRUE) |> row_spec(3, bold = TRUE)
| F (fallece) | F̄ (no fallece) | Total | |
|---|---|---|---|
| E (con I50) | 5.231 | 47.081 | 52.312 |
| Ē (sin I50) | 21.429 | 799.978 | 821.407 |
| Total | 26.660 | 847.059 | 873.719 |
cont_p <- data.table(
` ` = c("E (con I50)", "Ē (sin I50)", "Total"),
`F (fallece)` = fpct(c(nEF, nEcF, nF) / N, 3),
`F̄ (no fallece)` = fpct(c(nEnF, nEcnF, N - nF) / N, 3),
Total = fpct(c(nE, N - nE, N) / N, 3))
tabla_html(cont_p, caption = paste0("Tabla de contingencia de E contra F: probabilidades conjuntas y marginales (cada celda dividida por N = ", fnum(N), ")"),
label = "contEF_p") |>
column_spec(1, bold = TRUE) |> row_spec(3, bold = TRUE)
| F (fallece) | F̄ (no fallece) | Total | |
|---|---|---|---|
| E (con I50) | 0,599% | 5,389% | 5,987% |
| Ē (sin I50) | 2,453% | 91,560% | 94,013% |
| Total | 3,051% | 96,949% | 100,000% |
Tabla 6 entrega los conteos y Tabla 7 las probabilidades conjuntas, todas sobre N. Por ejemplo, P(E ∩ F) = 0,599%: solo una pequeña fracción de los egresos de Ω tiene I50 y termina en fallecimiento. Las celdas de la fila y la columna "Total" son las probabilidades marginales P(E) y P(F). Las probabilidades condicionales se obtienen dividiendo por el total de una fila o de una columna, y se presentan a continuación.
pFgEc <- nEcF / (N - nE)
pFgEp <- cond(omega$Fal, omega$Ep)
pFgEs <- cond(omega$Fal, omega$Es)
nEp <- sum(omega$Ep); nEs <- sum(omega$Es)
condF <- data.table(
Probabilidad = c("P(F)", "P(F | E)", "P(F | Ē)", "P(F | Eₚ)", "P(F | Eₛ)"),
`Pregunta que responde` = c(
"Fracción de los egresos de Ω que termina en fallecimiento",
"Fracción de los episodios con I50 que termina en fallecimiento",
"Fracción de los episodios sin I50 que termina en fallecimiento",
"Fracción de los episodios con I50 como diagnóstico principal que termina en fallecimiento",
"Fracción de los episodios con I50 solo secundario que termina en fallecimiento"),
`Numerador` = fnum(c(nF, nEF, nEcF, sum(omega$Ep & omega$Fal), sum(omega$Es & omega$Fal))),
`Denominador (total sobre el que se calcula)` = c(paste0("N = ", fnum(N)), paste0("n(E) = ", fnum(nE)),
paste0("n(Ē) = ", fnum(N - nE)), paste0("n(Eₚ) = ", fnum(nEp)),
paste0("n(Eₛ) = ", fnum(nEs))),
Valor = fpct(c(pF, pFgE, pFgEc, pFgEp, pFgEs)),
`Diferencia con P(F)` = c("—", fpp(c(pFgE, pFgEc, pFgEp, pFgEs) - pF)))
tabla_html(condF, caption = "Probabilidades condicionales de fallecimiento según el registro de insuficiencia cardíaca",
label = "condF") |> column_spec(2, width = "34%")
| Probabilidad | Pregunta que responde | Numerador | Denominador (total sobre el que se calcula) | Valor | Diferencia con P(F) |
|---|---|---|---|---|---|
| P(F) | Fracción de los egresos de Ω que termina en fallecimiento | 26.660 | N = 873.719 | 3,05% | — |
| P(F | E) | Fracción de los episodios con I50 que termina en fallecimiento | 5.231 | n(E) = 52.312 | 10,00% | +6,95 p.p. |
| P(F | Ē) | Fracción de los episodios sin I50 que termina en fallecimiento | 21.429 | n(Ē) = 821.407 | 2,61% | -0,44 p.p. |
| P(F | Eₚ) | Fracción de los episodios con I50 como diagnóstico principal que termina en fallecimiento | 808 | n(Eₚ) = 11.331 | 7,13% | +4,08 p.p. |
| P(F | Eₛ) | Fracción de los episodios con I50 solo secundario que termina en fallecimiento | 4.423 | n(Eₛ) = 40.981 | 10,79% | +7,74 p.p. |
Interpretación (Tabla 8): 10,0% de los episodios con I50 termina en fallecimiento, frente a 2,6% de los episodios sin I50: P(F | E) es 3,8 veces P(F | Ē). Dentro de la cohorte, la proporción es mayor cuando I50 está registrada solo como diagnóstico secundario (10,8%) que cuando es el diagnóstico principal (7,1%), lo mismo que se observó en la Actividad 1. Ambas condicionales se calculan sobre más de 11.000 episodios, de modo que no dependen de unos pocos casos. P(F | E) es el promedio ponderado de las dos: P(F | Eₚ)·P(Eₚ | E) + P(F | Eₛ)·P(Eₛ | E) = 0,0713 × 0,2166 + 0,1079 × 0,7834 = 0,1000, igual a P(F | E) = 0,1000. Estos valores describen con qué frecuencia coinciden ambos registros en los episodios de la base; no indican que la insuficiencia cardíaca produzca el fallecimiento.
No confundir la condicional con su inversa P(F | E) = 10,00% responde qué fracción de los episodios con I50 termina en fallecimiento. P(E | F) = 19,62% responde qué fracción de los fallecimientos de Ω tiene I50 registrada (se calcula con Bayes en la sección del teorema de Bayes). Comparten el numerador n(E ∩ F) = 5.231, pero sus denominadores son n(E) = 52.312 y n(F) = 26.660.
tab_g <- omega[, .(nG = .N, nEG = sum(E)), keyby = grupo_etario]
tab_g[, pEgG := nEG / nG]
tab_g_show <- tab_g[, .(`Grupo etario (G)` = as.character(grupo_etario),
`n(G): denominador` = fnum(nG),
`n(E ∩ G)` = fnum(nEG),
`P(E | G)` = fpct(pEgG),
`Diferencia con P(E)` = fpp(pEgG - pE),
`P(E | G) / P(E)` = fnum(pEgG / pE, 2),
Advertencia = aviso(nEG))]
tabla_html(tab_g_show, caption = paste0("Probabilidad de registrar insuficiencia cardíaca dentro de cada grupo etario, P(E | G) = n(E ∩ G) / n(G). Referencia: P(E) = ", fpct(pE)),
label = "EgG")
| Grupo etario (G) | n(G): denominador | n(E ∩ G) | P(E | G) | Diferencia con P(E) | P(E | G) / P(E) | Advertencia |
|---|---|---|---|---|---|---|
| < 45 | 442.631 | 2.152 | 0,49% | -5,50 p.p. | 0,08 | |
| 45-64 | 188.401 | 11.950 | 6,34% | +0,36 p.p. | 1,06 | |
| 65-74 | 118.545 | 14.496 | 12,23% | +6,24 p.p. | 2,04 | |
| 75-84 | 88.466 | 15.640 | 17,68% | +11,69 p.p. | 2,95 | |
| 85 y más | 35.676 | 8.074 | 22,63% | +16,64 p.p. | 3,78 |
g_max <- tab_g[which.max(pEgG)]; g_min <- tab_g[which.min(pEgG)]
ggplot(tab_g, aes(x = grupo_etario, y = pEgG)) +
geom_col(fill = paleta[1], width = 0.6) +
geom_hline(yintercept = pE, linetype = "dashed", color = paleta[2], linewidth = 0.9) +
annotate("text", x = 0.55, y = pE, label = paste0("P(E) = ", fpct(pE)), vjust = -0.6, hjust = 0,
color = paleta[2], size = 3.6) +
geom_text(aes(label = fpct(pEgG, 1)), vjust = -0.4, size = 3.8) +
scale_y_continuous(labels = function(x) fpct(x, 0), expand = expansion(mult = c(0, 0.15))) +
labs(title = "Probabilidad de registrar insuficiencia cardíaca según grupo etario",
subtitle = "Denominador de cada barra: episodios de Ω en ese grupo etario",
x = "Grupo etario (años al ingreso)", y = "P(E | G)")
Figura 1. P(E | G) por grupo etario; la línea punteada marca P(E) en todo Ω.
Interpretación (Tabla 9 y Figura 1): la probabilidad de que un episodio registre I50 crece con la edad del grupo: va de 0,49% en el grupo < 45 a 22,63% en el grupo 85 y más, es decir, 3,8 veces P(E). Los grupos de 65 años o más superan P(E) y los menores de 65 quedan por debajo. Ninguna celda tiene menos de 30 episodios con I50. Esta tabla responde P(E | G), la fracción de episodios de cada grupo que tiene I50; no debe leerse como la distribución de la cohorte por edad, que sería P(G | E).
coh <- omega[E == TRUE]
pLgEU <- cond(coh$L, coh$U)
pLgEUc <- cond(coh$L, !coh$U)
pLgE <- mean(coh$L)
tab_LU <- data.table(
Probabilidad = c("P(L)", "P(L | E)", "P(L | E ∩ U)", "P(L | E ∩ Ū)"),
`Subconjunto (denominador)` = c(paste0("Ω: N = ", fnum(N)), paste0("E: ", fnum(nE)),
paste0("E ∩ U: ", fnum(sum(coh$U))), paste0("E ∩ Ū: ", fnum(sum(!coh$U)))),
`Episodios con estancia larga` = fnum(c(sum(omega$L), sum(coh$L), sum(coh$L & coh$U), sum(coh$L & !coh$U))),
Valor = fpct(c(pL, pLgE, pLgEU, pLgEUc)),
`Diferencia con P(L | E)` = c("—", "—", fpp(pLgEU - pLgE), fpp(pLgEUc - pLgE)))
tabla_html(tab_LU, caption = paste0("Estancia larga (más de ", corte_L, " días) dentro de la cohorte según el tipo de ingreso"),
label = "LU")
| Probabilidad | Subconjunto (denominador) | Episodios con estancia larga | Valor | Diferencia con P(L | E) |
|---|---|---|---|---|
| P(L) | Ω: N = 873.719 | 212.172 | 24,28% | — |
| P(L | E) | E: 52.312 | 23.382 | 44,70% | — |
| P(L | E ∩ U) | E ∩ U: 46.876 | 21.693 | 46,28% | +1,58 p.p. |
| P(L | E ∩ Ū) | E ∩ Ū: 5.436 | 1.689 | 31,07% | -13,63 p.p. |
comp_Uc <- coh[U == FALSE, .N, by = TIPO_INGRESO][order(-N)]
comp_Uc[, etiqueta := fcase(TIPO_INGRESO == "PROGRAMADA", "ingresos programados",
TIPO_INGRESO == "OBSTETRICA", "ingresos obstétricos",
TIPO_INGRESO == "DESCONOCIDO", "tipo de ingreso desconocido",
default = tolower(TIPO_INGRESO))]
Interpretación (Tabla 10): dentro de la cohorte, 46,3% de los episodios que ingresan por urgencia tiene estancia larga, frente a 31,1% de los que no ingresan por urgencia: una diferencia de 15,2 puntos porcentuales. Ambas superan P(L) = 24,3% en todo Ω, lo que indica que la estancia larga es más frecuente en la cohorte, cualquiera sea el tipo de ingreso. Ū agrupa ingresos programados (5.378), ingresos obstétricos (55), tipo de ingreso desconocido (3); los ingresos por urgencia son la gran mayoría de la cohorte (89,6%), por lo que P(L | E) queda muy cerca de P(L | E ∩ U).
Dos eventos A y B serían independientes si P(A ∩ B) = P(A) · P(B). Se comparan ambos valores para tres pares de eventos sobre Ω, sin prueba de hipótesis: se muestran los dos valores, su diferencia y su razón.
indep <- function(a, b, nombre_a, nombre_b) {
pa <- mean(a); pb <- mean(b); pab <- mean(a & b)
data.table(`Par (A, B)` = paste0(nombre_a, ", ", nombre_b),
`P(A)` = fpct(pa), `P(B)` = fpct(pb),
`P(A) · P(B)` = fpct(pa * pb, 3), `P(A ∩ B)` = fpct(pab, 3),
`Diferencia P(A ∩ B) − P(A)·P(B)` = fpp(pab - pa * pb, 3),
`Razón P(A ∩ B) / [P(A)·P(B)]` = fnum(pab / (pa * pb), 2),
`P(A | B) frente a P(A)` = paste0(fpct(pab / pb), " vs ", fpct(pa)),
`n(A ∩ B)` = fnum(sum(a & b)),
raz = pab / (pa * pb))
}
tab_ind <- rbind(indep(omega$E, omega$Fal, "E", "F"),
indep(omega$E, omega$L, "E", "L"),
indep(omega$E, omega$U, "E", "U"))
raz_ind <- tab_ind$raz; tab_ind[, raz := NULL]
tabla_html(tab_ind, caption = paste0("Comparación entre P(A ∩ B) y P(A)·P(B) para tres pares de eventos (todas sobre N = ", fnum(N), ")"),
label = "indep")
| Par (A, B) | P(A) | P(B) | P(A) · P(B) | P(A ∩ B) | Diferencia P(A ∩ B) − P(A)·P(B) | Razón P(A ∩ B) / [P(A)·P(B)] | P(A | B) frente a P(A) | n(A ∩ B) |
|---|---|---|---|---|---|---|---|---|
| E, F | 5,99% | 3,05% | 0,183% | 0,599% | +0,416 p.p. | 3,28 | 19,62% vs 5,99% | 5.231 |
| E, L | 5,99% | 24,28% | 1,454% | 2,676% | +1,222 p.p. | 1,84 | 11,02% vs 5,99% | 23.382 |
| E, U | 5,99% | 62,45% | 3,739% | 5,365% | +1,626 p.p. | 1,43 | 8,59% vs 5,99% | 46.876 |
Interpretación (Tabla 11):
En los tres pares la desviación respecto de la independencia es descriptiva: indica que los eventos aparecen juntos en los registros con una frecuencia distinta a la del producto de sus marginales, no que uno explique al otro.
RESULTADO 03
Dentro de la cohorte se usan los niveles de severidad como partición y se descompone la probabilidad de fallecimiento:
P(F | E) = Σₖ P(F | E ∩ Sₖ) · P(Sₖ | E)
n_sin_sev_E <- sum(coh$sev == "Sin severidad registrada")
detalle_sin_sev <- coh[sev == "Sin severidad registrada", .N, by = IR_29301_SEVERIDAD]
tp <- coh[, .(n_k = .N, f_k = sum(Fal)), keyby = sev]
tp <- merge(data.table(sev = factor(niveles_sev, levels = niveles_sev)), tp, by = "sev", all.x = TRUE)
tp[is.na(n_k), `:=`(n_k = 0L, f_k = 0L)]
tp[, `:=`(p_s = n_k / nE, p_f_s = ifelse(n_k > 0, f_k / n_k, 0))]
tp[, producto := p_s * p_f_s]
tp[, aporte := f_k / sum(f_k)]
suma_prod <- sum(tp$producto)
tp_show <- tp[, .(`Nivel (Sₖ)` = as.character(sev),
`n(E ∩ Sₖ)` = fnum(n_k),
`P(Sₖ | E)` = f4(p_s),
`n(F ∩ E ∩ Sₖ)` = fnum(f_k),
`P(F | E ∩ Sₖ)` = f4(p_f_s),
`Producto P(F | E ∩ Sₖ)·P(Sₖ | E)` = f4(producto),
`% de los fallecimientos de E` = fpct(aporte, 1),
Advertencia = aviso(n_k))]
tp_show <- rbind(tp_show, data.table(`Nivel (Sₖ)` = "Suma", `n(E ∩ Sₖ)` = fnum(sum(tp$n_k)),
`P(Sₖ | E)` = f4(sum(tp$p_s)), `n(F ∩ E ∩ Sₖ)` = fnum(sum(tp$f_k)),
`P(F | E ∩ Sₖ)` = "—", `Producto P(F | E ∩ Sₖ)·P(Sₖ | E)` = f4(suma_prod),
`% de los fallecimientos de E` = fpct(1, 1), Advertencia = ""))
tabla_html(tp_show, caption = paste0("Ley de probabilidad total: descomposición de P(F | E) por nivel de severidad (P(Sₖ | E) sobre n(E) = ",
fnum(nE), "; P(F | E ∩ Sₖ) sobre n(E ∩ Sₖ))"),
label = "ptotal") |> row_spec(nrow(tp_show), bold = TRUE)
| Nivel (Sₖ) | n(E ∩ Sₖ) | P(Sₖ | E) | n(F ∩ E ∩ Sₖ) | P(F | E ∩ Sₖ) | Producto P(F | E ∩ Sₖ)·P(Sₖ | E) | % de los fallecimientos de E | Advertencia |
|---|---|---|---|---|---|---|---|
| S₁ | 734 | 0,0140 | 9 | 0,0123 | 0,0002 | 0,2% | |
| S₂ | 19.831 | 0,3791 | 403 | 0,0203 | 0,0077 | 7,7% | |
| S₃ | 31.745 | 0,6068 | 4.817 | 0,1517 | 0,0921 | 92,1% | |
| Sin severidad registrada | 2 | 0,0000 | 2 | 1,0000 | 0,0000 | 0,0% | Pocos episodios (n = 2) |
| Suma | 52.312 | 1,0000 | 5.231 | — | 0,1000 | 100,0% |
verif_tp <- data.table(
`Cálculo` = c("Suma de los productos (ley de probabilidad total)", "P(F | E) directa = n(E ∩ F) / n(E)", "Diferencia"),
Valor = c(f4(suma_prod), paste0(fnum(nEF), " / ", fnum(nE), " = ", f4(pFgE)),
formatC(suma_prod - pFgE, format = "e", digits = 1)))
tabla_html(verif_tp, caption = "Verificación de la ley de probabilidad total contra el cálculo directo", label = "ptotal_verif")
| Cálculo | Valor |
|---|---|
| Suma de los productos (ley de probabilidad total) | 0,1000 |
| P(F | E) directa = n(E ∩ F) / n(E) | 5.231 / 52.312 = 0,1000 |
| Diferencia | 0.0e+00 |
# niveles con al menos 30 episodios para comparar probabilidades (el resto se comenta aparte)
tp_ok <- tp[n_k >= 30]
k_aporte <- as.character(tp[which.max(f_k), sev])
k_prob <- as.character(tp_ok[which.max(p_f_s), sev])
fig_tp <- rbind(tp[n_k >= 30, .(sev, valor = p_f_s, medida = "P(F | E ∩ Sₖ): fallecimientos dentro del nivel")],
tp[n_k >= 30, .(sev, valor = aporte, medida = "% de los fallecimientos de E que aporta el nivel")])
ggplot(fig_tp, aes(x = sev, y = valor, fill = medida)) +
geom_col(position = position_dodge(width = 0.75), width = 0.7) +
geom_text(aes(label = fpct(valor, 1)), position = position_dodge(width = 0.75), vjust = -0.4, size = 3.5) +
scale_fill_manual(values = paleta[c(1, 2)], name = NULL) +
scale_y_continuous(labels = function(x) fpct(x, 0), expand = expansion(mult = c(0, 0.12))) +
labs(title = "Probabilidad de fallecimiento y aporte de fallecimientos por nivel de severidad",
subtitle = paste0("Cohorte E; se omite la categoría sin severidad registrada (", n_sin_sev_E, " episodios)"),
x = "Nivel de severidad GRD", y = NULL) +
theme(legend.position = "bottom")
Figura 2. Para cada nivel de severidad de la cohorte: probabilidad de fallecimiento dentro del nivel y participación en el total de fallecimientos de E.
Interpretación (Tabla 12, Tabla 13 y Figura 2):
RESULTADO 04
En cada aplicación se calcula la probabilidad a posteriori con la fórmula de Bayes y se verifica con el conteo directo de episodios.
P(E | F) = P(F | E) · P(E) / P(F), con P(F) = P(F | E)·P(E) + P(F | Ē)·P(Ē)
pF_total <- pFgE * pE + pFgEc * (1 - pE) # denominador por probabilidad total
pEgF_bayes <- pFgE * pE / pF
pEgF_conteo <- nEF / nF
b1 <- data.table(
Componente = c("P(F | E)", "P(E) (a priori)", "P(F | Ē)", "P(F) directa",
"P(F) por probabilidad total", "P(E | F) por Bayes (a posteriori)",
"P(E | F) por conteo directo", "Diferencia Bayes − conteo"),
`Cálculo` = c(paste0(fnum(nEF), " / ", fnum(nE)), paste0(fnum(nE), " / ", fnum(N)),
paste0(fnum(nEcF), " / ", fnum(N - nE)), paste0(fnum(nF), " / ", fnum(N)),
paste0(f4(pFgE), " × ", f4(pE), " + ", f4(pFgEc), " × ", f4(1 - pE)),
paste0(f4(pFgE), " × ", f4(pE), " / ", f4(pF)),
paste0("n(E ∩ F) / n(F) = ", fnum(nEF), " / ", fnum(nF)), "—"),
Valor = c(fpct(c(pFgE, pE, pFgEc, pF, pF_total, pEgF_bayes, pEgF_conteo)),
formatC(pEgF_bayes - pEgF_conteo, format = "e", digits = 1)))
tabla_html(b1, caption = "Teorema de Bayes, aplicación 1: fracción de los fallecimientos de Ω que tiene I50 registrada",
label = "bayes1") |> row_spec(6:7, bold = TRUE)
| Componente | Cálculo | Valor |
|---|---|---|
| P(F | E) | 5.231 / 52.312 | 10,00% |
| P(E) (a priori) | 52.312 / 873.719 | 5,99% |
| P(F | Ē) | 21.429 / 821.407 | 2,61% |
| P(F) directa | 26.660 / 873.719 | 3,05% |
| P(F) por probabilidad total | 0,1000 × 0,0599 + 0,0261 × 0,9401 | 3,05% |
| P(E | F) por Bayes (a posteriori) | 0,1000 × 0,0599 / 0,0305 | 19,62% |
| P(E | F) por conteo directo | n(E ∩ F) / n(F) = 5.231 / 26.660 | 19,62% |
| Diferencia Bayes − conteo | — | -2.8e-17 |
Interpretación (Tabla 14): la insuficiencia cardíaca está registrada en 6,0% de los egresos de Ω (a priori), pero en 19,6% de los egresos que terminan en fallecimiento (a posteriori). El conteo directo da 5.231 / 26.660 = 19,6%, igual al resultado de Bayes. Al conocer la evidencia "el episodio terminó en fallecimiento", la probabilidad sube de 6,0% a 19,6%, porque el fallecimiento es mucho más frecuente entre los episodios con I50 que en el total de Ω: la razón P(F | E) / P(F) = 3,28 es exactamente el factor por el que se multiplica la probabilidad a priori. Dicho de otro modo, aproximadamente 2 de cada 10 fallecimientos de Ω tienen I50 registrada, aunque solo 6 de cada 100 egresos la registran.
P(Sₖ | F ∩ E) = P(F | E ∩ Sₖ) · P(Sₖ | E) / Σᵢ P(F | E ∩ Sᵢ) · P(Sᵢ | E)
tp[, post_bayes := producto / sum(producto)]
tp[, post_conteo := f_k / sum(f_k)]
b2 <- tp[, .(`Nivel (Sₖ)` = as.character(sev),
`A priori P(Sₖ | E)` = fpct(p_s),
`Verosimilitud P(F | E ∩ Sₖ)` = fpct(p_f_s),
`A posteriori por Bayes` = fpct(post_bayes),
`A posteriori por conteo n(Sₖ ∩ F ∩ E) / n(F ∩ E)` = paste0(fnum(f_k), " / ", fnum(nEF), " = ", fpct(post_conteo)),
`Diferencia Bayes − conteo` = formatC(post_bayes - post_conteo, format = "e", digits = 1),
`Cambio (posteriori − priori)` = fpp(post_bayes - p_s),
Advertencia = aviso(n_k))]
tabla_html(b2, caption = paste0("Teorema de Bayes, aplicación 2: severidad a priori (sobre n(E) = ", fnum(nE),
") y a posteriori dado el fallecimiento (sobre n(F ∩ E) = ", fnum(nEF), ")"),
label = "bayes2")
| Nivel (Sₖ) | A priori P(Sₖ | E) | Verosimilitud P(F | E ∩ Sₖ) | A posteriori por Bayes | A posteriori por conteo n(Sₖ ∩ F ∩ E) / n(F ∩ E) | Diferencia Bayes − conteo | Cambio (posteriori − priori) | Advertencia |
|---|---|---|---|---|---|---|---|
| S₁ | 1,40% | 1,23% | 0,17% | 9 / 5.231 = 0,17% | 2.2e-19 | -1,23 p.p. | |
| S₂ | 37,91% | 2,03% | 7,70% | 403 / 5.231 = 7,70% | 0.0e+00 | -30,21 p.p. | |
| S₃ | 60,68% | 15,17% | 92,09% | 4.817 / 5.231 = 92,09% | 0.0e+00 | +31,40 p.p. | |
| Sin severidad registrada | 0,00% | 100,00% | 0,04% | 2 / 5.231 = 0,04% | 0.0e+00 | +0,03 p.p. | Pocos episodios (n = 2) |
k_sube <- as.character(tp[post_bayes > p_s & n_k >= 30, sev])
k_baja <- as.character(tp[post_bayes < p_s & n_k >= 30, sev])
fig_b2 <- rbind(tp[, .(sev, valor = p_s, tipo = "A priori: P(Sₖ | E)")],
tp[, .(sev, valor = post_bayes, tipo = "A posteriori: P(Sₖ | F ∩ E)")])
fig_b2[, tipo := factor(tipo, levels = c("A priori: P(Sₖ | E)", "A posteriori: P(Sₖ | F ∩ E)"))]
ggplot(fig_b2, aes(x = sev, y = valor, fill = tipo)) +
geom_col(position = position_dodge(width = 0.75), width = 0.7) +
geom_text(aes(label = fpct(valor, 1)), position = position_dodge(width = 0.75), vjust = -0.4, size = 3.4) +
scale_fill_manual(values = paleta[c(4, 3)], name = NULL) +
scale_x_discrete(labels = function(x) wrap_lbl(x, 14)) +
scale_y_continuous(labels = function(x) fpct(x, 0), expand = expansion(mult = c(0, 0.12))) +
labs(title = "Severidad a priori y a posteriori dentro de la cohorte",
x = "Nivel de severidad GRD", y = "Probabilidad") +
theme(legend.position = "bottom")
Figura 3. Distribución de la severidad en la cohorte antes (a priori) y después (a posteriori) de saber que el episodio terminó en fallecimiento.
Interpretación (Tabla 15 y Figura 3): antes de conocer el desenlace, un episodio de la cohorte tiene severidad S₃ con probabilidad 60,7%; si se sabe que terminó en fallecimiento, esa probabilidad sube a 92,1%. La probabilidad baja en S₁ y S₂ porque en esos niveles la verosimilitud P(F | E ∩ Sₖ) es menor que P(F | E) = 10,0%, y sube en S₃ porque allí es mayor. El fallecimiento es la evidencia: desplaza la probabilidad hacia los niveles donde ese desenlace es más frecuente. El conteo directo de episodios (5.231 fallecimientos de la cohorte repartidos por nivel) coincide con la fórmula en todos los niveles. La categoría sin severidad registrada (2 episodios) y el nivel S₁ se basan en muy pocos fallecimientos (2 y 9, respectivamente) y no permiten conclusiones.
P(Eₚ | L ∩ E) = P(L | Eₚ) · P(Eₚ | E) / [P(L | Eₚ)·P(Eₚ | E) + P(L | Eₛ)·P(Eₛ | E)]
pEp_E <- nEp / nE
pL_Ep <- cond(coh$L, coh$Ep)
pL_Es <- cond(coh$L, coh$Es)
pEpgL_bayes <- pL_Ep * pEp_E / (pL_Ep * pEp_E + pL_Es * (1 - pEp_E))
pEpgL_conteo <- sum(coh$Ep & coh$L) / sum(coh$L)
b3 <- data.table(
Componente = c("P(Eₚ | E) (a priori)", "P(L | Eₚ)", "P(Eₛ | E)", "P(L | Eₛ)",
"P(Eₚ | L ∩ E) por Bayes (a posteriori)", "P(Eₚ | L ∩ E) por conteo directo",
"Diferencia Bayes − conteo"),
`Cálculo` = c(paste0(fnum(nEp), " / ", fnum(nE)), paste0(fnum(sum(coh$Ep & coh$L)), " / ", fnum(nEp)),
paste0(fnum(nEs), " / ", fnum(nE)), paste0(fnum(sum(coh$Es & coh$L)), " / ", fnum(nEs)),
paste0(f4(pL_Ep), " × ", f4(pEp_E), " / (", f4(pL_Ep), " × ", f4(pEp_E), " + ", f4(pL_Es), " × ", f4(1 - pEp_E), ")"),
paste0("n(Eₚ ∩ L) / n(L ∩ E) = ", fnum(sum(coh$Ep & coh$L)), " / ", fnum(sum(coh$L))), "—"),
Valor = c(fpct(c(pEp_E, pL_Ep, 1 - pEp_E, pL_Es, pEpgL_bayes, pEpgL_conteo)),
formatC(pEpgL_bayes - pEpgL_conteo, format = "e", digits = 1)))
tabla_html(b3, caption = paste0("Teorema de Bayes, aplicación 3: probabilidad de que I50 sea el diagnóstico principal dado que el episodio de la cohorte tuvo estancia larga (más de ", corte_L, " días)"),
label = "bayes3") |> row_spec(5:6, bold = TRUE)
| Componente | Cálculo | Valor |
|---|---|---|
| P(Eₚ | E) (a priori) | 11.331 / 52.312 | 21,66% |
| P(L | Eₚ) | 4.220 / 11.331 | 37,24% |
| P(Eₛ | E) | 40.981 / 52.312 | 78,34% |
| P(L | Eₛ) | 19.162 / 40.981 | 46,76% |
| P(Eₚ | L ∩ E) por Bayes (a posteriori) | 0,3724 × 0,2166 / (0,3724 × 0,2166 + 0,4676 × 0,7834) | 18,05% |
| P(Eₚ | L ∩ E) por conteo directo | n(Eₚ ∩ L) / n(L ∩ E) = 4.220 / 23.382 | 18,05% |
| Diferencia Bayes − conteo | — | 2.8e-17 |
Interpretación (Tabla 16): en la cohorte, I50 es el diagnóstico principal en 21,7% de los episodios (a priori). Entre los episodios de la cohorte con estancia larga, esa probabilidad baja a 18,0%, y el conteo directo confirma el valor. La evidencia "estancia larga" es menos frecuente cuando I50 es el diagnóstico principal (P(L | Eₚ) = 37,2%) que cuando es solo secundario (P(L | Eₛ) = 46,8%); por eso, al observar una estancia larga, la probabilidad se desplaza hacia el rol secundario. La razón de verosimilitudes P(L | Eₚ) / P(L | Eₛ) = 0,80 resume cuánto pesa esa evidencia. Es coherente con la Actividad 1, donde la estancia mediana era mayor cuando I50 era secundaria.
res_b <- data.table(
`Aplicación` = c("1. P(E | F)", paste0("2. P(", niveles_sev, " | F ∩ E)"), "3. P(Eₚ | L ∩ E)"),
`A priori` = fpct(c(pE, tp$p_s, pEp_E)),
`A posteriori (Bayes)` = fpct(c(pEgF_bayes, tp$post_bayes, pEpgL_bayes)),
`A posteriori (conteo)` = fpct(c(pEgF_conteo, tp$post_conteo, pEpgL_conteo)),
`|Diferencia|` = formatC(abs(c(pEgF_bayes - pEgF_conteo, tp$post_bayes - tp$post_conteo,
pEpgL_bayes - pEpgL_conteo)), format = "e", digits = 1),
`Dirección` = sube_baja(c(pEgF_bayes, tp$post_bayes, pEpgL_bayes), c(pE, tp$p_s, pEp_E)))
tabla_html(res_b, caption = "Resumen de las tres aplicaciones de Bayes: a priori, a posteriori por fórmula y por conteo directo",
label = "bayes_res")
| Aplicación | A priori | A posteriori (Bayes) | A posteriori (conteo) | |Diferencia| | Dirección |
|---|---|---|---|---|---|
|
5,99% | 19,62% | 19,62% | 2.8e-17 | sube |
|
1,40% | 0,17% | 0,17% | 2.2e-19 | baja |
|
37,91% | 7,70% | 7,70% | 0.0e+00 | baja |
|
60,68% | 92,09% | 92,09% | 0.0e+00 | sube |
|
0,00% | 0,04% | 0,04% | 0.0e+00 | sube |
|
21,66% | 18,05% | 18,05% | 2.8e-17 | baja |
Tabla 17 reúne las tres aplicaciones: en todas, la fórmula de Bayes y el conteo directo coinciden hasta el error de redondeo de la máquina.
RESULTADO 05
esp_M <- c("MEDICINA INTERNA", "CARDIOLOGÍA", "GERIATRÍA")
omega[, M := ESPECIALIDAD_MEDICA %in% esp_M & edad >= 65]
# candidatos evaluados antes de elegir M (todos con variables que no son diagnósticos)
eval_marcador <- function(m, nombre) {
se <- cond(m, omega$E); sp <- cond(!m, !omega$E)
data.table(Marcador = nombre, `n(M)` = fnum(sum(m)), Sensibilidad = fpct(se, 1),
Especificidad = fpct(sp, 1), VPP = fpct(cond(omega$E, m), 1))
}
cand_M <- rbind(
eval_marcador(omega$ESPECIALIDAD_MEDICA == "CARDIOLOGÍA", "Especialidad = Cardiología"),
eval_marcador(omega$ESPECIALIDAD_MEDICA %in% c("MEDICINA INTERNA", "CARDIOLOGÍA"), "Especialidad ∈ {Medicina interna, Cardiología}"),
eval_marcador(omega$edad >= 65, "Edad ≥ 65 años"),
eval_marcador(omega$M, "M elegido: especialidad ∈ {Medicina interna, Cardiología, Geriatría} y edad ≥ 65"))
tabla_html(cand_M, caption = paste0("Marcadores candidatos evaluados sobre Ω (sensibilidad sobre n(E) = ", fnum(nE),
"; especificidad sobre n(Ē) = ", fnum(N - nE), "; VPP sobre n(M))"),
label = "candM") |> row_spec(4, bold = TRUE)
| Marcador | n(M) | Sensibilidad | Especificidad | VPP |
|---|---|---|---|---|
| Especialidad = Cardiología | 24.571 | 14,5% | 97,9% | 30,8% |
| Especialidad ∈ {Medicina interna, Cardiología} | 179.764 | 66,7% | 82,4% | 19,4% |
| Edad ≥ 65 años | 242.687 | 73,0% | 75,1% | 15,7% |
| M elegido: especialidad ∈ {Medicina interna, Cardiología, Geriatría} y edad ≥ 65 | 98.239 | 49,9% | 91,2% | 26,6% |
M = el episodio está a cargo de la especialidad médica
Medicina interna, Cardiología o Geriatría
(ESPECIALIDAD_MEDICA) y la edad al ingreso es de 65 años o
más.
Se eligió por tres razones:
ESPECIALIDAD_MEDICA es
un campo administrativo del episodio y la edad se calcula con las fechas
de nacimiento e ingreso. Ninguno se construye a partir de los campos de
diagnóstico que definen E, a diferencia del GRD o de la categoría
diagnóstica mayor.M se eligió mirando estos mismos datos, por lo que su desempeño aquí es una descripción optimista. Esto se retoma en las limitaciones.
nME <- sum(omega$M & omega$E); nMEc <- sum(omega$M & !omega$E)
nMcE <- sum(!omega$M & omega$E); nMcEc <- sum(!omega$M & !omega$E)
nM <- nME + nMEc
t22 <- data.table(` ` = c("M (marcador positivo)", "M̄ (marcador negativo)", "Total"),
`E (con I50)` = fnum(c(nME, nMcE, nE)),
`Ē (sin I50)` = fnum(c(nMEc, nMcEc, N - nE)),
Total = fnum(c(nM, N - nM, N)))
tabla_html(t22, caption = paste0("Tabla 2 × 2 del marcador M contra el evento E, sobre Ω (N = ", fnum(N), ")"),
label = "t22") |> column_spec(1, bold = TRUE) |> row_spec(3, bold = TRUE)
| E (con I50) | Ē (sin I50) | Total | |
|---|---|---|---|
| M (marcador positivo) | 26.127 | 72.112 | 98.239 |
| M̄ (marcador negativo) | 26.185 | 749.295 | 775.480 |
| Total | 52.312 | 821.407 | 873.719 |
sens <- nME / nE # P(M | E)
espec <- nMcEc / (N - nE) # P(M̄ | Ē)
vpp_fun <- function(p, se, sp) se * p / (se * p + (1 - sp) * (1 - p))
vpn_fun <- function(p, se, sp) sp * (1 - p) / (sp * (1 - p) + (1 - se) * p)
vpp_bayes <- vpp_fun(pE, sens, espec); vpp_tabla <- nME / nM
vpn_bayes <- vpn_fun(pE, sens, espec); vpn_tabla <- nMcEc / (N - nM)
met <- data.table(
Medida = c("Sensibilidad P(M | E)", "Especificidad P(M̄ | Ē)", "Proporción de la enfermedad en Ω, P(E)",
"VPP P(E | M)", "VPN P(Ē | M̄)"),
`Por Bayes` = c("—", "—", "—",
paste0(f4(sens), " × ", f4(pE), " / (", f4(sens), " × ", f4(pE), " + ", f4(1 - espec), " × ", f4(1 - pE), ") = ", fpct(vpp_bayes)),
paste0(f4(espec), " × ", f4(1 - pE), " / (", f4(espec), " × ", f4(1 - pE), " + ", f4(1 - sens), " × ", f4(pE), ") = ", fpct(vpn_bayes))),
`Por conteo en la tabla 2 × 2` = c(paste0(fnum(nME), " / ", fnum(nE), " = ", fpct(sens)),
paste0(fnum(nMcEc), " / ", fnum(N - nE), " = ", fpct(espec)),
paste0(fnum(nE), " / ", fnum(N), " = ", fpct(pE)),
paste0(fnum(nME), " / ", fnum(nM), " = ", fpct(vpp_tabla)),
paste0(fnum(nMcEc), " / ", fnum(N - nM), " = ", fpct(vpn_tabla))),
`Diferencia` = c("—", "—", "—", formatC(vpp_bayes - vpp_tabla, format = "e", digits = 1),
formatC(vpn_bayes - vpn_tabla, format = "e", digits = 1)))
tabla_html(met, caption = "Sensibilidad, especificidad y valores predictivos del marcador M, por Bayes y por conteo en la tabla 2 × 2",
label = "metM") |> column_spec(2, width = "38%")
| Medida | Por Bayes | Por conteo en la tabla 2 × 2 | Diferencia |
|---|---|---|---|
| Sensibilidad P(M | E) | — | 26.127 / 52.312 = 49,94% | — |
| Especificidad P(M̄ | Ē) | — | 749.295 / 821.407 = 91,22% | — |
| Proporción de la enfermedad en Ω, P(E) | — | 52.312 / 873.719 = 5,99% | — |
| VPP P(E | M) | 0,4994 × 0,0599 / (0,4994 × 0,0599 + 0,0878 × 0,9401) = 26,60% | 26.127 / 98.239 = 26,60% | 1.1e-16 |
| VPN P(Ē | M̄) | 0,9122 × 0,9401 / (0,9122 × 0,9401 + 0,5006 × 0,0599) = 96,62% | 749.295 / 775.480 = 96,62% | 0.0e+00 |
Interpretación (Tabla 19 y Tabla 20): M marca a 49,9% de los episodios con I50 (sensibilidad) y deja sin marcar a 91,2% de los episodios sin I50 (especificidad). Aun así, de los 98.239 episodios marcados por M solo 26,6% tiene I50 registrada (VPP): de cada 4 episodios marcados, aproximadamente 3 no tienen la enfermedad. Esto ocurre porque E es poco frecuente en Ω (P(E) = 6,0%): aunque solo 8,8% de los episodios sin I50 queda marcado, esos episodios son tantos (72.112) que superan a los verdaderos positivos (26.127). El VPN es alto (96,6%), pero se acerca a 1 − P(E) = 94,0%, el valor que se obtendría sin usar ningún marcador. Bayes y el conteo en la tabla coinciden en ambos valores predictivos.
El VPP depende de P(E). Si la sensibilidad y la especificidad de M se mantuvieran fijas, el mismo marcador tendría un VPP distinto en cada establecimiento. Se marcan los establecimientos con mayor y menor peso relativo de la insuficiencia cardíaca en su actividad, con el mismo criterio de la Actividad 1: al menos 500 egresos hospitalarios y al menos un episodio con I50.
hosp <- suppressMessages(as.data.table(read_excel("Tablas_maestras_GRD.xlsx", sheet = "Hospitales")))
setnames(hosp, c("cod_hospital", "nombre_hospital"))
hosp[, cod_hospital := as.character(as.integer(cod_hospital))]
peso_hosp <- omega[, .(total = .N, nE_h = sum(E), nM_h = sum(M), nEM_h = sum(E & M)), by = COD_HOSPITAL]
peso_hosp <- peso_hosp[total >= 500 & nE_h > 0]
peso_hosp[, pE_h := nE_h / total]
peso_hosp <- merge(peso_hosp, hosp, by.x = "COD_HOSPITAL", by.y = "cod_hospital", all.x = TRUE)
peso_hosp[is.na(nombre_hospital), nombre_hospital := paste0("Cód. ", COD_HOSPITAL)]
h_max <- peso_hosp[which.max(pE_h)]; h_min <- peso_hosp[which.min(pE_h)]
puntos <- data.table(
Referencia = c(paste0("Mayor peso relativo: ", h_max$nombre_hospital),
"Ω completo (todos los establecimientos)",
paste0("Menor peso relativo: ", h_min$nombre_hospital)),
corto = c("Mayor peso relativo", "Ω completo", "Menor peso relativo"),
egresos = c(h_max$total, N, h_min$total),
p = c(h_max$pE_h, pE, h_min$pE_h),
nM_ref = c(h_max$nM_h, nM, h_min$nM_h),
nEM_ref = c(h_max$nEM_h, nME, h_min$nEM_h))
puntos[, vpp_curva := vpp_fun(p, sens, espec)]
puntos[, vpp_obs := ifelse(nM_ref > 0, nEM_ref / nM_ref, NA_real_)]
tabla_html(puntos[, .(Referencia, `Egresos (denominador)` = fnum(egresos), `P(E) en la referencia` = fpct(p),
`VPP con sensibilidad y especificidad de Ω` = fpct(vpp_curva, 1),
`VPP observado en la referencia` = ifelse(is.na(vpp_obs), "—", paste0(fpct(vpp_obs, 1), " (", fnum(nEM_ref), " / ", fnum(nM_ref), ")")))],
caption = paste0("VPP de M en los establecimientos de mayor y menor peso relativo de I50 (mínimo 500 egresos, ", nrow(peso_hosp), " establecimientos comparados)"),
label = "vpp_hosp")
| Referencia | Egresos (denominador) | P(E) en la referencia | VPP con sensibilidad y especificidad de Ω | VPP observado en la referencia |
|---|---|---|---|---|
| Mayor peso relativo: Instituto Nacional de Enfermedades Respiratorias y Cirugía Torácica | 3.951 | 18,15% | 55,8% | 30,6% (196 / 641) |
| Ω completo (todos los establecimientos) | 873.719 | 5,99% | 26,6% | 26,6% (26.127 / 98.239) |
| Menor peso relativo: Hospital Dr. Exequiel González Cortés (Santiago, San Miguel) | 8.011 | 0,32% | 1,8% | — |
curva <- data.table(p = seq(0.001, max(0.30, h_max$pE_h * 1.4), length.out = 500))
curva[, vpp := vpp_fun(p, sens, espec)]
ggplot(curva, aes(x = p, y = vpp)) +
geom_line(color = paleta[3], linewidth = 1.1) +
geom_segment(data = puntos, aes(x = p, xend = p, y = 0, yend = vpp_curva), linetype = "dotted", color = "grey45") +
geom_point(data = puntos, aes(y = vpp_curva, color = corto), size = 3.6) +
geom_point(data = puntos[!is.na(vpp_obs)], aes(y = vpp_obs, color = corto), shape = 5, size = 3.4, stroke = 1.2) +
geom_text(data = puntos[corto != "Menor peso relativo"],
aes(y = vpp_curva, label = paste0(corto, "\nP(E) = ", fpct(p, 1), " · VPP = ", fpct(vpp_curva, 1)), color = corto),
hjust = -0.06, vjust = 1.15, size = 3.2, lineheight = 0.95, show.legend = FALSE) +
geom_text(data = puntos[corto == "Menor peso relativo"],
aes(y = vpp_curva, label = paste0(corto, ": P(E) = ", fpct(p, 2), " · VPP = ", fpct(vpp_curva, 1)), color = corto),
hjust = -0.08, vjust = 0.5, nudge_x = 0.004, size = 3.2, show.legend = FALSE) +
scale_color_manual(values = c("Mayor peso relativo" = paleta[2], "Ω completo" = paleta[1], "Menor peso relativo" = paleta[6]), name = NULL) +
scale_x_continuous(labels = function(x) fpct(x, 0)) +
scale_y_continuous(labels = function(x) fpct(x, 0), limits = c(0, 1)) +
labs(title = "Valor predictivo positivo del marcador M según la proporción de la enfermedad",
subtitle = paste0("Sensibilidad = ", fpct(sens, 1), " y especificidad = ", fpct(espec, 1), " fijas (valores de Ω)"),
x = "P(E): proporción de episodios con I50 en el conjunto de referencia", y = "VPP = P(E | M)") +
theme(legend.position = "bottom")
Figura 4. VPP del marcador M en función de P(E), con la sensibilidad y la especificidad de Ω fijas. Los puntos llenos están sobre la curva; los rombos son el VPP observado en cada referencia.
Interpretación (Tabla 21 y Figura 4): con la sensibilidad y la especificidad fijas, el VPP crece con P(E). En Instituto Nacional de Enfermedades Respiratorias y Cirugía Torácica, donde I50 aparece en 18,1% de los egresos, el marcador tendría un VPP de 55,8%. En Hospital Dr. Exequiel González Cortés (Santiago, San Miguel), donde aparece en solo 0,32%, el VPP caería a 1,8%. El mismo marcador, con el mismo desempeño frente a E, resulta mucho menos útil donde la enfermedad tiene poco peso.
Los VPP observados (rombos) muestran además que la sensibilidad y la especificidad no son iguales en todos los establecimientos, porque la composición por especialidad y edad de cada uno es distinta. En el establecimiento de mayor peso relativo el VPP observado es 30,6% (196 de 641 episodios marcados), menor que el 55,8% que indica la curva. En el de menor peso relativo el VPP observado no se puede calcular: ninguno de sus 8.011 egresos cumple M (n(M) = 0), lo que es esperable en un establecimiento cuya actividad casi no incluye episodios de 65 años o más. Sus 26 episodios con I50 quedan todos sin marcar, es decir, allí la sensibilidad de M es 0%. La curva sirve para mostrar el efecto de P(E) sobre el VPP, pero no predice con exactitud el VPP de cada establecimiento.
RESULTADO 06
La jefatura trabaja a veces con muestras de episodios. Se simula esa situación: para cada tamaño n = 100, 500, 1.000, 5.000 y 20.000 se extraen B = 1.000 muestras aleatorias sin reposición de Ω y en cada una se estima P(E | F) con Bayes, usando solo las frecuencias de esa muestra: P̂(E | F) = P̂(F | E) · P̂(E) / P̂(F). La estimación no se puede calcular cuando la muestra no tiene fallecimientos (P̂(F) = 0). Si la muestra no tiene episodios con I50, P̂(F | E) no está definida, pero el numerador P̂(F | E) · P̂(E) = P̂(E ∩ F) vale 0 y la estimación es 0.
set.seed(20261009) # semilla fija: mismos resultados en cada compilación
B <- 1000
tamanos <- c(100, 500, 1000, 5000, 20000)
vE <- omega$E; vF <- omega$Fal
sim <- rbindlist(lapply(tamanos, function(n) {
r <- t(replicate(B, {
idx <- sample.int(N, n) # muestra sin reposición de Ω
c(nE = sum(vE[idx]), nF = sum(vF[idx]), nEF = sum(vE[idx] & vF[idx]))
}))
data.table(n = n, b = seq_len(B), r)
}))
sim[, `:=`(pE_m = nE / n, pF_m = nF / n, pFgE_m = ifelse(nE > 0, nEF / nE, NA_real_))]
sim[, est := fifelse(nF == 0, NA_real_, # sin fallecimientos: no calculable
fifelse(nE == 0, 0, pFgE_m * pE_m / pF_m))] # Bayes con frecuencias de la muestra
valor_omega <- pEgF_conteo
res_sim <- sim[, .(fallec_prom = mean(nF),
pct_na = mean(is.na(est)),
mediana = median(est, na.rm = TRUE),
q1 = quantile(est, 0.25, na.rm = TRUE),
q3 = quantile(est, 0.75, na.rm = TRUE),
p05 = quantile(est, 0.05, na.rm = TRUE),
p95 = quantile(est, 0.95, na.rm = TRUE),
cerca = mean(abs(est - valor_omega) <= 0.05, na.rm = TRUE)), by = n]
res_sim[, ric := q3 - q1]
# fracción de estimaciones exactamente 0 con n = 100 (ningún fallecimiento de la muestra con I50)
cero_100 <- sim[n == 100 & !is.na(est), mean(est == 0)]
tabla_html(res_sim[, .(`Tamaño de muestra n` = fnum(n),
`Fallecimientos por muestra (promedio)` = fnum(fallec_prom, 1),
`% de muestras sin fallecimientos (no calculable)` = fpct(pct_na, 1),
`Mediana de P̂(E | F)` = fpct(mediana, 1),
`Percentil 25` = fpct(q1, 1), `Percentil 75` = fpct(q3, 1),
`Rango intercuartílico` = fpp_abs(ric, 1),
`Rango 5%-95%` = paste0(fpct(p05, 1), " – ", fpct(p95, 1)),
`% de estimaciones a ±5 p.p. del valor de Ω` = fpct(cerca, 1))],
caption = paste0("Resumen de las B = 1.000 estimaciones de P(E | F) por tamaño de muestra. Valor sobre toda Ω: ", fpct(valor_omega),
". Mediana, cuartiles y % a ±5 p.p. se calculan sobre las muestras donde la estimación es calculable."),
label = "sim")
| Tamaño de muestra n | Fallecimientos por muestra (promedio) | % de muestras sin fallecimientos (no calculable) | Mediana de P̂(E | F) | Percentil 25 | Percentil 75 | Rango intercuartílico | Rango 5%-95% | % de estimaciones a ±5 p.p. del valor de Ω |
|---|---|---|---|---|---|---|---|---|
| 100 | 3,0 | 5,5% | 0,0% | 0,0% | 33,3% | 33,3 p.p. | 0,0% – 75,0% | 6,5% |
| 500 | 15,4 | 0,0% | 20,0% | 12,5% | 26,3% | 13,8 p.p. | 0,0% – 38,9% | 34,3% |
| 1.000 | 30,5 | 0,0% | 18,8% | 13,8% | 24,0% | 10,2 p.p. | 7,9% – 31,3% | 50,2% |
| 5.000 | 152,6 | 0,0% | 19,5% | 17,5% | 21,7% | 4,2 p.p. | 14,6% – 24,8% | 88,9% |
| 20.000 | 609,7 | 0,0% | 19,6% | 18,5% | 20,7% | 2,2 p.p. | 17,0% – 22,3% | 100,0% |
sim_ok <- sim[!is.na(est)]
sim_ok[, n_f := factor(fnum(n), levels = fnum(tamanos))]
ggplot(sim_ok, aes(x = n_f, y = est)) +
geom_violin(fill = paleta[4], color = NA, alpha = 0.6, scale = "width", adjust = 1.2) +
geom_boxplot(width = 0.16, outlier.size = 0.5, outlier.alpha = 0.3, fill = "white", color = paleta[3]) +
geom_hline(yintercept = valor_omega, linetype = "dashed", color = paleta[2], linewidth = 1) +
annotate("text", x = 5.45, y = valor_omega, label = paste0("Ω: ", fpct(valor_omega, 1)),
vjust = -0.6, hjust = 1, color = paleta[2], size = 3.7) +
scale_y_continuous(labels = function(x) fpct(x, 0), breaks = seq(0, 1, 0.1)) +
labs(title = "Estimaciones de P(E | F) por Bayes en muestras de episodios",
subtitle = "1.000 muestras sin reposición de Ω por cada tamaño n; se omiten las muestras sin fallecimientos",
x = "Tamaño de muestra n (episodios)", y = "Estimación de P(E | F)")
Figura 5. Distribución de las 1.000 estimaciones de P(E | F) para cada tamaño de muestra; la línea discontinua marca el valor calculado sobre toda Ω.
Interpretación (Tabla 22 y Figura 5):
RESULTADO 07
s3_prior <- tp[sev == "S₃", p_s]; s3_post <- tp[sev == "S₃", post_bayes]
No, no sirve para identificar episodios uno a uno. Su valor predictivo positivo es 26,6% (Tabla 20): de cada 100 episodios que M marca, solo unos 27 tienen I50 registrada, y los demás 73 no. Además, M deja sin marcar a 50,1% de los episodios con I50. En los establecimientos donde la enfermedad tiene poco peso el VPP cae aún más: según la curva de Figura 4, sería 1,8% en Hospital Dr. Exequiel González Cortés (Santiago, San Miguel). M puede servir como filtro previo para priorizar qué episodios revisar, porque concentra la enfermedad (VPP 4,4 veces P(E)). Para identificar episodios con insuficiencia cardíaca sigue siendo necesario revisar los campos de diagnóstico.
GRD_PUBLICO_2024.txt, descargado el 21 de agosto de
2026.Tablas_maestras_GRD.xlsx.CIE-10.xlsx.