Primeros pasos con ciecl: un reporte de egresos hospitalarios

¿Para quién es esta guía?

Imagina que trabajas en la unidad de estadística de un hospital y cada mes eres la persona encargada de elaborar el reporte de egresos por diabetes para la dirección del servicio. Recibes la base de egresos hospitalarios, y tu objetivo es responder preguntas concretas: ¿cuántos egresos tuvieron como diagnóstico principal una diabetes?, ¿de qué tipo?, ¿qué tan complejos eran esos pacientes?

El problema es que la base llega con códigos CIE-10 en formatos inconsistentes y sin descripciones: para interpretarlos tendrías que consultar a mano el catálogo oficial en PDF o Excel. ciecl elimina ese paso: incorpora el catálogo oficial CIE-10 de Chile (MINSAL/DEIS v2018) dentro de R y te permite normalizar, describir, buscar y analizar los códigos directamente sobre tu base.

Esta guía recorre ese flujo completo, de lo básico a lo avanzado. Solo necesitas conocimientos básicos de R; si además usas dplyr, los ejemplos encajan directo en tus pipelines.

Los datos: egresos hospitalarios del DEIS

Las bases de Egresos Hospitalarios las publica el Departamento de Estadísticas e Información de Salud (DEIS) del Ministerio de Salud de Chile. Cada fila es un alta hospitalaria y la columna DIAG1 contiene el diagnóstico principal codificado en CIE-10.

En la práctica, estos archivos llegan con dos variaciones de formato muy comunes:

  1. Formatos compactos: códigos sin punto decimal (ej: J189 en lugar de J18.9).
  2. Sufijos de relleno: una letra X para completar la longitud del campo en categorías de 3 dígitos (ej: I10X para hipertensión esencial).

Generemos un conjunto de datos sintético que replica la estructura y las anomalías típicas de los archivos del DEIS:

set.seed(42)

# Simulación de 200 registros con formatos típicos del DEIS Chile
egresos <- data.frame(
  ID_EGRESO = 1:200,
  PACIENTE_ID = sample(1:50, 200, replace = TRUE),
  ANO       = sample(2018:2022, 200, replace = TRUE),
  DIAG1     = sample(
    c(
      "J189", "O800", "Z380", "K359", "N390",
      "I10X", "J449", "E119", "O829", "J069",
      "K922", "N185", "I509", "C509", "A099",
      "N40X", "K800", "I259", "J180", "E149"
    ),
    size    = 200,
    replace = TRUE
  ),
  stringsAsFactors = FALSE
)

head(egresos)
#>   ID_EGRESO PACIENTE_ID  ANO DIAG1
#> 1         1          49 2018  J189
#> 2         2          37 2022  E119
#> 3         3           1 2021  E149
#> 4         4          25 2018  N390
#> 5         5          10 2022  I10X
#> 6         6          36 2021  C509

Paso 1: Normalizar los códigos con cie_norm()

Antes de cualquier análisis hay que estandarizar DIAG1. cie_norm() aplica las reglas de codificación oficial del MINSAL de forma vectorizada: elimina la X de relleno, inserta el punto decimal en la posición correcta y limpia espacios, guiones y símbolos especiales (como † o *).

# Limpieza y estandarización de diagnósticos en el flujo de trabajo
egresos <- egresos |>
  mutate(
    DIAG1_NORM = cie_norm(codes = DIAG1)
  )

# Comparación entre formato original y normalizado
egresos |>
  select(DIAG1, DIAG1_NORM) |>
  distinct() |>
  head(5)
#>   DIAG1 DIAG1_NORM
#> 1  J189      J18.9
#> 2  E119      E11.9
#> 3  E149      E14.9
#> 4  N390      N39.0
#> 5  I10X        I10

Con esto, I10X quedó como I10 y J189 como J18.9: los códigos ya son comparables con el catálogo oficial.

Paso 2: Agregar las descripciones oficiales con cie_describe()

Para el reporte necesitas las glosas clínicas, no solo los códigos. cie_describe() devuelve un vector de texto con una descripción por cada código, así que puedes agregarlo como una columna más de tu tabla con mutate(), sin pasos intermedios:

# Integración directa de descripciones al dataframe principal
egresos_full <- egresos |>
  mutate(
    descripcion = cie_describe(DIAG1_NORM)
  )

head(egresos_full |> select(ID_EGRESO, DIAG1, descripcion))
#>   ID_EGRESO DIAG1
#> 1         1  J189
#> 2         2  E119
#> 3         3  E149
#> 4         4  N390
#> 5         5  I10X
#> 6         6  C509
#>                                                       descripcion
#> 1                                       Neumonía, no especificada
#> 2                     Diabetes mellitus tipo 2 sin complicaciones
#> 3 Diabetes mellitus, no especificada, sin mención de complicación
#> 4              Infección de vías urinarias, sitio no especificado
#> 5                                Hipertensión esencial (primaria)
#> 6                 Tumor maligno de la mama, parte no especificada

Si además de la glosa necesitas la metadata completa (capítulo, grupo, notas de inclusión/exclusión), usa cie_lookup(), que devuelve un tibble estructurado listo para un left_join():

# Obtención de metadata completa vía lookup + join
metadata <- cie_lookup(
  code = unique(egresos$DIAG1_NORM),
  full_description = TRUE
)
#> ✖ Códigos no encontrados: "K35.9"

egresos_metadata <- egresos |>
  left_join(metadata, by = c("DIAG1_NORM" = "codigo"))

Cuando la búsqueda no entrega resultados

Es normal que algunas consultas no encuentren nada, y conviene saber cómo se comporta el paquete en esos casos: las funciones nunca fallan con un error por ausencia de resultados; devuelven un tibble vacío con la estructura de columnas correcta y un mensaje informativo.

Si buscas un código que no existe en el catálogo:

cie_lookup("XYZ123")
#> ✖ Código no encontrado: "XYZ123"
#> # A tibble: 0 × 11
#> # ℹ 11 variables: codigo <chr>, descripcion <chr>, categoria <chr>,
#> #   seccion <chr>, capitulo_nombre <chr>, inclusion <chr>, exclusion <chr>,
#> #   capitulo <chr>, es_daga <lgl>, es_cruz <lgl>, uso_cl <chr>

Si el umbral de cie_search() es demasiado estricto para el término ingresado:

cie_search("zzzqwerty", threshold = 0.95)
#> ✖ Sin coincidencias >= threshold 0.95
#> # A tibble: 0 × 4
#> # ℹ 4 variables: codigo <chr>, descripcion <chr>, score <dbl>, categoria <chr>

En ambos casos el flujo no se interrumpe: puedes verificar nrow(resultado) == 0 y reaccionar (bajar el threshold, revisar la ortografía o validar el código). Para chequear rápidamente qué códigos de un vector son válidos según el catálogo, usa cie_validate_vector():

cie_validate_vector(c("E11.0", "XYZ123", "I10X"))
#> [1]  TRUE FALSE  TRUE

Paso 4: Estratificar riesgo con cie_comorbid()

El último nivel del reporte es la complejidad de los pacientes. cie_comorbid() mapea los diagnósticos a los índices de Charlson o Elixhauser y devuelve una matriz de comorbilidades por paciente, lista para modelos estadísticos:

# Requiere el paquete 'comorbidity' instalado
# Cálculo del Índice de Charlson consolidado por paciente
comorbilidades <- cie_comorbid(
  data = egresos,
  id = "PACIENTE_ID",
  code = "DIAG1",
  map = "charlson"
)

head(comorbilidades, 10)
#> # A tibble: 10 × 19
#>    PACIENTE_ID    mi   chf   pvd  cevd dementia   cpd rheumd   pud   mld  diab
#>          <int> <int> <int> <int> <int>    <int> <int>  <int> <int> <int> <int>
#>  1           1     0     0     0     0        0     0      0     0     0     1
#>  2           2     0     0     0     0        0     0      0     0     0     0
#>  3           3     0     0     0     0        0     0      0     0     0     1
#>  4           4     0     1     0     0        0     1      0     0     0     0
#>  5           5     0     1     0     0        0     0      0     0     0     1
#>  6           6     0     0     0     0        0     1      0     0     0     1
#>  7           7     0     0     0     0        0     0      0     0     0     0
#>  8           8     0     0     0     0        0     0      0     0     0     1
#>  9           9     0     0     0     0        0     1      0     0     0     0
#> 10          10     0     0     0     0        0     0      0     0     0     1
#> # ℹ 8 more variables: diabwc <int>, hp <int>, rend <int>, canc <int>,
#> #   msld <int>, metacanc <int>, aids <int>, score_charlson <dbl>

Resumen del flujo

El recorrido de esta guía cubre el ciclo completo desde la base cruda hasta el insumo analítico:

  1. Estandarización: corrección de formatos con cie_norm().
  2. Contextualización: glosas oficiales con cie_describe() y metadata con cie_lookup().
  3. Exploración: búsqueda de códigos por texto con cie_search(), tolerante a errores y con comportamiento predecible cuando no hay resultados.
  4. Agregación: índices de comorbilidad con cie_comorbid().

¿No sabes cuál función usar en otro escenario? Ejecuta cie_guide() para ver una tabla comparativa con la función recomendada y un ejemplo por caso.

Para seguir aprendiendo


Fuente de datos: Esta herramienta utiliza el catálogo CIE-10 oficial para Chile, gestionado por el DEIS del Ministerio de Salud. Más detalles en deis.minsal.cl.