Las tasas crudas y ajustadas de mortalidad son dos de los indicadores más utilizados en epidemiología. Sirven para hacer comparaciones entre diferentes poblaciones y períodos de tiempo.
El procedimiento para el cálculo de tasas de mortalidad es sencillo, sin embargo, al tener denominador y numerador fuentes de información distintas, requiere habitualmente el cumplimiento de ciertos pasos: obtención de la información, adaptación de los formatos, homologación de categorías, etc. Estas tareas suelen ser tediosas y aumentan la probabilidad de cometer errores. Por otro lado, cuando los cálculos deben hacerse para múltiples áreas geográficas o períodos de tiempo, suelen ser poco eficientes.
El objetivo de este documento es presentar una forma programática en R (R Core Team 2019) para el cálculo de tasas de mortalidad por año, jurisdicción y sexo para Argentina en el período 2010-2021.
Para el desarrollo de esta actividad se utilizarán las librerías dplyr (Wickham et al. 2023),epitools (Aragon 2020),readr (Wickham, Hester, and Bryan 2022) y DT (Xie, Cheng, and Tan 2023).
En el portal de Datos Abiertos se encuentra disponible un dataset de defunciones ocurridas y registradas en Argentina para el período 2005-2021. En este archivo las muertes están clasificadas por una serie de variables y en la columna “cantidad” presenta una cuenta de defunciones para la combinación de categorías de cada fila.
Descargamos el archivo y creamos el data frame “defunciones”.
library(dplyr)
options(timeout=1000000) # incrementamos el timeout debido a que la descarga es lenta
url = "http://datos.salud.gob.ar/dataset/27c588e8-43d0-411a-a40c-7ecc563c2c9f/resource/fab9e990-865c-43c4-a643-3dbc3b70a934/download/defunciones-ocurridas-y-registradas-en-la-republica-argentina-anos-2005-2021.csv"
download.file(url, destfile = "defunciones.csv")
defunciones = read.csv("defunciones.csv", encoding = "latin1")
unlink("defunciones.csv")
El archivo de defunciones tiene 778.353 registros. Debido a que vamos a utilizar sólo el período 2010-2021, eliminamos los años anteriores.
defunciones = defunciones[defunciones$anio >= 2010,]
# observamos la estructura del data frame
str(defunciones)
## 'data.frame': 558016 obs. of 11 variables:
## $ anio : int 2014 2016 2012 2021 2016 2017 2013 2014 2014 2017 ...
## $ jurisdiccion_de_residencia_id: int 34 94 90 62 14 86 2 78 58 54 ...
## $ jurisdicion_residencia_nombre: chr "Formosa" "Tierra del Fuego, Antártida e Islas del Atlántico Sur" "Tucumán" "Río Negro" ...
## $ cie10_causa_id : chr "P22" "J18" "P91" "P22" ...
## $ cie10_clasificacion : chr "Dificultad respiratoria del recién nacido" "Neumonía, organismo no especificado" "Otras alteraciones cerebrales del recién nacido" "Dificultad respiratoria del recién nacido" ...
## $ sexo_id : int 1 1 1 2 1 1 1 1 2 1 ...
## $ Sexo : chr "masculino" "masculino" "masculino" "femenino" ...
## $ muerte_materna_id : chr "" NA "" NA ...
## $ muerte_materna_clasificacion : chr NA NA NA NA ...
## $ grupo_edad : chr "01.De a 0 a 14 anios" "01.De a 0 a 14 anios" "01.De a 0 a 14 anios" "01.De a 0 a 14 anios" ...
## $ cantidad : int 22 1 1 1 1 1 1 2 2 1 ...
# eliminamos las variables cie10_causa_id, muerte_materna_id y muerte_materna_clasificacion que no vamos a usar
defunciones$cie10_causa_id = NULL
defunciones$cie10_clasificacion = NULL
defunciones$muerte_materna_id = NULL
defunciones$muerte_materna_clasificacion = NULL
Podemos observar que en este archivo las edades están agrupadas de en grupos amplios que no coinciden con los que utiliza generalmente el INDEC (quinquenales).
Si observamos el documento “Procesamiento de proyecciones de población de Argentina 2010-2040 (INDEC)”), podemos ver que los grupos utilizados en las proyecciones de población son quinquenales, finalizando en el grupo “100 y más”.
Observamos los grupos etarios del archivo de defunciones:
unique(defunciones$grupo_edad)
## [1] "01.De a 0 a 14 anios" "02.De 15 a 34 anios" "03.De 35 a 54 anios"
## [4] "04.De 55 a 74 anios" "05.De 75 anios y mas" "06.Sin especificar"
Constatamos que son diferentes, por lo que tendremos que reagrupar las edades del archivo de población.
En primer lugar vamos a descargar las proyecciones con el procesamiento realizado en el ejercicio anterior. El archivo resultante está alojado en el repositorio de GitHub, por lo que podemos descargarlo.
library(readr)
url = "https://raw.githubusercontent.com/agsantoro/VisualizacionDatos2023/refs/heads/main/poblacion_prov.csv"
download.file(url,dest="poblacion.csv")
poblacion = read_csv("poblacion.csv") %>% as.data.frame()
Observamos los grupos de edad de ambos archivos y reagrupamos las edades en el de población.
unique(poblacion$edad)
## [1] "0-4" "5-9" "10-14" "15-19" "20-24" "25-29"
## [7] "30-34" "35-39" "40-44" "45-49" "50-54" "55-59"
## [13] "60-64" "65-69" "70-74" "75-79" "80-84" "85-89"
## [19] "90-94" "95-99" "100 y más"
unique(defunciones$grupo_edad)
## [1] "01.De a 0 a 14 anios" "02.De 15 a 34 anios" "03.De 35 a 54 anios"
## [4] "04.De 55 a 74 anios" "05.De 75 anios y mas" "06.Sin especificar"
grupos = unique(poblacion$edad)
poblacion$edad[poblacion$edad %in% grupos[1:3]] = "01.De a 0 a 14 anios"
poblacion$edad[poblacion$edad %in% grupos[4:7]] = "02.De 15 a 34 anios"
poblacion$edad[poblacion$edad %in% grupos[8:11]] = "03.De 35 a 54 anios"
poblacion$edad[poblacion$edad %in% grupos[12:15]] = "04.De 55 a 74 anios"
poblacion$edad[poblacion$edad %in% grupos[16:21]] = "05.De 75 anios y mas"
Comprobamos que tengamos la misma clasificación en ambos archivos:
unique(poblacion$edad)
## [1] "01.De a 0 a 14 anios" "02.De 15 a 34 anios" "03.De 35 a 54 anios"
## [4] "04.De 55 a 74 anios" "05.De 75 anios y mas"
unique(defunciones$grupo_edad)
## [1] "01.De a 0 a 14 anios" "02.De 15 a 34 anios" "03.De 35 a 54 anios"
## [4] "04.De 55 a 74 anios" "05.De 75 anios y mas" "06.Sin especificar"
La única diferencia observada es que en el archivo de defunciones tenemos muertes de edad sin especificar, mientras que en las proyecciones de población naturalmente esta categoría no existe.
Sumarizamos el dataset de poblaciones que reducir las filas
poblacion = poblacion %>% group_by(ano,juri,juri_nombre,sexo_codigo,sexo_nombre,edad) %>% summarise(poblacion=sum(poblacion))
colnames(poblacion)
## [1] "ano" "juri" "juri_nombre" "sexo_codigo" "sexo_nombre"
## [6] "edad" "poblacion"
En primer lugar vamos a seleccionar y renombrar columnas del data frame de defunciones para que los nombres de las columnas coincidan en ambas fuentes.
colnames(poblacion)
## [1] "ano" "juri" "juri_nombre" "sexo_codigo" "sexo_nombre"
## [6] "edad" "poblacion"
defunciones = defunciones %>% dplyr::select(ano = anio,
juri = jurisdiccion_de_residencia_id,
sexo_codigo = sexo_id,
edad = grupo_edad,
cantidad)
head(defunciones)
## ano juri sexo_codigo edad cantidad
## 1 2014 34 1 01.De a 0 a 14 anios 22
## 4 2016 94 1 01.De a 0 a 14 anios 1
## 5 2012 90 1 01.De a 0 a 14 anios 1
## 8 2021 62 2 01.De a 0 a 14 anios 1
## 10 2016 14 1 01.De a 0 a 14 anios 1
## 11 2017 86 1 01.De a 0 a 14 anios 1
También debemos incluir los datos del total del país y ambos sexos en el archivo de defunciones, que no tiene información agregada.
defunciones = rbind(
defunciones,
defunciones %>% mutate(juri=1))
defunciones = rbind(
defunciones,
defunciones %>% mutate(sexo_codigo=0))
Para que el archivo quede preparado, sólo nos queda utilizar el comando expand.grid para que contenga todas las combinaciones posibles.
grid = list(
ano=unique(defunciones$ano),
juri=unique(defunciones$juri),
edad=unique(defunciones$edad),
sexo_codigo=unique(defunciones$sexo_codigo)
)
grid = expand.grid(grid)
defunciones = left_join(grid,defunciones)
defunciones[is.na(defunciones)] = 0
# agrupamos para volver a sumarizar la tabla luego de todos los cambios
defunciones = defunciones %>% group_by(ano,juri,sexo_codigo,edad) %>%
summarise(cantidad=sum(cantidad))
Ahora vamos a realizar un loop para ir recorriendo cada año, jurisdicción y sexo y calculando las tasas brutas y ajustadas con epitools.
library(epitools)
# convertimos las variables de código en numéricas para que puedan vincularse sin problema
poblacion$juri = as.numeric(poblacion$juri)
poblacion$sexo_codigo = as.numeric(poblacion$sexo_codigo)
# definimos la población total de Argentina en 2020 como población standard
poblacion_standard = poblacion$poblacion[poblacion$ano=="2020" &
poblacion$sexo_nombre=="Ambos sexos" &
poblacion$juri=="1"]
# creamos un data frame vacío donde se van a ir agregando los indicadores calculados
tasas_resultado = data.frame()
for (a in unique(defunciones$ano)) { # recorremos los años
for (j in unique(defunciones$juri[defunciones$juri %in% 1:94])) { # dentro de cada jurisdicción, recorremos las jurisdicciones
for (s in 0:2) { #dentro de cada jurisdicción, recorremos las categorías de sexo
def_data = defunciones[defunciones$ano == a &
defunciones$juri == j &
defunciones$sexo_codigo == s,] %>% left_join(poblacion) # creamos un data frame con la información del año / jurisdicción / sexo activos
defunciones_n = sum(def_data$cantidad) # calculamos el total de defunciones
tasa_cruda = sum(def_data$cantidad)/sum(def_data$poblacion[is.na(def_data$poblacion)==F]) * 100000 # calculamos la tasa cruda
def_data = def_data[def_data$edad!="06.Sin especificar",] # eliminamos la fila de edad sin especificar para cumplir con el modelo de datos que utliza la librería epitools
# ahora creamos el dataset para anexar en esta vuelta del lopp
ano = first(def_data$ano) # año
juri_codigo = first(def_data$juri) # código de la jurisdicción
juri_nombre = first(def_data$juri_nombre) # nombre de la jurisdicción
sexo_codigo = first(def_data$sexo_codigo) # código de sexo
sexo_nombre = first(def_data$sexo_nombre) # nombre de sexo
# usamos la función ageadjust.direct para ajustar las tasas
tasas = epitools::ageadjust.direct(
count = def_data$cantidad, # en count se indica la cantidad de defunciones
pop = def_data$poblacion, # en pop la población
stdpop = poblacion_standard, # en stdpop la población utilizada como standard
conf.level = .95 # en conf.level el nivel de confianza seleccionado para la estimación de los intervalos de confianza
) *100000
# ordenamos todos los resultados en un data frame y lo añadimos a resultados
append = data.frame(
ano,
juri_codigo,
juri_nombre,
sexo_codigo,
sexo_nombre,
defunciones_n,
tasa_cruda,
tasas[1],
tasas[2],
tasas[3],
tasas[4]
)
colnames(append)[8:11] = names(tasas)
rownames(append) = 1
tasas_resultado = rbind(
tasas_resultado,
append
) %>% arrange(juri_codigo,sexo_codigo)
}
}
}
Visualizamos los resultados
library(DT)
DT::datatable(tasas_resultado, rownames = F)