Bienvenidas y bienvenidos al taller Demografía del parentesco con énfasis en estimaciones de duelo de la Escuela ALAP 2026. Este sitio reúne todo el material del curso: una pestaña por módulo. Los módulos teóricos se acompañan de presentaciones en vivo; los módulos de laboratorio contienen el código en R que ejecutaremos en conjunto.

Todo el material del curso (código y datos) está disponible en el repositorio de GitHub: https://github.com/alburezg/ALAP26_duelo.

Módulos

Módulo 1

Módulo 1 · Introducción a la demografía del parentesco + preparación técnica

A cargo de Diego Alburez-Gutierrez.

Este primer módulo combina una introducción teórica (presentación en vivo) con un laboratorio de preparación técnica. Al terminar, cada participante tendrá su entorno de R listo y habrá localizado todos los datos que usaremos a lo largo del taller.

Programa del taller

El taller se desarrolla en dos días (24 y 25 de agosto de 2026, San José, Costa Rica). Este es el programa tentativo; los horarios pueden ajustarse durante las sesiones.

Lunes 24 de agosto

Horario Sesión
8:30–9:00 Bienvenida · Presentación cultural
9:00–10:30 Módulo 1 · Introducción a la demografía del parentesco + preparación técnica
10:30–11:00 Merienda
11:00–12:00 Módulo 2 · Estimación de parentesco con DemoKin
12:00–13:00 Almuerzo
13:00–15:00 Módulo 3 · Demografía del duelo: el conflicto colombiano
15:00–15:30 Pausa para café
15:30–16:30 Módulo 4 · Ejercicios: replicar el análisis para otro país
17:00 Salida del bus · Regreso al alojamiento

Martes 25 de agosto

Horario Sesión
8:30–10:00 Módulo 5 · Microsimulación con SOCSIM
10:00–10:30 Merienda
10:30–12:00 Módulo 6 · Pérdida de parientes y conclusiones
12:00–12:30 Cierre de las Escuelas ALAP · Comparsa
12:30 Almuerzo
15:00 Salida del bus · Regreso a San José

Las pestañas Soluciones y Datos son material de referencia para consultar en cualquier momento.

Contenido de este módulo:

1.1 ¿Qué es la demografía del parentesco?

La demografía formal del parentesco permite estimar, a partir de las tasas de fecundidad y mortalidad de una población, cuántos parientes vivos (y fallecidos) puede esperar tener una persona promedio a cada edad. El marco parte del trabajo seminal de Goodman et al. (1974) y fue reformulado en términos matriciales por Caswell (2019), con extensiones posteriores para tasas variables en el tiempo (Caswell and Song 2021) y modelos de dos sexos (Caswell 2022).

Todas estas variantes están implementadas en el paquete de R DemoKin. En la segunda parte del taller usaremos estas estimaciones para cuantificar el duelo a nivel poblacional: cuántas personas pierden a un familiar y cuántas quedan en duelo por cada defunción.

La parte conceptual de este módulo se desarrolla en la presentación. Aquí nos concentramos en dejar el entorno de trabajo listo.

1.2 Instalación de R y los paquetes necesarios

Necesitamos R (≥ 4.2) y RStudio. Instalamos DemoKin directamente desde GitHub (la versión más reciente) y los demás paquetes desde CRAN. Ejecute este bloque una sola vez:

[1.1]

# Instalar DemoKin desde GitHub
install.packages("remotes")
remotes::install_github("IvanWilli/DemoKin")

# Paquete de microsimulación (Módulos 5-6)
install.packages("rsocsim")

# Paquetes de manejo y visualización de datos usados en todos los módulos:
#   tidyverse, arrow  -> manipulación de datos y lectura de .parquet
#   scales            -> formato de ejes y etiquetas (Módulo 3)
#   ggh4x, data.table -> facetas y manejo de datos de la microsimulación (5-6)
#   future            -> rsocsim lo usa para correr la simulación en segundo
#                        plano (Módulo 5). Hay que instalarlo aparte: rsocsim
#                        lo declara como sugerido, no como dependencia.
install.packages(c("tidyverse", "arrow", "scales", "ggh4x", "data.table", "future"))

rsocsim tiene una simulación sencilla incorporada que puedes ejecutar para ver si el paquete se ha instalado correctamente. Por ahora, vamos a ejecutar el código sin centrarnos en los detalles técnicos:

[1.2]

library(rsocsim)

# basedir mantiene la prueba dentro del proyecto (socsim/); si se omite,
# rsocsim escribe en el directorio temporal de la sesión de R.
folder = rsocsim::create_simulation_folder(
  basedir = file.path(getwd(), "socsim"),
  simdir = "check_instalacion"
)
supfile = rsocsim::create_sup_file(folder)
seed = 300
rsocsim::socsim(folder, supfile, seed)
## [1] 1

Con esto quedan instalados todos los paquetes que usaremos a lo largo del taller. Cada módulo carga con library() únicamente los que necesita.

Cargamos los paquetes que usaremos en los laboratorios:

[1.3]

library(tidyverse) # manipulación y gráficos
library(DemoKin) # modelos de parentesco
library(arrow) # lectura de archivos .parquet
## Versión de DemoKin: 1.0.3

1.3 Datos del World Population Prospects (WPP) para América Latina

Los modelos de parentesco necesitan tres insumos por edad, sexo y año: supervivencia, fecundidad y población. Preparamos estos insumos a partir del World Population Prospects 2024 de las Naciones Unidas para 20 países de América Latina y el Caribe (1950–2023) y los guardamos en el folder data/wpp_latam_1950_2023, que contiene un archivo .parquet por país.

[1.4]

# Países disponibles
countries <- read_csv("data/countries.csv")
countries
## # A tibble: 20 × 2
##    iso3  country             
##    <chr> <chr>               
##  1 ARG   Argentina           
##  2 BOL   Bolivia             
##  3 BRA   Brasil              
##  4 CHL   Chile               
##  5 COL   Colombia            
##  6 ECU   Ecuador             
##  7 PRY   Paraguay            
##  8 PER   Perú                
##  9 URY   Uruguay             
## 10 VEN   Venezuela           
## 11 CRI   Costa Rica          
## 12 SLV   El Salvador         
## 13 GTM   Guatemala           
## 14 HND   Honduras            
## 15 MEX   México              
## 16 NIC   Nicaragua           
## 17 PAN   Panamá              
## 18 CUB   Cuba                
## 19 DOM   República Dominicana
## 20 HTI   Haití

Cada país es un archivo wpp_<ISO3>.parquet. Veamos el de Colombia:

[1.5]

col <- read_parquet("data/wpp_latam_1950_2023/wpp_COL.parquet")

dim(col) # filas y columnas
## [1] 14948    10

[1.6]

head(col)
## # A tibble: 6 × 10
##   iso3  country   year sex     age    px      qx      mx    fx    pop
##   <chr> <chr>    <dbl> <chr> <dbl> <dbl>   <dbl>   <dbl> <dbl>  <dbl>
## 1 COL   Colombia  1950 f         0 0.881 0.119   0.129       0 237964
## 2 COL   Colombia  1950 f         1 0.969 0.0310  0.0315      0 211187
## 3 COL   Colombia  1950 f         2 0.979 0.0211  0.0214      0 200886
## 4 COL   Colombia  1950 f         3 0.985 0.0146  0.0147      0 191607
## 5 COL   Colombia  1950 f         4 0.990 0.0104  0.0104      0 183025
## 6 COL   Colombia  1950 f         5 0.993 0.00745 0.00748     0 175117

La tabla está en formato tidy: una fila por combinación de year, sex ("f"/"m") y age (0–100), con las columnas:

  • px — probabilidad de sobrevivir de la edad x a x+1;
  • qx, mx — probabilidad y tasa de mortalidad;
  • fx — tasa de fecundidad específica por edad (mujeres; 0 en hombres);
  • pop — población al 1 de enero.

1.4 Datos del conflicto colombiano

Para el Módulo 3 reproduciremos las estimaciones de duelo del artículo sobre el conflicto armado colombiano (Acosta et al. 2026). Los datos están en data/colombia/:

[1.7]

# Muertes por homicidio relacionadas con el conflicto (1985-2018),
# por año, sexo y edad de la víctima
homicidios <- read_parquet("data/colombia/col_homicidios_1985_2018.parquet")

dim(homicidios) # filas y columnas
## [1] 6868    4

[1.8]

head(homicidios)
## # A tibble: 6 × 4
##    year sex     age    dx
##   <dbl> <chr> <int> <dbl>
## 1  1985 f         0 33.3 
## 2  1985 f         1 17.9 
## 3  1985 f         2  9.81
## 4  1985 f         3  5.67
## 5  1985 f         4  3.54
## 6  1985 f         5  2.47

[1.9]

# Total de homicidios del conflicto en el período, sumando sobre edad y sexo.
# Es el denominador de los multiplicadores de duelo del Módulo 3.
sum(homicidios$dx)
## [1] 618105.1

Solo homicidios. El artículo original también estima el duelo por desapariciones forzadas. En este taller, por simplicidad, consideraremos únicamente los homicidios.

Con el entorno listo y los datos localizados, en el Módulo 2 aprenderemos a generar estimaciones de parentesco con DemoKin.

Módulo 2

Módulo 2 · Laboratorio: estimación de parentesco con DemoKin

A cargo de Diego Alburez-Gutierrez.

En este laboratorio aprenderemos a estimar las redes de parentesco de una persona promedio (a quien llamaremos Focal) usando el paquete DemoKin. Nos concentraremos en el modelo más completo que usaremos en el taller: el modelo de dos sexos y variable en el tiempo, con salida por período. Este es exactamente el modelo que sustenta las estimaciones de duelo del Módulo 3.

[2.1]

library(tidyverse)
library(DemoKin)
library(arrow)

Contenido de este módulo:

2.1 El modelo de dos sexos y variable en el tiempo

La idea central de los modelos matriciales de parentesco (Caswell 2019) es una recurrencia por edad de Focal: el número esperado de parientes de un tipo dado que Focal tiene a la edad x+1x+1 se obtiene proyectando a los parientes que tenía a la edad xx (que sobreviven y envejecen un año) y sumando los nuevos parientes que aparecen en el intervalo:

𝒌(x+1)=𝑼𝒌(x)+𝜷(x),𝒌(0)=𝒌0. \mathbf{k}(x+1) = \mathbf{U}\,\mathbf{k}(x) \;+\; \boldsymbol{\beta}(x), \qquad \mathbf{k}(0)=\mathbf{k}_0 .

Aquí 𝒌(x)\mathbf{k}(x) es un vector, no un número: es la distribución por edad de un tipo de pariente (cuántas hijas de 0 años, de 1 año, …, tiene Focal cuando ella tiene la edad xx). La ecuación tiene tres ingredientes:

  • 𝑼\mathbf{U}, la matriz de supervivencia: mueve a cada pariente un año hacia arriba en la escala de edad, con su probabilidad de sobrevivir. Es la que hace “envejecer” la red de un año al siguiente.
  • 𝜷(x)\boldsymbol{\beta}(x), el subsidio: los parientes nuevos que se incorporan en el intervalo (se explica enseguida).
  • 𝒌0\mathbf{k}_0, la condición inicial: los parientes que ya existen en el momento en que Focal nace.

El subsidio 𝜷(x)\boldsymbol{\beta}(x): de dónde salen los parientes nuevos. El término 𝑼𝒌(x)\mathbf{U}\,\mathbf{k}(x) solo hace envejecer a los parientes que ya había; por sí solo, la red nunca crecería. El subsidio es el flujo de parientes nuevos, y es lo que acopla unos tipos de pariente con otros. Casi siempre esos parientes nuevos llegan por un nacimiento, así que entran en la clase de edad 0; la clave es quién los tiene. El subsidio de un tipo de pariente se calcula a partir de la abundancia de otro pariente. Por ejemplo:

  • las hijas de Focal nacen de la propia Focal, de modo que su subsidio es simplemente la fecundidad de Focal a la edad xx;
  • las nietas nacen de las hijas de Focal, así que su subsidio depende de la distribución por edad de las hijas, 𝒅(x)\mathbf{d}(x): 𝜷nietas(x)=𝑭𝒅(x),\boldsymbol{\beta}_{\text{nietas}}(x) = \mathbf{F}\,\mathbf{d}(x), donde 𝑭\mathbf{F} es la matriz de fecundidad por edad (coloca los nacimientos en la edad 0).

Este encadenamiento —un pariente “produce” a otro— es justamente lo que resume el diagrama de parentesco de la sección 2.2.

La condición inicial 𝒌0\mathbf{k}_0: los parientes al nacer Focal. La recurrencia necesita un punto de partida a la edad 0. Para los descendientes es trivial: al nacer, Focal todavía no tiene hijas ni nietas, así que 𝒅(0)=𝟎\mathbf{d}(0)=\mathbf{0}. Para los ascendientes, en cambio, la condición inicial la fija la estructura de la población. El caso fundamental es la madre: la distribución por edad de la madre en el instante en que nace Focal es la distribución de las edades a la maternidad, 𝒎(0)=𝝅,πy=nyfyynyfy, \mathbf{m}(0) = \boldsymbol{\pi}, \qquad \pi_y = \frac{n_y\,f_y}{\sum_{y'} n_{y'}\,f_{y'}}, es decir, las mujeres en edad fértil ponderadas por su fecundidad fyf_y y su número nyn_y. A partir de la madre se derivan, “subiendo” una generación, la abuela, las tías y los hermanos que Focal ya tiene al nacer.

Las condiciones de frontera: el modelo variable en el tiempo. Hasta aquí las tasas eran fijas. En el modelo variable en el tiempo las matrices llevan un índice de año calendario (𝑼t\mathbf{U}_t, 𝑭t\mathbf{F}_t): cuando Focal pasa de la edad xx a x+1x+1, el calendario también avanza un año, de modo que una cohorte recorre una diagonal en el diagrama de Lexis, atravesando las tasas de años sucesivos. Esto obliga a fijar una condición de frontera temporal: qué tasas regían antes del primer año con datos. DemoKin supone que la población era estable con las tasas de ese primer año. Por eso importa dónde arranca la serie: empezar en 1950 en lugar de 1900 (como hace el artículo del Módulo 3) altera un poco las estimaciones de los parientes más lejanos, cuyas trayectorias comienzan mucho antes del nacimiento de Focal.

Este taller combina dos extensiones del modelo básico:

  • Variable en el tiempo (Caswell and Song 2021): las tasas de fecundidad y mortalidad cambian con el año calendario. Esto es crucial en América Latina, donde la fecundidad cayó drásticamente desde 1960.
  • De dos sexos (Caswell 2022): se rastrean parientes de ambos sexos (madres y padres, hermanas y hermanos, etc.), integrando la demografía femenina y masculina. Cada tasa (supervivencia, fecundidad) y la población se especifican por separado para mujeres y hombres.

Período vs. cohorte. Con tasas variables en el tiempo hay dos formas de mirar el parentesco:

  • Período: en un año calendario dado (p. ej., 2018), ¿cómo es la red de parientes de las personas de cada edad? (mirada transversal).
  • Cohorte: para las personas nacidas en un año dado, ¿cómo evoluciona su red a lo largo de la vida? (mirada longitudinal).

En el Módulo 3 necesitamos la mirada por período (output_period), porque estimamos el duelo de toda la población en cada año.

El modelo variable en el tiempo aprovecha justamente la estructura Edad-Periodo-Cohorte (APC): una persona y sus parientes atraviesan tasas distintas a lo largo de su vida, siguiendo una diagonal en el diagrama de Lexis (edad × año). Período y cohorte son dos formas de recortar ese plano:

Dimensiones Edad-Periodo-Cohorte del modelo de parentesco. Fuente: Caswell (2019).
Dimensiones Edad-Periodo-Cohorte del modelo de parentesco. Fuente: Caswell (2019).

2.2 El diagrama de parentesco: cómo se eligen los parientes

DemoKin identifica cada tipo de pariente con un código corto. La forma más clara de ver cómo se relacionan entre sí —y qué código le corresponde a cada uno— es el diagrama de parentesco de Keyfitz (Keyfitz and Caswell 2005; Caswell 2019): una red centrada en Focal en la que cada nodo es un tipo de pariente y cada arista une a un pariente con el que lo “produce” (la relación de subsidio de la sección anterior). El diagrama siguiente muestra el número esperado de parientes mujeres de una Focal colombiana de 30 años, con el código de DemoKin y el conteo en cada nodo:

Diagrama de parentesco de Keyfitz para una mujer colombiana promedio de 30 años. Cada nodo es un tipo de pariente (con su código de DemoKin y el número esperado de parientes vivos); las aristas conectan a cada pariente con el que lo genera. Adaptado del taller de la Escuela ALAP 2024.
Diagrama de parentesco de Keyfitz para una mujer colombiana promedio de 30 años. Cada nodo es un tipo de pariente (con su código de DemoKin y el número esperado de parientes vivos); las aristas conectan a cada pariente con el que lo genera. Adaptado del taller de la Escuela ALAP 2024.

La equivalencia entre los códigos de DemoKin y los de Caswell (2019), junto con las etiquetas legibles, está en la tabla demokin_codes del paquete. Nótese que los códigos distinguen, por ejemplo, hermanas mayores (os) de menores (ys), porque el modelo las genera de forma distinta (véase el diagrama); cuando no interesa esa distinción, DemoKin ofrece códigos “colapsados” como s (hermanas/os), a (tías/os), c (primas/os) y n (sobrinas/os):

[2.2]

demokin_codes
##    DemoKin Caswell               Labels_female                   Labels_male
## 1      coa       t    Cousins from older aunts     Cousins from older uncles
## 2      cya       v  Cousins from younger aunts   Cousins from younger uncles
## 3        c    <NA>                     Cousins                       Cousins
## 4        d       a                   Daughters                          Sons
## 5       gd       b             Grand-daughters                    Grand-sons
## 6      ggd       c       Great-grand-daughters              Great-grand-sons
## 7      ggm       h          Great-grandmothers            Great-grandfathers
## 8       gm       g                Grandmothers                  Grandfathers
## 9        m       d                      Mother                        Father
## 10     nos       p   Nieces from older sisters   Nephews from older brothers
## 11     nys       q Nieces from younger sisters Nephews from younger brothers
## 12       n    <NA>                      Nieces                       Nephews
## 13      oa       r     Aunts older than mother     Uncles older than fathers
## 14      ya       s   Aunts younger than mother    Uncles younger than father
## 15       a    <NA>                       Aunts                        Uncles
## 16      os       m               Older sisters                Older brothers
## 17      ys       n             Younger sisters              Younger brothers
## 18       s    <NA>                     Sisters                      Brothers
##                          Labels_2sex
## 1    Cousins from older aunts/uncles
## 2  Cousins from younger aunts/uncles
## 3                            Cousins
## 4                           Children
## 5                     Grand-children
## 6               Great-grand-children
## 7                 Great-grandparents
## 8                       Grandparents
## 9                            Parents
## 10      Niblings from older siblings
## 11    Niblings from younger siblings
## 12                          Niblings
## 13   Aunts/Uncles older than parents
## 14 Aunts/Uncles younger than parents
## 15                      Aunts/Uncles
## 16                    Older siblings
## 17                  Younger siblings
## 18                          Siblings

Al ajustar un modelo, elegimos los parientes de interés pasando estos códigos al argumento output_kin (por ejemplo, c("d", "m", "gm") para hijas/os, madres/padres y abuelas/os). En este módulo trabajaremos con seis tipos: hijas/os (d), madres/padres (m), abuelas/os (gm), hermanas/os (s), primas/os (c) y tías/os (a).

2.3 Preparación de los insumos

kin2sex() necesita seis insumos, cada uno como una matriz con las edades en las filas (0–100) y los años en las columnas:

Insumo Significado
pf, pm probabilidades de supervivencia (mujeres, hombres)
ff, fm tasas de fecundidad por edad (mujeres, hombres)
nf, nm población por edad (mujeres, hombres)

Cargamos los datos del WPP para Colombia que preparamos en el Módulo 1:

[2.3]

col <- read_parquet("data/wpp_latam_1950_2023/wpp_COL.parquet")
head(col)
## # A tibble: 6 × 10
##   iso3  country   year sex     age    px      qx      mx    fx    pop
##   <chr> <chr>    <dbl> <chr> <dbl> <dbl>   <dbl>   <dbl> <dbl>  <dbl>
## 1 COL   Colombia  1950 f         0 0.881 0.119   0.129       0 237964
## 2 COL   Colombia  1950 f         1 0.969 0.0310  0.0315      0 211187
## 3 COL   Colombia  1950 f         2 0.979 0.0211  0.0214      0 200886
## 4 COL   Colombia  1950 f         3 0.985 0.0146  0.0147      0 191607
## 5 COL   Colombia  1950 f         4 0.990 0.0104  0.0104      0 183025
## 6 COL   Colombia  1950 f         5 0.993 0.00745 0.00748     0 175117

Explorar los insumos. Antes de correr el modelo conviene mirar las tasas que lo alimentan. Empecemos por la mortalidad: la probabilidad de muerte qxq_x por edad, con una línea por año (escala logarítmica). Se aprecia la caída de la mortalidad a lo largo del tiempo, sobre todo en la infancia:

[2.4]

col %>%
  filter(sex == "f") %>%
  ggplot(aes(x = age, y = qx, colour = year, group = year)) +
  geom_line(alpha = 0.6) +
  scale_y_log10() +
  scale_colour_viridis_c() +
  labs(
    title = "Mortalidad femenina: qx por edad y año (Colombia)",
    x = "Edad", y = "qx (escala log)", colour = "Año"
  ) +
  theme_bw()

La fecundidad por edad, con una línea por año. La curva se desplaza y baja: la fecundidad cae fuertemente desde los años 1960, un hecho central para el parentesco en América Latina:

[2.5]

col %>%
  filter(sex == "f", fx > 0) %>%
  ggplot(aes(x = age, y = fx, colour = year, group = year)) +
  geom_line(alpha = 0.6) +
  scale_colour_viridis_c() +
  labs(
    title = "Fecundidad por edad y año (Colombia)",
    x = "Edad de la madre", y = "fx", colour = "Año"
  ) +
  theme_bw()

También podemos ver las tasas como superficies de Lexis (edad × año), que es la forma natural de pensar insumos que varían por edad, período y cohorte (APC):

[2.6]

col %>%
  filter(sex == "f") %>%
  ggplot(aes(x = year, y = age, fill = fx)) +
  geom_tile() +
  scale_fill_viridis_c(option = "magma") +
  labs(
    title = "Superficie de fecundidad (edad × año), Colombia",
    x = "Año", y = "Edad de la madre", fill = "fx"
  ) +
  theme_bw()

En esta superficie, una cohorte de Focales avanza en diagonal (envejece un año por cada año calendario), atravesando las tasas cambiantes que vimos en la sección 2.1.

Los datos están en formato tidy (una fila por edad-sexo-año). La siguiente función auxiliar los convierte al formato matriz (edad × año) que espera DemoKin:

[2.7]

reshape_wpp <- function(dat, variable, which_sex) {
  dat %>%
    filter(sex == which_sex) %>%
    select(age, year, value = all_of(variable)) %>%
    arrange(age, year) %>%
    pivot_wider(names_from = year, values_from = value) %>%
    select(-age) %>%
    as.matrix()
}

# Supervivencia por sexo
pf <- reshape_wpp(col, "px", "f")
pm <- reshape_wpp(col, "px", "m")

# Fecundidad femenina
ff <- reshape_wpp(col, "fx", "f")

# Población por sexo
nf <- reshape_wpp(col, "pop", "f")
nm <- reshape_wpp(col, "pop", "m")

dim(pf) # 101 edades x 74 años
## [1] 101  74

[2.8]

pf[1:4, 1:5] # primeras edades y años
##           1950      1951      1952      1953      1954
## [1,] 0.8811348 0.8839967 0.8867910 0.8895860 0.8923623
## [2,] 0.9689702 0.9704595 0.9716280 0.9728043 0.9739992
## [3,] 0.9788570 0.9798508 0.9807750 0.9816684 0.9825186
## [4,] 0.9853639 0.9860392 0.9867598 0.9874350 0.9880403

Fecundidad masculina. El WPP solo publica fecundidad femenina. Adoptamos el supuesto androgino: la fecundidad masculina es igual a la femenina (fm = ff). Es una simplificación razonable para fines didácticos; existen métodos para desplazar la fecundidad masculina según la edad media a la paternidad, pero no los usaremos aquí.

[2.9]

fm <- ff

2.4 Estimación con kin2sex()

Ejecutamos el modelo de dos sexos variable en el tiempo pidiendo la salida por período para todos los años 1985–2018 (el rango que necesitaremos en el Módulo 3). Con output_kin elegimos los tipos de pariente de interés: hijas/os (d), madres/padres (m), hermanas/os (s), abuelas/os (gm), nietas/os (gd), tías/os (a), sobrinas/os (n) y primas/os (c).

Un solo modelo para Colombia. Correr kin2sex() es el paso costoso (tarda varios minutos); lo que tarda es ajustar el modelo, no el número de años que se piden en la salida. Por eso lo corremos una sola vez aquí, para todos los años, guardamos el resultado en un archivo y lo reutilizamos en el Módulo 3 (así no repetimos el cálculo). Dos atajos más para agilizar el taller:

  • Corremos el modelo solo para Focal mujer y copiamos el resultado para Focal hombre. Normalmente correríamos kin2sex() de nuevo con sex_focal = "m", pero la red de parientes es muy parecida entre Focales de uno u otro sexo y así ahorramos la mitad del tiempo.
  • Guardamos el resultado en un único archivo (col_kin_1985_2018.parquet) y, si ya existe, simplemente lo leemos (una “caché”). Así cada módulo se puede ejecutar por separado sin volver a ajustar el modelo.

Antes de correrlo, conviene entender cada argumento de kin2sex():

  • pf, pm, ff, fm, nf, nm: los seis insumos matriciales (edad × año) que preparamos arriba —supervivencia, fecundidad y población de mujeres (*f) y hombres (*m).
  • time_invariant = FALSE: usa tasas variables en el tiempo (una matriz por año), no un solo año fijo. Es lo que activa el modelo de la sección 2.1.
  • output_period = 1985:2018: pide la salida por período para esos años (la mirada transversal que necesita el Módulo 3).
  • output_kin: los tipos de pariente de interés, con los códigos de la sección 2.2.
  • sex_focal = "f": el sexo de Focal (aquí, mujer).
  • birth_female = 0.5: la proporción de nacimientos que son niñas (razón de sexo al nacer); DemoKin la usa para repartir los nacimientos entre hijas e hijos.

El código que ajusta el modelo y guarda el archivo es este:

[2.10]

# Correr el modelo UNA vez, para Focal MUJER y todos los años (paso costoso).
kin_f <- kin2sex(
  pf = pf, pm = pm, ff = ff, fm = fm, nf = nf, nm = nm,
  time_invariant = FALSE,
  output_period = 1985:2018,
  output_kin = c("d", "m", "s", "gm", "gd", "a", "n", "c"),
  sex_focal = "f",
  birth_female = 0.5
)

# Reutilizar (copiar) el resultado para Focal HOMBRE en vez de correr un
# segundo modelo. Guardamos ambos sexos en un solo objeto y en un solo archivo.
kin <- bind_rows(
  as_tibble(kin_f$kin_full) %>% mutate(sex_focal = "f"),
  as_tibble(kin_f$kin_full) %>% mutate(sex_focal = "m")
) %>%
  transmute(
    year = as.integer(year), sex_focal,
    age_focal = as.integer(age_focal), kin, sex_kin,
    age_kin = as.integer(age_kin), living
  ) %>%
  filter(living >= 1e-6) # descartar celdas prácticamente vacías (archivo compacto)

write_parquet(kin, "data/colombia/col_kin_1985_2018.parquet")

El objeto kin tiene una fila por año, sexo/edad de Focal y sexo/edad del pariente, con el número esperado de parientes vivos (living). La columna sex_kin ("f"/"m") distingue el sexo del pariente: kin = "d", sex_kin = "m" son los hijos de Focal; kin = "m", sex_kin = "m" es el padre, etc.

[2.11]

dim(kin) # filas y columnas
## [1] 4976986       7

[2.12]

head(kin)
## # A tibble: 6 × 7
##    year sex_focal age_focal kin   sex_kin age_kin living
##   <int> <chr>         <int> <chr> <chr>     <int>  <dbl>
## 1  1985 f                 0 a     f             0 0.0130
## 2  1986 f                 0 a     f             0 0.0123
## 3  1987 f                 0 a     f             0 0.0117
## 4  1988 f                 0 a     f             0 0.0114
## 5  1989 f                 0 a     f             0 0.0111
## 6  1990 f                 0 a     f             0 0.0109

Para poner los resultados en español definimos una pequeña función que traduce los códigos de pariente a etiquetas legibles (equivale a rename_kin() de DemoKin, que las devuelve en inglés):

[2.13]

etiquetas_kin <- c(
  d = "Hijas e hijos", m = "Madres y padres", s = "Hermanas y hermanos",
  gm = "Abuelas y abuelos", gd = "Nietas y nietos", a = "Tías y tíos",
  n = "Sobrinas y sobrinos", c = "Primas y primos"
)

renombrar_kin <- function(df) {
  df %>% mutate(kin_label = factor(etiquetas_kin[kin], levels = etiquetas_kin))
}

2.5 Número de parientes vivos por edad de Focal

Graficamos cuántos parientes de cada tipo y sexo tiene una mujer colombiana promedio a cada edad, según las tasas de 2018. Sumamos living sobre la edad del pariente para obtener el total (count_living) por tipo y sexo del pariente:

[2.14]

kin %>%
  filter(sex_focal == "f", year == 2018) %>%
  summarise(count_living = sum(living), .by = c(age_focal, kin, sex_kin)) %>%
  renombrar_kin() %>%
  mutate(sexo = if_else(sex_kin == "f", "Mujer", "Hombre")) %>%
  ggplot(aes(x = age_focal, y = count_living, colour = sexo)) +
  geom_line(linewidth = 1) +
  facet_wrap(~kin_label, scales = "free_y") +
  labs(
    title = "Parientes vivos de una mujer colombiana (período 2018)",
    x = "Edad de Focal",
    y = "Número esperado de parientes vivos",
    colour = "Sexo del pariente"
  ) +
  theme_bw() +
  theme(legend.position = "bottom")

Podemos verlo también como composición de la familia a lo largo de la vida. Aquí sumamos los parientes de ambos sexos para obtener el total por tipo de pariente a cada edad de Focal:

[2.15]

kin %>%
  filter(sex_focal == "f", year == 2018) %>%
  summarise(count_living = sum(living), .by = c(age_focal, kin)) %>%
  renombrar_kin() %>%
  ggplot(aes(x = age_focal, y = count_living, fill = kin_label)) +
  geom_area(colour = "black", linewidth = 0.2, alpha = 0.85) +
  labs(
    title = "Composición de la red de parientes vivos (período 2018)",
    x = "Edad de Focal", y = "Número esperado de parientes vivos",
    fill = "Tipo de pariente"
  ) +
  theme_bw()

¿Qué vemos aquí? La red no tiene un tamaño fijo: crece y se recompone con la edad de Focal. En la juventud predominan los parientes ascendientes (madres y padres, abuelas y abuelos) y los hermanos; hacia la adultez esos ascendientes van desapareciendo y ganan peso los descendientes (hijas e hijos, y más tarde nietas y nietos). Los parientes extendidos —tías/os y primas/os— son los más numerosos en casi todas las edades: es justamente esa abundancia la que, en el Módulo 3, amplificará el efecto de cada muerte sobre el duelo.

2.6 Distribución por edad de los parientes

El objeto kin guarda la distribución por edad de cada tipo de pariente, no solo su total. Comparemos la distribución por edad de cuatro tipos de pariente de una Focal de 60 años en 2018 —hijas/os, hermanas/os, tías/os y primas/os—, cada uno en su propio panel (con escala vertical libre) y separado por sexo del pariente:

[2.16]

kin %>%
  filter(
    sex_focal == "f", year == 2018, age_focal == 60,
    kin %in% c("d", "s", "a", "c")
  ) %>%
  renombrar_kin() %>%
  mutate(sexo = if_else(sex_kin == "f", "Mujer", "Hombre")) %>%
  ggplot(aes(x = age_kin, y = living, colour = sexo)) +
  geom_line(linewidth = 1) +
  facet_wrap(~kin_label, scales = "free_y") +
  labs(
    title = "Distribución por edad de los parientes de una Focal de 60 años (2018)",
    x = "Edad del pariente", y = "Número esperado", colour = "Sexo del pariente"
  ) +
  theme_bw() +
  theme(legend.position = "bottom")

Cada distribución cuenta una historia demográfica distinta: las hijas/os se concentran en edades adultas jóvenes; las hermanas/os, alrededor de la edad de Focal; las tías/os en edades mayores (y son pocas, porque muchas ya han fallecido); y las primas/os se despliegan sobre un rango de edades amplio.

Con esto tenemos todo lo necesario para el Módulo 3, donde combinaremos esta estructura de parentesco (kin) con las muertes por el conflicto para estimar el duelo a nivel poblacional.

Módulo 3

Módulo 3 · Demografía de la pérdida: el conflicto colombiano

A cargo de Enrique Acosta.

Este módulo combina una presentación teórica sobre la demografía del duelo con un laboratorio en el que reproduciremos, paso a paso, las cuatro medidas clave del artículo Weaponizing Kinship (Acosta et al. 2026):

  1. la incidencia anual del duelo;
  2. la tabla de multiplicadores de duelo;
  3. la prevalencia acumulada del duelo (a 2018);
  4. la distribución por edad de la prevalencia (pirámide poblacional de 2018, coloreada según el tipo de familia perdida).

La parte teórica (qué es el duelo a nivel poblacional, por qué importa, cómo se inserta en la tradición de Goodman-Keyfitz-Pullum y Caswell) se desarrolla en la presentación. Aquí nos concentramos en el cómputo.

Consideraremos únicamente los homicidios relacionados con el conflicto (el artículo también analiza las desapariciones forzadas).

[3.1]

library(tidyverse)
library(DemoKin)
library(arrow)

Contenido de este módulo:

3.1 Los datos

Usaremos tres insumos, todos en data/colombia/ (su documentación completa está en la pestaña Datos):

[3.2]

dcol <- "data/colombia"

# (a) Datos demográficos colombianos: son los INSUMOS del modelo de parentesco
#     (fecundidad fx, supervivencia px, población nx) más la población y el
#     factor ax que usaremos para el duelo, por año, sexo y edad (1950-2018).
demo <- read_parquet(file.path(dcol, "col_demo_1950_2018.parquet"))
pop <- demo %>% select(year, sex, age, pop, ax)

# (b) Muertes por homicidio (conflicto), por año, sexo y edad de la víctima.
homicidios <- read_parquet(file.path(dcol, "col_homicidios_1985_2018.parquet"))

# (c) Proporción de inmigrantes (se excluyen del riesgo de duelo).
inmigrantes <- read_parquet(file.path(dcol, "col_inmigrantes_2018.parquet"))

El cuarto insumo es la estructura de parentesco (kin): cuántos parientes vivos de cada tipo tiene una persona promedio, por año y por sexo/edad de Focal y del pariente. No es un dato externo: es la salida del modelo que ya ajustamos en el Módulo 2 (de dos sexos y variable en el tiempo), con salida por período 1985–2018 y para Focal de ambos sexos.

Para no volver a correr el modelo —que es el paso costoso— lo reutilizamos: leemos el archivo que guardó el Módulo 2. Si por alguna razón no existiera, el mismo bloque lo regenera, con los datos del WPP para Colombia y los mismos atajos del Módulo 2 (se corre para Focal mujer y se copia para Focal hombre):

Nota sobre los insumos del parentesco. La estructura de parentesco proviene del modelo del Módulo 2, ajustado con las tasas del WPP para Colombia (1950–2023). El artículo original usa tasas colombianas propias que arrancan en 1900. Como DemoKin supone una población estable antes del primer año (véase “condiciones de frontera”, Módulo 2) y las tasas no son idénticas, nuestras estimaciones de parentesco —sobre todo de parientes lejanos— son cercanas pero no idénticas a las publicadas.

[3.3]

archivo_kin <- file.path(dcol, "col_kin_1985_2018.parquet")

if (!file.exists(archivo_kin)) {
  # Reconstruir el archivo (normalmente ya lo generó el Módulo 2).
  col <- read_parquet("data/wpp_latam_1950_2023/wpp_COL.parquet")

  # reshape_wpp(): toma los datos largos del WPP y devuelve UNA matriz con las
  # edades en las filas y los años en las columnas (el formato que espera
  # DemoKin). Argumentos: dat = los datos; variable = la columna que queremos
  # ("px", "fx" o "pop"); which_sex = "f" o "m".
  reshape_wpp <- function(dat, variable, which_sex) {
    dat %>%
      filter(sex == which_sex) %>%
      select(age, year, value = all_of(variable)) %>%
      arrange(age, year) %>%
      pivot_wider(names_from = year, values_from = value) %>%
      select(-age) %>%
      as.matrix()
  }

  # Correr el modelo para Focal mujer y copiarlo para Focal hombre (eficiencia).
  kin_f <- kin2sex(
    pf = reshape_wpp(col, "px", "f"), pm = reshape_wpp(col, "px", "m"),
    ff = reshape_wpp(col, "fx", "f"), fm = reshape_wpp(col, "fx", "f"),
    nf = reshape_wpp(col, "pop", "f"), nm = reshape_wpp(col, "pop", "m"),
    time_invariant = FALSE, output_period = 1985:2018,
    output_kin = c("d", "m", "s", "gm", "gd", "a", "n", "c"),
    sex_focal = "f", birth_female = 0.5
  )
  kin <- bind_rows(
    as_tibble(kin_f$kin_full) %>% mutate(sex_focal = "f"),
    as_tibble(kin_f$kin_full) %>% mutate(sex_focal = "m")
  ) %>%
    transmute(
      year = as.integer(year), sex_focal,
      age_focal = as.integer(age_focal), kin, sex_kin,
      age_kin = as.integer(age_kin), living
    ) %>%
    filter(living >= 1e-6)
  write_parquet(kin, archivo_kin)
}

kin <- read_parquet(archivo_kin)

[3.4]

dim(kin) # filas y columnas
## [1] 4976986       7

[3.5]

head(kin)
## # A tibble: 6 × 7
##    year sex_focal age_focal kin   sex_kin age_kin living
##   <int> <chr>         <int> <chr> <chr>     <int>  <dbl>
## 1  1985 f                 0 a     f             0 0.0130
## 2  1986 f                 0 a     f             0 0.0123
## 3  1987 f                 0 a     f             0 0.0117
## 4  1988 f                 0 a     f             0 0.0114
## 5  1989 f                 0 a     f             0 0.0111
## 6  1990 f                 0 a     f             0 0.0109

Definimos etiquetas legibles y los dos grupos de parentesco que usa el artículo (lo que llamamos familia extendida es lo que el artículo llama distant/lejana):

Grupo Parientes que lo componen Códigos
Familia cercana (𝒞\mathcal{C}) hijas/os, madres/padres, hermanas/os d, m, s
Familia extendida (𝒟\mathcal{D}) abuelas/os, nietas/os, tías/os, sobrinas/os, primas/os gm, gd, a, n, c

El siguiente diagrama sitúa a cada tipo de pariente respecto de Focal y lo colorea según pertenezca a la familia cercana (rosa) o extendida (azul). Estos son los mismos colores que usaremos en todas las figuras del módulo:

Parientes considerados en el análisis, coloreados según sean familia cercana (rosa) o extendida (azul). Adaptado de Acosta et al. (2026).
Parientes considerados en el análisis, coloreados según sean familia cercana (rosa) o extendida (azul). Adaptado de Acosta et al. (2026).

[3.6]

etiquetas_kin <- c(
  d = "Hijas e hijos", m = "Madres y padres", s = "Hermanas y hermanos",
  gm = "Abuelas y abuelos", gd = "Nietas y nietos", a = "Tías y tíos",
  n = "Sobrinas y sobrinos", c = "Primas y primos"
)
parientes_cercanos <- c("d", "m", "s")
parientes_extendidos <- c("gm", "gd", "a", "n", "c")

3.2 El modelo de duelo: marco metodológico

El objetivo es estimar cuántas personas han perdido al menos un pariente de un tipo dado a causa del conflicto. La lógica combina tres ingredientes: la estructura de parentesco (cuántos parientes vivos hay), las muertes por homicidio (con qué probabilidad muere cada pariente) y la población expuesta.

Paso 1 — Probabilidad de muerte de un pariente. A partir del número de homicidios dd a la edad yy y sexo gg en el año tt, y de la población correspondiente, obtenemos una tasa de mortalidad por homicidio mygt=dygt/pobygtm_{ygt} = d_{ygt} / \text{pob}_{ygt} y la convertimos en probabilidad con la relación estándar de tabla de vida:

qygt=mygt1+(1ax)mygt. q_{ygt} = \frac{m_{ygt}}{1 + (1 - a_x)\,m_{ygt}}.

Paso 2 — Probabilidad de NO perder ningún pariente (anual). Para una persona Focal de sexo ss y edad xx en el año tt, suponiendo independencia entre las muertes de sus parientes, la probabilidad de no perder ningún pariente del tipo kk es el producto, sobre todas las edades yy y sexos gg de los parientes, de la probabilidad de que cada uno sobreviva, elevada al número esperado de parientes nn en esa celda (Acosta et al. 2026):

pk,x,s,t0=gy(1qygt)nk,x,s,y,g,t. p^{0}_{k,x,s,t} = \prod_{g}\prod_{y} \left(1 - q_{ygt}\right)^{\,n_{k,x,s,y,g,t}}.

La probabilidad de perder al menos un pariente del tipo kk ese año es su complemento, 1pk,x,s,t01 - p^{0}_{k,x,s,t}.

Paso 3 — Prevalencia acumulada. El duelo es un estado absorbente: una vez que se pierde un pariente, la persona queda en duelo para el resto de su vida. La probabilidad de no haber perdido ningún pariente del tipo kk a lo largo de la vida, hasta la edad aa en el año tt, es el producto de las probabilidades anuales a lo largo de la trayectoria de la cohorte c=tac = t - a:

pk,a,s,t0A=x=0apk,c,x,s0. p^{0A}_{k,a,s,t} = \prod_{x=0}^{a} p^{0}_{k,c,x,s}.

La probabilidad acumulada de haber perdido al menos un pariente es pk,a,s,t>0A=1pk,a,s,t0Ap^{>0A}_{k,a,s,t} = 1 - p^{0A}_{k,a,s,t}.

Paso 4 — De probabilidades a personas. Multiplicamos por la población expuesta (excluyendo inmigrantes, que no estuvieron expuestos al conflicto):

fk,a,s,tA=pk,a,s,t>0A×poba,s,t×(1miga,s,t). f^{A}_{k,a,s,t} = p^{>0A}_{k,a,s,t} \times \text{pob}_{a,s,t} \times (1 - \text{mig}_{a,s,t}).

Paso 5 — Multiplicador de duelo. El número total de personas en duelo por el pariente kk dividido entre el número total de homicidios:

Mk=a,sfk,a,s,tAhomicidios totales. M_k = \frac{\sum_{a,s} f^{A}_{k,a,s,t}}{\text{homicidios totales}}.

Traducimos estos cinco pasos a código. Primero, la probabilidad de muerte por homicidio de un pariente en cada celda de edad-sexo-año (Paso 1). Seguimos el artículo acotando qq a un máximo de 0.4 para estabilizar estratos con pocos casos:

[3.7]

qx_kin <- homicidios %>%
  left_join(pop, by = c("year", "sex", "age")) %>%
  mutate(
    mx_h = dx / pop,
    qx_h = mx_h / (1 + (1 - ax) * mx_h),
    qx_h = pmin(qx_h, 0.4)
  ) %>%
  transmute(year, sex_kin = sex, age_kin = age, qx_kin = qx_h)

Ahora la probabilidad anual de no perder ningún pariente (Paso 2). Unimos la estructura de parentesco con estas probabilidades y aplicamos la fórmula del producto:

p0_anual <- kin %>%
  left_join(qx_kin, by = c("year", "sex_kin", "age_kin")) %>%
  mutate(p0x = (1 - qx_kin)^living) %>%
  summarise(
    p0 = prod(p0x, na.rm = TRUE),
    .by = c(year, sex_focal, age_focal, kin)
  )

También calculamos la exposición de 2018 (población menos inmigrantes), que usaremos para convertir probabilidades en personas:

[3.8]

exposicion_2018 <- pop %>%
  filter(year == 2018) %>%
  left_join(inmigrantes, by = c("sex", "age")) %>%
  mutate(
    imm_r = replace_na(imm_r, 0),
    exposicion = pop * (1 - imm_r)
  ) %>%
  transmute(sex_focal = sex, age_focal = age, exposicion)
Grupos de parentesco: cómo se combinan

Además de los ocho tipos individuales, agrupamos los parientes en familia cercana (𝒞\mathcal{C}) y familia extendida (𝒟\mathcal{D}) (véase la tabla de arriba). La pregunta “¿perdió al menos un pariente del grupo?” requiere combinar las probabilidades de no perder a ninguno de sus miembros. Suponiendo independencia entre los tipos de pariente, la probabilidad de no perder a nadie de un grupo es el producto de las probabilidades acumuladas de sus miembros (Acosta et al. 2026):

p0𝒞=k𝒞pk0A,p0𝒟=k𝒟pk0A. p_0^{\mathcal{C}} = \prod_{k \in \mathcal{C}} p^{0A}_{k}, \qquad p_0^{\mathcal{D}} = \prod_{k \in \mathcal{D}} p^{0A}_{k}.

Con estas dos probabilidades podemos clasificar a toda la población en cuatro categorías mutuamente excluyentes, según haya perdido o no parientes cercanos y/o extendidos:

P(solo cercana)=(1p0𝒞)p0𝒟,P(solo extendida)=p0𝒞(1p0𝒟),P(cercana y extendida)=(1p0𝒞)(1p0𝒟),P(no en duelo)=p0𝒞p0𝒟. \begin{aligned} P(\text{solo cercana}) &= (1 - p_0^{\mathcal{C}})\; p_0^{\mathcal{D}}, \\ P(\text{solo extendida}) &= p_0^{\mathcal{C}}\;(1 - p_0^{\mathcal{D}}), \\ P(\text{cercana y extendida})&= (1 - p_0^{\mathcal{C}})\,(1 - p_0^{\mathcal{D}}), \\ P(\text{no en duelo}) &= p_0^{\mathcal{C}}\; p_0^{\mathcal{D}}. \end{aligned}

La lógica booleana detrás de estas cuatro categorías se ve mejor con un diagrama de Venn: el círculo izquierdo son quienes han perdido al menos un pariente cercano (el complemento de p0𝒞p_0^{\mathcal{C}}); el derecho, quienes han perdido al menos un pariente extendido (complemento de p0𝒟p_0^{\mathcal{D}}). Su intersección es la categoría “cercana y extendida”; su unión (toda el área sombreada) es “cercana o extendida”, con probabilidad 1p0𝒞p0𝒟1 - p_0^{\mathcal{C}}\,p_0^{\mathcal{D}}.

Operaciones booleanas sobre los dos estados de duelo. Cada región lleva su probabilidad bajo el supuesto de independencia. La intersección (“y”) es la categoría “cercana y extendida”; toda el área sombreada es la unión (“o”). Adaptado del material metodológico de Acosta et al. (2026).
Operaciones booleanas sobre los dos estados de duelo. Cada región lleva su probabilidad bajo el supuesto de independencia. La intersección (“y”) es la categoría “cercana y extendida”; toda el área sombreada es la unión (“o”). Adaptado del material metodológico de Acosta et al. (2026).

Las cuatro suman 1: cada persona cae en exactamente una. La probabilidad de haber perdido al menos un pariente cualquiera (cercana O extendida) es el complemento de “no en duelo”: P(cercana o extendida)=1p0𝒞p0𝒟P(\text{cercana o extendida}) = 1 - p_0^{\mathcal{C}}\, p_0^{\mathcal{D}}. Multiplicando cada probabilidad por la población expuesta y sumando obtenemos el número de personas en cada categoría. Usaremos estas fórmulas en la prevalencia (Medida 3) y en la pirámide (Medida 4).

3.3 Medida 1: incidencia anual del duelo

La incidencia anual responde a la pregunta: ¿cuántas personas pierden al menos un pariente de un tipo dado en un año determinado? Es una medida de flujo: cuenta los duelos nuevos que ocurren cada año, y por eso es la manera más directa de ver cómo la violencia del conflicto se traduce, año a año, en pérdidas familiares.

El punto de partida son las muertes por homicidio que ya cargamos. Conviene mirarlas primero, porque son el motor de todo lo demás: los años con más homicidios serán los años con más personas en duelo.

[3.9]

homicidios %>%
  summarise(muertes = sum(dx), .by = year) %>%
  ggplot(aes(x = year, y = muertes / 1000)) +
  geom_col(fill = "#888888", width = 0.8) +
  labs(
    title = "Homicidios anuales relacionados con el conflicto (Colombia)",
    x = "Año", y = "Muertes (miles)"
  ) +
  theme_bw()

Para pasar de muertes a personas en duelo, tomamos la probabilidad anual de perder al menos un pariente, 1p01 - p^0 (calculada arriba), la multiplicamos por la población y sumamos sobre el sexo y la edad de Focal. Calculamos primero la incidencia por tipo individual de pariente (la reutilizaremos en los multiplicadores):

[3.10]

pop_focal <- pop %>% select(year, sex_focal = sex, age_focal = age, pop)

incidencia <- p0_anual %>%
  left_join(pop_focal, by = c("year", "sex_focal", "age_focal")) %>%
  mutate(en_duelo = (1 - p0) * pop) %>%
  summarise(en_duelo = sum(en_duelo), .by = c(year, kin))

¿Por qué no apilar los tipos de pariente? Sería tentador apilar la incidencia de cada tipo de pariente en una sola barra, pero eso cuenta doble: una misma persona puede perder, el mismo año, un primo y una tía, y aparecería en ambas categorías. La incidencia de “al menos un pariente” no es aditiva. Por eso mostramos la incidencia por grupo de familia (cercana y extendida), combinando a los miembros del grupo con la fórmula de producto vista arriba.

[3.11]

# incidencia_familia_anual(): cuántas personas quedan en duelo CADA AÑO por un
# grupo de parientes. Argumentos: tipos = qué parientes forman el grupo
# (p. ej. c("d","m","s")); etiqueta = el nombre que llevará el grupo en el
# gráfico. Devuelve una fila por año, con las personas en duelo y la etiqueta.
# Los pasos son: (1) quedarse con esos parientes, (2) combinarlos con la
# fórmula de producto (la probabilidad de no perder a NINGUNO), (3) pegar la
# población de Focal, (4) pasar de probabilidad a personas, (5) sumar por año.
incidencia_familia_anual <- function(tipos, etiqueta) {
  p0_anual %>%
    filter(kin %in% tipos) %>%
    summarise(p0 = prod(p0), .by = c(year, sex_focal, age_focal)) %>%
    left_join(pop_focal, by = c("year", "sex_focal", "age_focal")) %>%
    mutate(en_duelo = (1 - p0) * pop) %>%
    summarise(en_duelo = sum(en_duelo), .by = year) %>%
    mutate(grupo = etiqueta)
}

incidencia_familia <- bind_rows(
  incidencia_familia_anual(parientes_cercanos, "Familia cercana"),
  incidencia_familia_anual(parientes_extendidos, "Familia extendida")
)

Graficamos la incidencia anual de cada grupo con barras agrupadas (como en el estudio sobre Gaza). Los picos coinciden con los años más violentos del conflicto (compárese con la gráfica de homicidios de arriba):

[3.12]

incidencia_familia %>%
  ggplot(aes(x = year, y = en_duelo / 1000, fill = grupo)) +
  geom_col(position = position_dodge(width = 0.8), width = 0.7) +
  scale_fill_manual(values = c(
    "Familia cercana" = "#b56576",
    "Familia extendida" = "#355070"
  )) +
  scale_y_continuous(labels = scales::comma) +
  labs(
    title = "Incidencia anual del duelo por homicidio (Colombia, 1985-2018)",
    x = "Año", y = "Personas en duelo (miles)", fill = "Grupo de familia"
  ) +
  theme_bw()

Interpretación. Cada año, el conflicto deja en duelo a decenas de miles de personas, muchas más a través de la familia extendida que de la cercana: aunque la probabilidad de perder a un primo específico es baja, cada persona tiene muchos parientes extendidos, de modo que la probabilidad de perder al menos uno es alta. Esta es la intuición central de la demografía del duelo: el tamaño de la red de parentesco amplifica el efecto de cada muerte.

3.4 Medida 2: multiplicadores de duelo

El multiplicador de duelo resume, en un solo número, el alcance social de la violencia: ¿cuántas personas quedan en duelo por cada homicidio? Es el cociente entre las personas en duelo y el número de muertes:

Multiplicadork=personas en duelo por el pariente knúmero de homicidios. \text{Multiplicador}_k = \frac{\text{personas en duelo por el pariente } k}{\text{número de homicidios}}.

Usamos la incidencia que acabamos de calcular como numerador (personas que quedan en duelo, sumadas sobre todo el período 1985–2018) y el total de homicidios como denominador. Es decir, es una medida de incidencia por muerte: cuántos duelos genera, en promedio, cada homicidio.

Para los grupos de familia (cercana, extendida, o cualquiera) combinamos primero las probabilidades anuales de los parientes del grupo (como en la sección de grupos de arriba) y luego calculamos la incidencia:

[3.13]

muertes_total <- sum(homicidios$dx) # total de homicidios 1985-2018

# incidencia_grupo(): igual que incidencia_familia_anual(), pero devuelve UN
# SOLO número: el total de personas en duelo de todo el período (1985-2018), sin
# separar por año. Es el numerador del multiplicador de duelo.
# Argumento: tipos = qué parientes forman el grupo.
incidencia_grupo <- function(tipos) {
  p0_anual %>%
    filter(kin %in% tipos) %>%
    summarise(p0 = prod(p0), .by = c(year, sex_focal, age_focal)) %>%
    left_join(pop_focal, by = c("year", "sex_focal", "age_focal")) %>%
    mutate(en_duelo = (1 - p0) * pop) %>%
    summarise(en_duelo = sum(en_duelo)) %>%
    pull(en_duelo)
}

# por tipo de pariente
mult_kin <- incidencia %>%
  summarise(personas = sum(en_duelo), .by = kin) %>%
  mutate(kin = recode(kin, !!!etiquetas_kin))

# por grupo de familia
mult_grupos <- tibble(
  kin = c("Familia cercana", "Familia extendida", "Cercana o extendida"),
  personas = c(
    incidencia_grupo(parientes_cercanos),
    incidencia_grupo(parientes_extendidos),
    incidencia_grupo(names(etiquetas_kin))
  )
)

# orden de la tabla igual que en el artículo publicado
orden_tabla <- c(
  "Hijas e hijos", "Madres y padres", "Hermanas y hermanos",
  "Abuelas y abuelos", "Sobrinas y sobrinos", "Nietas y nietos",
  "Primas y primos", "Tías y tíos",
  "Familia cercana", "Familia extendida", "Cercana o extendida"
)

tabla_multiplicadores <- bind_rows(mult_kin, mult_grupos) %>%
  mutate(
    muertes = muertes_total,
    multiplicador = round(personas / muertes, 1),
    personas = round(personas),
    kin = factor(kin, levels = orden_tabla)
  ) %>%
  arrange(kin)
Multiplicadores de duelo por homicidio, Colombia 1985-2018. ‘Personas en duelo’ es la incidencia (duelos nuevos sumados sobre el período); el multiplicador es esas personas por homicidio.
Pariente Personas en duelo (incidencia) Muertes (homicidios) Multiplicador
Hijas e hijos 828,606 618,105 1.3
Madres y padres 1,204,717 618,105 1.9
Hermanas y hermanos 2,049,100 618,105 3.3
Abuelas y abuelos 1,535,099 618,105 2.5
Sobrinas y sobrinos 3,682,503 618,105 6.0
Nietas y nietos 621,888 618,105 1.0
Primas y primos 17,932,037 618,105 29.0
Tías y tíos 5,187,009 618,105 8.4
Familia cercana 4,078,227 618,105 6.6
Familia extendida 28,744,258 618,105 46.5
Cercana o extendida 32,705,956 618,105 52.9

Interpretación. El multiplicador es mucho mayor para la familia extendida que para la cercana: cada homicidio deja en duelo a muchas más personas a través de primos, tíos y sobrinos que a través de hijos, padres y hermanos, simplemente porque hay más parientes extendidos. La tercera columna muestra el denominador común (el total de homicidios), para que quede claro que el multiplicador es personas en duelo por muerte.

3.5 Medida 3: prevalencia acumulada del duelo

Mientras que la incidencia es un flujo (duelos nuevos por año), la prevalencia acumulada es un stock: cuenta a las personas que han perdido al menos un pariente en algún momento de su vida, hasta 2018. Como el duelo es un estado que no se revierte, aplicamos el producto acumulado (cumprod) de las probabilidades anuales a lo largo de la trayectoria de cada cohorte (c=añoedadc = \text{año} - \text{edad}), y nos quedamos con el año 2018 (Paso 3):

p0_acum <- p0_anual %>%
  mutate(cohorte = year - age_focal) %>%
  group_by(sex_focal, cohorte, kin) %>%
  arrange(age_focal, .by_group = TRUE) %>%
  mutate(p0_acum = cumprod(p0)) %>%
  ungroup() %>%
  filter(year == 2018)

Una función auxiliar calcula el número de personas que, hacia 2018, habían perdido al menos un pariente de un conjunto dado. Combina la probabilidad acumulada de los miembros del conjunto (producto de sus p0Ap^{0A}, como en la sección de grupos), la convierte en probabilidad de pérdida y la multiplica por la exposición:

[3.14]

# en_duelo_prev(): cuántas personas VIVAS en 2018 han perdido al menos un
# pariente de un grupo en algún momento. A diferencia de las funciones
# anteriores, parte de p0_acum (probabilidades ACUMULADAS a lo largo de la vida)
# y usa la exposición de 2018, no la población de cada año.
# Argumento: tipos = qué parientes forman el grupo. Devuelve un solo número.
en_duelo_prev <- function(tipos) {
  p0_acum %>%
    filter(kin %in% tipos) %>%
    summarise(p0_acum = prod(p0_acum), .by = c(sex_focal, age_focal)) %>%
    left_join(exposicion_2018, by = c("sex_focal", "age_focal")) %>%
    mutate(b = (1 - p0_acum) * exposicion) %>%
    summarise(personas = sum(b)) %>%
    pull(personas)
}

Estimamos la prevalencia por tipo individual de pariente y por grupo de familia (cercana, extendida, y cercana-o-extendida), en número de personas y como porcentaje de la población:

[3.15]

poblacion_2018 <- sum(exposicion_2018$exposicion)

prev_kin <- tibble(kin = names(etiquetas_kin)) %>%
  mutate(
    personas = map_dbl(kin, en_duelo_prev),
    etiqueta = recode(kin, !!!etiquetas_kin),
    grupo = if_else(kin %in% parientes_cercanos, "Cercana", "Extendida")
  )

prev_grupos <- tibble(
  etiqueta = c("Familia cercana", "Familia extendida", "Cercana o extendida"),
  personas = c(
    en_duelo_prev(parientes_cercanos),
    en_duelo_prev(parientes_extendidos),
    en_duelo_prev(names(etiquetas_kin))
  ),
  grupo = "Grupo"
)

prevalencia <- bind_rows(prev_kin %>% select(etiqueta, personas, grupo), prev_grupos) %>%
  mutate(
    millones = personas / 1e6,
    pct = 100 * personas / poblacion_2018
  )

Siguiendo el artículo, mostramos los parientes individuales en un panel y los grupos de familia en otro, en el mismo orden que la publicación:

[3.16]

orden_individual <- c(
  "Hijas e hijos", "Madres y padres", "Hermanas y hermanos",
  "Abuelas y abuelos", "Sobrinas y sobrinos", "Nietas y nietos",
  "Primas y primos", "Tías y tíos"
)
orden_grupo <- c("Familia cercana", "Familia extendida", "Cercana o extendida")

prevalencia %>%
  mutate(
    panel = if_else(grupo == "Grupo", "Grupos de familia", "Parientes individuales"),
    panel = factor(panel, levels = c("Parientes individuales", "Grupos de familia")),
    etiqueta = factor(etiqueta, levels = rev(c(orden_individual, orden_grupo)))
  ) %>%
  ggplot(aes(x = etiqueta, y = millones, fill = grupo)) +
  geom_col() +
  geom_text(aes(label = sprintf("%.1f M (%.0f%%)", millones, pct)),
    hjust = -0.1, size = 3
  ) +
  coord_flip() +
  facet_grid(panel ~ ., scales = "free_y", space = "free_y") +
  scale_fill_manual(values = c(
    "Cercana" = "#b56576", "Extendida" = "#355070",
    "Grupo" = "grey55"
  )) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25))) +
  labs(
    title = "Prevalencia acumulada del duelo por homicidio en 2018",
    subtitle = "Personas que han perdido al menos un pariente del tipo/grupo indicado",
    x = NULL, y = "Personas en duelo (millones)", fill = "Grupo"
  ) +
  theme_bw()

Resultado clave. Hacia 2018, cerca de 19.1 millones de personas (40% de la población) habían perdido al menos un pariente por homicidios del conflicto. La familia extendida domina: por ejemplo, unos 12.4 millones perdieron al menos un primo o prima. Estas cifras son directamente comparables con la Figura 4 del artículo (que reporta ~11.8 millones para primos considerando homicidios y desapariciones). Nuestra cifra difiere un poco por dos motivos que operan en sentidos opuestos: consideramos solo homicidios (lo que la reduce) y el modelo inicia en 1950 (lo que la aumenta; véase la nota del punto 3.1). El resultado global —cerca del 40% de la población en duelo— coincide con el titular del artículo.

3.6 Medida 4: distribución por edad de la prevalencia

La prevalencia total esconde un patrón por edad muy marcado. Para verlo, representamos toda la población de 2018 en una pirámide poblacional, coloreando cada barra según las cuatro categorías mutuamente excluyentes que definimos antes: no en duelo, solo familia cercana, solo familia extendida, o ambas. Es, en el fondo, la distribución por edad y sexo de la prevalencia.

Usamos directamente las fórmulas de producto (no hace falta inclusión-exclusión): para cada edad y sexo calculamos p0𝒞p_0^{\mathcal{C}} y p0𝒟p_0^{\mathcal{D}} y de ahí las cuatro categorías, que por construcción suman la población total:

[3.17]

pop_2018 <- pop %>%
  filter(year == 2018) %>%
  transmute(sex_focal = sex, age_focal = age, pop)

# p0_grupo(): probabilidad acumulada de NO haber perdido a ningún pariente del
# grupo, por sexo y edad de Focal (combinando a los miembros con el producto).
# A diferencia de en_duelo_prev(), no multiplica por la población: devuelve la
# probabilidad, que es lo que necesitamos para la pirámide.
# Argumento: tipos = qué parientes forman el grupo.
p0_grupo <- function(tipos) {
  p0_acum %>%
    filter(kin %in% tipos) %>%
    summarise(p0 = prod(p0_acum), .by = c(sex_focal, age_focal))
}
pC <- p0_grupo(parientes_cercanos) %>% rename(p0_C = p0)
pD <- p0_grupo(parientes_extendidos) %>% rename(p0_D = p0)

piramide <- pC %>%
  left_join(pD, by = c("sex_focal", "age_focal")) %>%
  left_join(pop_2018, by = c("sex_focal", "age_focal")) %>%
  mutate(
    `No en duelo`                 = p0_C * p0_D * pop,
    `Solo familia cercana`        = (1 - p0_C) * p0_D * pop,
    `Solo familia extendida`      = p0_C * (1 - p0_D) * pop,
    `Familia cercana y extendida` = (1 - p0_C) * (1 - p0_D) * pop
  ) %>%
  pivot_longer(
    c(
      `No en duelo`, `Solo familia cercana`,
      `Solo familia extendida`, `Familia cercana y extendida`
    ),
    names_to = "categoria", values_to = "personas"
  ) %>%
  mutate(
    categoria = factor(categoria, levels = c(
      "No en duelo", "Solo familia extendida",
      "Familia cercana y extendida", "Solo familia cercana"
    )),
    # mujeres a la izquierda (valores negativos), hombres a la derecha
    personas = ifelse(sex_focal == "f", -personas, personas) / 1000
  )

[3.18]

colores <- c(
  "No en duelo"                 = "grey75",
  "Solo familia extendida"      = "#355070",
  "Familia cercana y extendida" = "#eaac8b",
  "Solo familia cercana"        = "#b56576"
)

piramide %>%
  ggplot(aes(x = age_focal, y = personas, fill = categoria)) +
  geom_col(width = 1) +
  geom_hline(yintercept = 0, linewidth = 0.2) +
  coord_flip() +
  scale_fill_manual(values = colores) +
  scale_y_continuous(labels = function(x) scales::comma(abs(x))) +
  labs(
    title = "Población de Colombia en 2018 según duelo por homicidio",
    subtitle = "Mujeres a la izquierda, hombres a la derecha",
    x = "Edad", y = "Población (miles)", fill = "Situación de duelo"
  ) +
  theme_bw() +
  theme(legend.position = "bottom")

Interpretación. La pirámide muestra que el duelo por el conflicto está presente en todas las edades, pero se acumula con la edad: las personas mayores han estado expuestas al riesgo durante más años y por eso es más probable que hayan perdido a un familiar. La mayor parte del duelo ocurre a través de la familia extendida (azul), aunque una fracción importante ha perdido también parientes cercanos (naranja y rosa).

Nota sobre las cifras. Como pedimos, usamos la estimación central (número medio de homicidios) en lugar de las 1000 réplicas de la estimación por sistemas múltiples del artículo. Por ello los valores son muy parecidos, pero no idénticos, a los publicados en Acosta et al. (2026).

Recapitulación

En este módulo partimos de la estructura de parentesco del Módulo 2 y las muertes por homicidio para reproducir las cuatro medidas clave del artículo: la incidencia anual (duelos nuevos por año), los multiplicadores (personas en duelo por muerte), la prevalencia acumulada a 2018 (el stock de personas en duelo) y su distribución por edad (la pirámide). El hilo conductor fue siempre el mismo: el tamaño de la red de parentesco —sobre todo la familia extendida— amplifica el efecto demográfico de cada muerte.

En el Módulo 4 te toca a ti: repetirás exactamente estos cuatro pasos para el país que elijas, reutilizando el código que acabamos de escribir.

Módulo 4

Módulo 4 · Ejercicios: replicar el análisis para otro país

A cargo de todo el equipo.

En este laboratorio pondrá en práctica todo lo aprendido. La tarea es elegir un país de América Latina o el Caribe y replicar las cuatro medidas del Módulo 3 (incidencia anual, multiplicadores, prevalencia acumulada y su distribución por edad), pero para la mortalidad violenta de ese país.

El flujo de trabajo es el mismo del Módulo 3, con dos cambios:

  1. Los insumos del modelo de parentesco salen de los datos del WPP que preparamos (un país a elección), no de los datos especiales de Colombia.
  2. La mortalidad de referencia son tasas específicas por homicidio del país elegido.

Datos de mortalidad por homicidio. Estas tasas por homicidio fueron calculadas a partir de estimaciones de la Global Burden of Disease 2023 para 20 países de la región.

[4.1]

library(tidyverse)
library(DemoKin)
library(arrow)

Importante: este módulo arranca de cero. Todo el sitio se compila en una sola sesión de R, así que los objetos del Módulo 3 (que son de Colombia) siguen en la memoria cuando llegamos aquí. Si reutiliza uno de ellos sin darse cuenta, el código correrá sin error pero le dará resultados de Colombia. Para evitarlo, empezamos borrándolos: así, reutilizar uno por accidente da un error claro en vez de un resultado equivocado.

[4.2]

# Borramos los objetos de Colombia del Módulo 3. intersect() con ls() hace que
# el bloque funcione igual si corre este módulo por separado (no habrá nada que
# borrar y no dará error).
objetos_modulo_3 <- c(
  "demo", "pop", "homicidios", "inmigrantes", "kin", "qx_kin",
  "p0_anual", "p0_acum", "pop_focal", "exposicion_2018", "poblacion_2018",
  "pop_2018", "muertes_total", "etiquetas_kin", "parientes_cercanos",
  "parientes_extendidos", "incidencia_familia_anual", "incidencia_grupo",
  "en_duelo_prev", "p0_grupo", "archivo_kin", "dcol"
)

rm(list = intersect(objetos_modulo_3, ls()))

Contenido de este módulo:

4.1 Elegir un país y preparar los insumos

Elegimos un país mediante su código ISO3 (véase data/countries.csv). Aquí usamos Costa Rica (CRI) como ejemplo —el mismo país que se resuelve paso a paso en la pestaña Soluciones—; cambie el código por el país que prefiera.

Las tres primeras líneas del bloque son los únicos parámetros del análisis: el país y el rango de años. Todo lo que sigue se calcula a partir de ellos, así que para cambiar de país o de año de referencia basta con editarlas (no hay años escritos «a mano» más abajo).

[4.3]

# --- Parámetros del análisis: lo único que hay que cambiar ---
iso <- "CRI" # <-- cambie aquí su país (código ISO3)
anio_inicial <- 2000 # primer año con datos de homicidio (GBD)
anio_final <- 2023 # año de referencia del análisis (último disponible)

# Datos del WPP para el país elegido (supervivencia px, fecundidad fx, población)
pais <- open_dataset("data/wpp_latam_1950_2023/", format = "parquet") |>
  filter(iso3 == iso) |>
  collect() |>
  as_tibble()

dim(pais) # filas y columnas
## [1] 14948    10

[4.4]

head(pais)
## # A tibble: 6 × 10
##   iso3  country     year sex     age    px      qx      mx    fx   pop
##   <chr> <chr>      <dbl> <chr> <dbl> <dbl>   <dbl>   <dbl> <dbl> <dbl>
## 1 CRI   Costa Rica  1950 f         0 0.905 0.0948  0.101       0 18386
## 2 CRI   Costa Rica  1950 f         1 0.987 0.0130  0.0131      0 16952
## 3 CRI   Costa Rica  1950 f         2 0.990 0.00988 0.00993     0 15903
## 4 CRI   Costa Rica  1950 f         3 0.992 0.00752 0.00755     0 15128
## 5 CRI   Costa Rica  1950 f         4 0.994 0.00572 0.00574     0 14265
## 6 CRI   Costa Rica  1950 f         5 0.996 0.00435 0.00436     0 13536

Con los datos del país preparamos la población de Focal (para la incidencia anual, que necesita todos los años) y la exposición en el año de referencia (para la prevalencia, que es una foto de un solo año):

[4.5]

# Población de Focal por año, sexo y edad: el denominador de la incidencia anual.
pop_focal <- pais %>% transmute(year, sex_focal = sex, age_focal = age, pop)

# Exposición en el año de referencia: la población que puede estar en duelo.
# (A diferencia del Módulo 3, aquí no descontamos inmigrantes: no tenemos ese
# dato para todos los países.)
exposicion <- pais %>%
  filter(year == anio_final) %>%
  transmute(sex_focal = sex, age_focal = age, exposicion = pop)

# Población total del país en el año de referencia.
poblacion <- sum(exposicion$exposicion)

# Etiquetas de los tipos de pariente y los dos grupos de familia.
etiquetas_kin <- c(
  d = "Hijas e hijos", m = "Madres y padres", s = "Hermanas y hermanos",
  gm = "Abuelas y abuelos", gd = "Nietas y nietos", a = "Tías y tíos",
  n = "Sobrinas y sobrinos", c = "Primas y primos"
)
parientes_cercanos <- c("d", "m", "s")
parientes_extendidos <- c("gm", "gd", "a", "n", "c")

poblacion
## [1] 5092976

Construimos las matrices (edad × año) que pide kin2sex(). La función es la misma que vimos en el Módulo 2; la definimos otra vez aquí para que este módulo funcione por sí solo:

[4.6]

# reshape_wpp(): toma los datos largos del WPP y devuelve UNA matriz con las
# edades en las filas y los años en las columnas, que es el formato que espera
# DemoKin. Argumentos: dat = los datos del país; variable = la columna que
# queremos ("px", "fx" o "pop"); which_sex = "f" o "m".
reshape_wpp <- function(dat, variable, which_sex) {
  dat %>%
    filter(sex == which_sex) %>%
    select(age, year, value = all_of(variable)) %>%
    arrange(age, year) %>%
    pivot_wider(names_from = year, values_from = value) %>%
    select(-age) %>%
    as.matrix()
}

pf <- reshape_wpp(pais, "px", "f")
pm <- reshape_wpp(pais, "px", "m")
ff <- reshape_wpp(pais, "fx", "f")
fm <- ff # supuesto androgino
nf <- reshape_wpp(pais, "pop", "f")
nm <- reshape_wpp(pais, "pop", "m")

4.2 Las tasas de mortalidad por homicidio

En el Módulo 3, la probabilidad de muerte de un pariente venía de las muertes por homicidio del conflicto colombiano. Para el ejercicio usamos un archivo de tasas de mortalidad por homicidio por país, año, sexo y edad: data/homicide_mortality_rates.csv (columnas iso3, year, sex, age, mx).

Leemos el archivo, lo filtramos para el país y los años elegidos, y convertimos la tasa mx en probabilidad qx (suponiendo ax = 0.5, es decir, que las muertes se reparten de forma uniforme dentro del año):

[4.7]

qx_kin <- read_csv("data/homicide_mortality_rates.csv", show_col_types = FALSE) %>%
  filter(iso3 == iso, year %in% anio_inicial:anio_final) %>%
  mutate(qx = mx / (1 + 0.5 * mx)) %>%
  transmute(year, sex_kin = sex, age_kin = age, qx_kin = qx)

head(qx_kin)
## # A tibble: 6 × 4
##    year sex_kin age_kin     qx_kin
##   <dbl> <chr>     <dbl>      <dbl>
## 1  2000 f             0 0.0000132 
## 2  2000 f             1 0.00000638
## 3  2000 f             2 0.0000213 
## 4  2000 f             3 0.0000409 
## 5  2000 f             4 0.0000455 
## 6  2000 f             5 0.0000344

4.3 Generar la estructura de parentesco del país

Corremos el modelo de parentesco (como en los Módulos 2 y 3) para el país elegido, con salida por período y para ambos sexos de Focal. Igual que en el Módulo 2, lo corremos para Focal mujer y copiamos el resultado para Focal hombre (por eficiencia; normalmente correríamos kin2sex() de nuevo con sex_focal = "m").

Atención: este paso tarda varios minutos. Por eso lo calculamos una sola vez, guardamos el resultado en data/ y lo reutilizamos en adelante (esto se llama caché). La primera vez que corra el bloque tendrá que esperar; después será instantáneo. Si cambia de país o de años, el nombre del archivo cambia también, así que el modelo se vuelve a correr solo cuando hace falta.

[4.8]

# El nombre del archivo incluye el país y los años: así, si cambia cualquiera de
# los parámetros, no se reutiliza por error un resultado viejo.
archivo_kin <- file.path(
  "data", paste0("kin_", iso, "_", anio_inicial, "_", anio_final, ".parquet")
)

if (!file.exists(archivo_kin)) {
  # Corremos el modelo para Focal MUJER y copiamos el resultado para Focal
  # hombre. Es un atajo por eficiencia: normalmente correríamos kin2sex() otra
  # vez con sex_focal = "m". Acotamos la salida con output_period a los años que
  # tienen datos de homicidio, para no calcular años que no vamos a usar.
  kin_f <- kin2sex(
    pf = pf, pm = pm, ff = ff, fm = fm, nf = nf, nm = nm,
    time_invariant = FALSE,
    output_period = anio_inicial:anio_final,
    output_kin = c("d", "m", "s", "gm", "gd", "a", "n", "c"),
    sex_focal = "f",
    birth_female = 0.5
  )

  kin <- bind_rows(
    as_tibble(kin_f$kin_full) %>% mutate(sex_focal = "f"),
    as_tibble(kin_f$kin_full) %>% mutate(sex_focal = "m")
  ) %>%
    transmute(year, sex_focal, age_focal, kin, sex_kin, age_kin, living) %>%
    filter(living >= 1e-6)

  write_parquet(kin, archivo_kin)
}

kin <- read_parquet(archivo_kin)

dim(kin) # filas y columnas
## [1] 3478964       7

[4.9]

head(kin)
## # A tibble: 6 × 7
##    year sex_focal age_focal kin   sex_kin age_kin  living
##   <int> <chr>         <int> <chr> <chr>     <int>   <dbl>
## 1  2000 f                 0 a     f             0 0.00874
## 2  2001 f                 0 a     f             0 0.00854
## 3  2002 f                 0 a     f             0 0.00809
## 4  2003 f                 0 a     f             0 0.00766
## 5  2004 f                 0 a     f             0 0.00713
## 6  2005 f                 0 a     f             0 0.00666

4.4 Ejercicio: replicar las cuatro medidas

Su tarea. Reproduzca para su país las cuatro medidas del Módulo 3:

  1. Incidencia anual del duelo (personas en duelo por año y tipo de pariente).
  2. Multiplicadores de duelo (personas en duelo por muerte).
  3. Prevalencia acumulada en el año de referencia (% de la población que ha perdido al menos un pariente).
  4. Distribución por edad de la prevalencia (pirámide poblacional coloreada por familia cercana / extendida / ambas).

Ya tiene todo lo que necesita. Los bloques anteriores dejaron listos estos objetos, todos referidos a su país:

Objeto Qué contiene
kin Estructura de parentesco: parientes vivos por año, sexo y edad de Focal
qx_kin Probabilidad de morir por homicidio, por año, sexo y edad del pariente
pop_focal Población de Focal por año, sexo y edad (denominador de la incidencia)
exposicion Población por sexo y edad en el año de referencia (para la prevalencia)
poblacion Población total en el año de referencia (un solo número)
anio_inicial, anio_final Rango de años del análisis
etiquetas_kin Nombres legibles de los tipos de pariente
parientes_cercanos, parientes_extendidos Los dos grupos de familia

Cuidado con los nombres. Puede reutilizar el código del Módulo 3, pero adapte los nombres de los objetos: el Módulo 3 usa exposicion_2018, poblacion_2018 y pop_2018, que aquí se llaman exposicion y poblacion (sin el año, porque el año es un parámetro). Ese código también usa filter(year == 2018); en su análisis debe ser filter(year == anio_final). Y recuerde que necesitará el total de muertes del período como denominador del multiplicador: en el Módulo 3 era muertes_total, calculado a partir de conteos de muertes; aquí tendrá que obtenerlo de las tasas mx y la población.

Si se atasca, en la pestaña Soluciones (al final) encontrará el código completo y comentado del ejercicio, resuelto paso a paso para Costa Rica.

Preguntas para la discusión.

  • ¿Cuántas personas quedan en duelo por cada homicidio en su país (el multiplicador de duelo)? ¿Cómo se compara con Colombia, y qué explica la diferencia: el tamaño de las redes de parentesco (herencia de la fecundidad pasada) o la intensidad de la violencia?
  • ¿Qué tipo de pariente aporta más al duelo total por homicidio? ¿Por qué pesa tanto la familia extendida frente a la cercana?
  • Los homicidios suelen concentrarse en hombres jóvenes. ¿Cómo se refleja ese patrón por edad y sexo de las víctimas en quiénes quedan en duelo y a través de qué parientes (madres, hermanas, hijas, parejas…)?
  • Dado el descenso de la fecundidad en su país, ¿esperaría que el multiplicador de duelo por homicidio aumente o disminuya en las próximas décadas? ¿Por qué?

Módulo 5

Módulo 5 · Laboratorio: microsimulación con SOCSIM

A cargo de Liliana Calderón. (Adaptado del taller de la Escuela ALAP 2024.)

Hasta ahora estimamos el parentesco con modelos analíticos (DemoKin). En este módulo lo hacemos con microsimulación: en lugar de calcular valores esperados con matrices, simulamos individuo por individuo una población completa —con sus nacimientos, muertes y matrimonios— y luego reconstruimos las redes de parentesco a partir de la genealogía resultante. Usamos el paquete rsocsim, la interfaz en R del microsimulador SOCSIM (Hammel et al. 1976; Mason 2016).

[5.1]

library(rsocsim)
library(tidyverse)
library(ggh4x) # facetas con escalas independientes
library(data.table)
library(arrow)
library(future) # rsocsim lo usa para correr la simulación en segundo plano

Contenido de este módulo:

5.1 Instalación

rsocsim ya se instaló desde CRAN en el Módulo 1. Si necesitas instalarlo aquí, el comando es el mismo:

[5.2]

install.packages("rsocsim")

5.2 ¿Qué es SOCSIM y cómo funciona?

SOCSIM se desarrolló originalmente para Unix en UC Berkeley (Hammel et al. 1976), donde se ha mantenido durante décadas. La versión actual de rsocsim pretende ser independiente del sistema operativo y, en su mayor parte, es compatible con la distribución original de SOCSIM. Para más información sobre el SOCSIM original, véase https://lab.demog.berkeley.edu/socsim/ y especialmente Mason (2016). La siguiente descripción se ha adaptado de los materiales complementarios de Alburez‐Gutierrez et al. (2021).

SOCSIM es un programa de microsimulación demográfica de código abierto y extensible. Está escrito en el lenguaje de programación C y se basa en gran medida en matrices de listas enlazadas para hacer seguimiento de las relaciones de parentesco y almacenar información sobre los individuos simulados. El simulador toma como datos de entrada los archivos iniciales de población y las tasas mensuales de fecundidad y mortalidad por edades. El individuo es la unidad de análisis del simulador. Cada persona está sujeta a un conjunto de tasas, expresadas como probabilidades mensuales de eventos, dadas ciertas características demográficas, como la edad y el sexo. Cada mes, cada individuo se enfrenta al riesgo de experimentar una serie de eventos, como el nacimiento, la muerte y el matrimonio. La selección del evento y el tiempo de espera hasta que se produzca se determinan estocásticamente mediante un modelo de riesgo competitivo. En el programa de simulación se incluyen algunas otras restricciones con el fin de sortear los eventos sólo para los individuos que reúnen las condiciones para ser elegibles (por ejemplo, para permitir un intervalo mínimo de tiempo entre nacimientos de la misma madre, para evitar tabúes sociales como el incesto, etc.). Cada evento para el cual el individuo está en riesgo se modela como una distribución exponencial por partes. El tiempo de espera hasta que se produzca cada evento se genera aleatoriamente y el siguiente evento a ser ejecutado para cada individuo es aquel con el tiempo de espera más corto.

Al final de la simulación, se obtiene un archivo de población (.opop), que registra las características demográficas de cada individuo que vivió en la simulación y los números de identificación de las principales relaciones de parentesco (madre, padre y cónyuge), y un archivo de matrimonios (.omar). Con esa población sintética podemos estudiar la disponibilidad y la pérdida de parientes.

Para dar un ejemplo de la utilización de rsocsim, realizaremos una microsimulación SOCSIM Colombia para el periodo 1950–2023, usando como insumos las mismas tasas del WPP 2024 que preparamos para los modelos de DemoKin.

Para correr la simulación, los datos originales de WPP deben convertirse primero a tasas o probabilidades mensuales en formato SOCSIM, tal y como se describe en SOCSIM Oversimplified (c.f. Mason 2016 para más detalles). Las tasas correspondientes a cada año se especifican en el archivo de supervisión socsim_Colombia.sup, proporcionado en este repositorio, que se utilizará para ejecutar la simulación.

5.3 Escribir los archivos de tasas de entrada

SOCSIM necesita tasas mensuales de fecundidad y mortalidad por edad y sexo en un formato de texto propio. Si se dispone de la información, también se pueden especificar por estado civil o por «grupos» [c.f. SOCSIM Oversimplified, Mason (2016), pp. 26-28, para más información.En los archivos de tasas, el orden es siempre evento demográfico (birth, death, marriage), grupo (1, ..), sexo (F o M) y estado civil (married, single, divorced, widowed). Para las tasas de fecundidad, puede ir seguido de un número que indique la paridad. Cada línea posterior contiene una tasa o probabilidad mensual y el intervalo de edad sobre el que rige (años y meses del límite superior de edad). Definimos a continuación dos funciones auxiliares que convierten nuestros datos del WPP (los .parquet por país; véase el Módulo 1) a tasas o probabilidades mensuales en el formato adecuado y las guardan en la carpeta que les indiquemos. La opción scipen = 9999 evita la notación científica, que SOCSIM no sabe leer.

[5.3]

options(scipen = 9999)

# Lee los datos del WPP para un país (ISO3) desde el .parquet preparado.
.leer_wpp_pais <- function(iso) {
  arrow::read_parquet(file.path("data/wpp_latam_1950_2023", paste0("wpp_", iso, ".parquet")))
}

# --- Tasas de fecundidad mensuales por edad para SOCSIM ---
write_socsim_fertility_rates_WPP <- function(country = "Colombia", iso = "COL", rates_dir = "rates") {
  dir.create(rates_dir, recursive = TRUE, showWarnings = FALSE)

  # Fecundidad femenina por edad simple [15-49] (tasas por mujer, anuales)
  data <- .leer_wpp_pais(iso) %>%
    filter(sex == "f", age >= 15, age <= 49) %>%
    select(year, age, fx)

  # Convertir a tasas mensuales y usar el límite superior de edad que usa SOCSIM
  ASFR <-
    data %>%
    mutate(
      Age_up = age + 1,
      Month = 0,
      fx_mo = fx / 12
    ) %>%
    select(-fx)

  # Añadir filas con tasa 0 para las edades 0-15 y 50-101
  ASFR <-
    ASFR %>%
    group_by(year) %>%
    group_split() %>%
    map_df(~ add_row(.x,
      year = unique(.x$year),
      age = 0, Age_up = 15, Month = 0, fx_mo = 0.0, .before = 1
    )) %>%
    group_by(year) %>%
    group_split() %>%
    map_df(~ add_row(.x,
      year = unique(.x$year),
      age = 50, Age_up = 101, Month = 0, fx_mo = 0.0, .after = 36
    )) %>%
    ungroup() %>%
    select(-age)

  years <- ASFR %>%
    pull(year) %>%
    unique()
  rows_ageF <- ASFR %>%
    pull(Age_up) %>%
    unique() %>%
    seq_along()

  for (year in years) {
    n <- which(year == years)
    n_row <- (n - 1) * 37 + rows_ageF

    outfilename <- file(file.path(rates_dir, paste0(country, "fert", year)), "w")
    cat(c("** Period (Monthly) Age-Specific Fertility Rates for", country, "in", year, "\n"),
      file = outfilename
    )
    cat(c("* Retrieved from the World Population Prospects 2024", "\n"), file = outfilename)
    cat("\n", file = outfilename)

    cat("birth", "1", "F", "single", "0", "\n", file = outfilename)
    for (i in n_row) cat(c(as.matrix(ASFR)[i, -1], "\n"), file = outfilename)
    cat("\n", file = outfilename)

    cat("birth", "1", "F", "married", "0", "\n", file = outfilename)
    for (i in n_row) cat(c(as.matrix(ASFR)[i, -1], "\n"), file = outfilename)

    close(outfilename)
  }
}

# --- Probabilidades de muerte mensuales por edad y sexo para SOCSIM ---
write_socsim_mortality_rates_WPP <- function(country = "Colombia", iso = "COL", rates_dir = "rates") {
  dir.create(rates_dir, recursive = TRUE, showWarnings = FALSE)

  # Probabilidades de muerte (qx) por edad simple [0-100] y sexo
  data <- .leer_wpp_pais(iso) %>%
    transmute(year,
      Sex = factor(if_else(sex == "f", "Female", "Male"),
        levels = c("Female", "Male")
      ),
      age, qx
    )

  # Convertir probabilidades anuales en mensuales (Wachter 2014, p. 53)
  # q100 = 1 para limitar la esperanza de vida a 100
  ASMP <-
    data %>%
    mutate(
      qx_mo = if_else(age == 100, 1, 1 - (1 - qx)^(1 / 12)),
      Age_up = age + 1,
      Month = 0
    ) %>%
    select(year, Age_up, Month, Sex, qx_mo) %>%
    pivot_wider(names_from = Sex, values_from = qx_mo) # columnas: Female, Male

  years <- ASMP %>%
    pull(year) %>%
    unique()
  rows_ageM <- ASMP %>%
    pull(Age_up) %>%
    unique() %>%
    seq_along()

  for (year in years) {
    n <- which(year == years)
    n_row <- (n - 1) * 101 + rows_ageM

    outfilename <- file(file.path(rates_dir, paste0(country, "mort", year)), "w")
    cat(c("** Period (Monthly) Age-Specific Probabilities of Death for", country, "in", year, "\n"),
      file = outfilename
    )
    cat(c("* Retrieved from the World Population Prospects 2024. Single age life tables", "\n"),
      file = outfilename
    )
    cat(c("** The final age interval is limited to one year [100-101)", "\n"), file = outfilename)
    cat("\n", file = outfilename)

    # Mujeres solteras (columnas year, Age_up, Month, Female, Male -> quitar year y Male)
    cat("death", "1", "F", "single", "\n", file = outfilename)
    for (i in n_row) cat(c(as.matrix(ASMP)[i, -c(1, 5)], "\n"), file = outfilename)
    cat("\n", file = outfilename)

    # Hombres solteros (quitar year y Female)
    cat("death", "1", "M", "single", "\n", file = outfilename)
    for (i in n_row) cat(c(as.matrix(ASMP)[i, -c(1, 4)], "\n"), file = outfilename)

    close(outfilename)
  }
}

Toda la simulación (tasas, población inicial y resultados de SOCSIM) se guarda dentro de la carpeta socsim/, para no ensuciar la raíz del proyecto:

[5.4]

folder <- file.path(getwd(), "socsim")
dir.create(folder, showWarnings = FALSE)
rates_dir <- file.path(folder, "rates")

Como datos de entrada de fecundidad, utilizamos todo el rango de edades de las tasas de fecundidad por edad de la madre (para todos los órdenes de nacimiento) para cada año calendario, proporcionadas por el WPP 2024 [15-49]. Además, SOCSIM requiere una categoría de edad final con un límite superior correspondiente a la esperanza de vida máxima. En este caso, la establecemos en el rango [50-100] para ser coherentes con la estructura de las tablas de mortalidad del WPP. En este ejercicio, las tasas son idénticas para todos los estados civiles. Sin embargo, en los archivos de tasas deben especificarse, al menos, para las mujeres solteras y casadas (single, married). Para los demás estados civiles (divorciadas, viudas y convivientes), se aplican las reglas predeterminadas para las tasas en SOCSIM.

Como datos de entrada de mortalidad, SOCSIM requiere probabilidades de muerte (qx) de las tablas de mortalidad de periodo. Utilizamos todo el rango de edades de las tablas de mortalidad por edad simple proporcionadas por WPP 2024 [0-100]. El intervalo final de edad “100” se limita a un año, es decir, [100-101]. Las probabilidades de muerte son idénticas para todos los estados civiles de cada sexo. Sin embargo, para este ejercicio sólo se especifican para mujeres solteras y hombres solteros (single) en los archivos de tasas. Los demás estados civiles seguirán las reglas predeterminadas para las tasas en SOCSIM.

Ejecutemos las siguientes funciones para convertir al formato SOCSIM (mensuales) los datos de fecundidad y de mortalidad de WPP 2024 (los .parquet por país).

[5.5]

# Escribir los archivos de tasas para Colombia (ISO3 = "COL") en socsim/rates/
write_socsim_fertility_rates_WPP(country = "Colombia", iso = "COL", rates_dir = rates_dir)
write_socsim_mortality_rates_WPP(country = "Colombia", iso = "COL", rates_dir = rates_dir)

# Ejemplo: los archivos escritos para 1950
list.files(rates_dir, pattern = "1950")
## [1] "Colombiafert1950" "Colombiamort1950"

5.4 Población inicial

Ahora que tenemos los archivos de tasas, vamos a crear los archivos iniciales de población (.opop) y matrimonio (.opop). Por cuestiones prácticas del taller, usaremos una población inicial pequeña para reducir el tiempo de ejecución de la simulación y de cómputo del código posterior. El archivo .opop inicial tendrá un tamaño de 1000, con sexo y fechas de nacimiento asignados aleatoriamente, y grupo 1 para todos. Las demás columnas se completarán durante la simulación. El archivo .omar inicial será un archivo vacío.

[5.6]

set.seed(250826)
size_opop <- 1000

# Crear la población inicial
presim.opop <- setNames(
  data.frame(matrix(0, ncol = 14, nrow = size_opop)),
  c(
    "pid", "fem", "group", "nev", "dob", "mom", "pop",
    "nesibm", "nesibp", "lborn", "marid", "mstat", "dod", "fmult"
  )
)
presim.opop$pid <- 1:size_opop
presim.opop$fem <- sample(0:1, size_opop, replace = TRUE)
presim.opop$group <- 1
presim.opop$dob <- sample(500:1000, size_opop, replace = TRUE)

# Guardar la población inicial para la presimulación
write.table(presim.opop, file.path(folder, "presim.opop"), row.names = FALSE, col.names = FALSE)
# Crear un data frame vacío para los matrimonios en la población inicial
write.table(data.frame(), file.path(folder, "presim.omar"), row.names = FALSE, col.names = FALSE)

5.5 Correr la simulación

Una vez creados los archivos de tasas de entrada y los archivos iniciales de población y matrimonios, podemos ejecutar la simulación. Para utilizar la función socsim, debemos especificar la carpeta en la que se encuentran los archivos de supervisión y de tasas, el nombre del archivo de supervisión y un número de semilla para la simulación.

El archivo de supervisión socsim_Colombia.sup le indica a SOCSIM qué segmentos simular y con qué tasas. El primer segmento de la simulación se ejecuta durante 100 años (1200 meses) para producir una estructura por edad estable basada en las tasas y probabilidades del WPP para 1950. Cada uno de los segmentos siguientes se ejecuta durante un año (12 meses) con los archivos de fecundidad y mortalidad correspondientes.

Tiempo de cómputo. La simulación tarda algunos minutos. La corremos una vez y guardamos los resultados; si ya existen, solo los cargamos.

[5.7]

folder <- file.path(getwd(), "socsim")
supfile <- "socsim_Colombia.sup"
seed <- "250826"

# Correr la microsimulación y leer sus archivos de salida (población y matrimonios).
# Ojo: el "future" de process_method es el NOMBRE DEL MÉTODO con que rsocsim
# corre la simulación en segundo plano (y así puede mostrar el avance mientras
# corre), no el nombre de un argumento de paquete. Eso sí: para que ese método
# funcione hace falta tener instalado el paquete `future` (Módulo 1), porque
# rsocsim lo declara como sugerido y no se instala solo.
rsocsim::socsim(folder, supfile, seed, process_method = "future")
opop <- rsocsim::read_opop(folder = folder, supfile = supfile, seed = seed, suffix = "", fn = NULL)
omar <- rsocsim::read_omar(folder = folder, supfile = supfile, seed = seed, suffix = "", fn = NULL)

# Guardar los resultados para reutilizarlos (la simulación tarda varios minutos)
saveRDS(list(opop = opop, omar = omar), "data/socsim_resultados.rds")

Los resultados de la simulación están listos. Podemos utilizar las funciones read_opop y read_omar del paquete rsocsim para importar los archivos de población y matrimonio de salida a R.

El archivo de población (.opop) contiene un registro por cada individuo que ha estado vivo durante la simulación. Cada registro (fila) proporciona la siguiente información sobre un individuo determinado: identificador de persona (pid), sexo (fem, 1 para mujer y 0 para hombre), identificador de grupo (group), siguiente evento programado (nev), fecha de nacimiento (dob), identificador de persona de la madre (mom), identificador de persona del padre (pop), identificador de persona del siguiente hermano mayor por vía materna (nesibm), identificador de persona del siguiente hermano mayor por vía paterna (nesibp), identificador de persona del último hijo nacido (lborn), identificador del matrimonio más reciente en .omar (marid), estado civil al final de la simulación (mstat), fecha de defunción (dod, o 0 si está vivo al final de la simulación) y multiplicador de fertilidad (fmult).

[5.8]

head(opop)
##   pid fem group nev dob mom pop nesibm nesibp lborn marid mstat  dod fmult
## 1   1   0     1  65 568   0   0      0      0  1063    63     3 1598     0
## 2   2   0     1  65 994   0   0      0      0  4573   468     4 1589     0
## 3   3   0     1  65 500   0   0      0      0  1068    68     4 1258     0
## 4   4   0     1  65 758   0   0      0      0  1192   162     4 1036     0
## 5   5   0     1  65 721   0   0      0      0  2934    49     4 1547     0
## 6   6   0     1  65 500   0   0      0      0  1267    47     4 1371     0

El archivo de matrimonios (.omar) contiene un registro por cada matrimonio ocurrido durante la simulación. Cada registro de matrimonio proporciona la siguiente información: número identificador del matrimonio (mid), identificador de persona de la esposa (wpid), identificador de persona del esposo (hpid), fecha de inicio del matrimonio (dstart), fecha de finalización del matrimonio (dend, es 0 si estaba vigente al final de la simulación), razón por la que finalizó el matrimonio (rend), identificador del siguiente matrimonio anterior más reciente de la esposa (wprior), identificador del siguiente matrimonio anterior más reciente del esposo (hprior).

[5.9]

head(omar)
##   mid wpid hpid dstart dend rend wprior hprior
## 1   1  300  731   1001 1630    3      0      0
## 2   2  776  422   1001 1548    3      0      0
## 3   3  241  874   1001 1457    3      0      0
## 4   4  696  328   1001 1103    3      0      0
## 5   5  430   35   1001 1430    3      0      0
## 6   6  179  465   1001 1375    3      0      0

5.6 Estimar las tasas a partir de la simulación

Para verificar que la simulación reproduce las tasas de entrada, estimamos las tasas de fecundidad y mortalidad por edad a partir de los microdatos simulados, usando las funciones estimate_fertility_rates() y estimate_mortality_rates() del paquete.

Para ejecutarlas, necesitamos definir algunos argumentos: el archivo .opop opop, el año final de la simulación final_sim_year, los años mínimo y máximo para los que queremos estimar las tasas, [year_min y year_max), el tamaño del grupo de años year_group, la edad mínima y máxima para la fecundidad [age_min_fert y age_max_fert) o la edad máxima para la mortalidad age_max_mort) y el tamaño del grupo de edades age_group. Podemos calcular las tasas para diferentes años y grupos de edad, pero es importante que los años y edades mínimos y máximos correspondan con el tamaño de los grupos.

Estas funciones calculan tasas específicas de fecundidad y mortalidad por edad, utilizando el tamaño de la población a mitad de año por sexo y edad como una estimación de los años-persona vividos durante el año. Debido al tamaño limitado de la población en una microsimulación (especialmente, de supervivientes a edades avanzadas), a veces pocos o ningún individuo de una edad específica están vivos en un momento determinado (1 de julio). Por ello, es posible obtener tasas superiores a 1, iguales a 0 (0 eventos/población), infinitas (eventos/0 población) y valores NaN (0 eventos/0 población).

[5.10]

asfr_sim <- rsocsim::estimate_fertility_rates(
  opop = opop, final_sim_year = 2023,
  year_min = 1950, year_max = 2020, year_group = 5,
  age_min_fert = 15, age_max_fert = 50, age_group = 5
)

asmr_sim <- rsocsim::estimate_mortality_rates(
  opop = opop, final_sim_year = 2023,
  year_min = 1950, year_max = 2020, year_group = 5,
  age_max_mort = 100, age_group = 5
)

Ahora podemos graficar nuestras estimaciones de fecundidad y mortalidad derivadas de la microsimulación para mujeres en algunos años seleccionados.

[5.11]

yrs_plot <- c("[1950,1955)", "[1980,1985)", "[2015,2020)")
age_levels <- levels(asmr_sim$age)

bind_rows(
  asfr_sim %>% mutate(rate = "Fecundidad", sex = "female"),
  asmr_sim %>% mutate(rate = "Mortalidad") %>% filter(sex == "female")
) %>%
  mutate(age = factor(as.character(age), levels = age_levels)) %>%
  filter(socsim != 0 & !is.infinite(socsim) & !is.nan(socsim), year %in% yrs_plot) %>%
  ggplot(aes(x = age, y = socsim, group = year, colour = year)) +
  geom_line(linewidth = 1) +
  facet_wrap(. ~ rate, scales = "free") +
  facetted_pos_scales(y = list(
    scale_y_continuous(),
    scale_y_continuous(trans = "log10")
  )) +
  scale_x_discrete(guide = guide_axis(angle = 90)) +
  scale_color_manual(values = c("#FFCD00", "#003087", "#C8102E")) +
  labs(
    title = "Tasas estimadas a partir de la simulación SOCSIM (mujeres, Colombia)",
    x = "Edad", y = "Estimación", color = "Años"
  ) +
  theme_bw()

¿Qué vemos aquí? Las curvas recuperan los patrones demográficos esperados: la fecundidad dibuja la clásica campana concentrada en las edades reproductivas y se va desplazando entre 1950 y 2020, mientras que la mortalidad muestra su forma en “J” (alta en la infancia, mínima en la juventud y creciente en la vejez). Identificar que la simulación ha reproducido estas formas es la primera señal de que ha funcionado. En la sección siguiente, lo verificaremos comparando los resultados con las tasas de entrada del WPP.

5.7 Comparar SOCSIM con el WPP

Como verificación final, comparamos las tasas específicas de fecundidad y mortalidad por edad obtenidas a partir de los resultados de SOCSIM con los datos originales WPP utilizados como entrada, agregadas a los mismos grupos quinquenales de edad y periodo utilizados en el punto anterior.

[5.12]

col_wpp <- read_parquet("data/wpp_latam_1950_2023/wpp_COL.parquet")

# Cortes de año y edad usados en las estimaciones SOCSIM para fecundidad
yr_breaks_fert <- unique(as.numeric(str_extract_all(asfr_sim$year, "\\d+", simplify = TRUE)))
age_breaks_fert <- unique(as.numeric(str_extract_all(asfr_sim$age, "\\d+", simplify = TRUE)))
yr_range_fert <- min(yr_breaks_fert):max(yr_breaks_fert - 1)

# Fecundidad WPP agregada, para mujeres (5x5)
WPP_fert <- col_wpp %>%
  filter(sex == "f", year %in% yr_range_fert, age >= 15, age <= 49) %>%
  mutate(
    year = cut(year, yr_breaks_fert, right = FALSE),
    age = cut(age, age_breaks_fert, right = FALSE)
  ) %>%
  filter(!is.na(age)) %>%
  summarise(Estimate = mean(fx, na.rm = TRUE), .by = c(year, age)) %>%
  mutate(Source = "WPP", Rate = "Fecundidad")

# Fecundidad SOCSIM
SocsimF <- asfr_sim %>% 
  transmute(year, age,
  Estimate = socsim,
  Source = "SOCSIM", Rate = "Fecundidad"
)

# Cortes de año y edad usados en las estimaciones SOCSIM para mortalidad
yr_breaks_mort <- unique(as.numeric(str_extract_all(asmr_sim$year, "\\d+", simplify = T)))
yr_range_mort <- min(yr_breaks_mort):max(yr_breaks_mort-1)
age_breaks_mort <- unique(as.numeric(str_extract_all(asmr_sim$age, "\\d+", simplify = T)))

# Mortalidad WPP agregada para mujeres (5x5)
WPP_mort <- col_wpp %>%
  filter(sex == "f", year %in% yr_range_mort) %>%
  mutate(
    year = cut(year, yr_breaks_mort, right = FALSE),
    age = cut(age, age_breaks_mort, right = FALSE)
  ) %>%
  filter(!is.na(age)) %>%
  summarise(Estimate = mean(mx, na.rm = TRUE), .by = c(year, age)) %>%
  mutate(Source = "WPP", Rate = "Mortalidad")

# Mortalidad SOCSIM
SocsimM <- asmr_sim %>% 
  filter(sex == "female") %>% 
  transmute(year, age,
  Estimate = socsim,
  Source = "SOCSIM", Rate = "Mortalidad"
)

Finalmente, podemos graficar las tasas de fecundidad y mortalidad por edad para mujeres en Colombia obtenidas de los resultados SOCSIM y de WPP.

[5.13]

bind_rows(WPP_fert, SocsimF, WPP_mort, SocsimM) %>%
  filter(Estimate != 0 & !is.infinite(Estimate) & !is.nan(Estimate)) %>% 
  mutate(age = factor(as.character(age), levels = age_levels)) %>%
  filter(year %in% yrs_plot) %>% 
  ggplot(aes(x = age, y = Estimate, group = interaction(year, Source)))+
  facet_wrap(. ~ Rate, scales = "free") + 
  geom_line(aes(colour = year, linetype = Source), linewidth = 1)+
  scale_linetype_manual(values = c("WPP" = "11","SOCSIM" = "solid")) +
  facetted_pos_scales(y = list(ASFR = scale_y_continuous(),
                               ASMR =  scale_y_continuous(trans = "log10")))+
  scale_x_discrete(guide = guide_axis(angle = 90)) +
  scale_color_manual(values = c("#FFCD00", "#003087", "#C8102E"))+
  labs(title = "Tasas específicas de fecundidad y mortalidad por edades quinquenales 
       \n obtenidas de WPP y una simulación SOCSIM para Colombia (1950-2023)", 
       x = "Edades", y = "Estimación", 
       color = "Años", linetype = "Fuente") + 
  theme_bw()

En general, las tasas derivadas de la microsimulación se aproximan a las del WPP usadas como entrada, lo que nos permite considerar los resultados como suficientemente válidos para el analisis. Las diferencias se reducen al aumentar el tamaño de la población inicial. En el Módulo 6 usamos estos resultados para estudiar la pérdida y disponibilidad de parientes.

Módulo 6

Módulo 6 · Simulaciones: pérdida de parientes y conclusiones

A cargo de Liliana Calderón. (Adaptado del taller de la Escuela ALAP 2024; sección de pérdida de parientes preparada originalmente por Mallika Snyder.)

Una vez corrida la simulación (Módulo 5), SOCSIM nos proporciona una genealogía sintética de toda la población: sabemos cuándo nace, se casa y muere cada individuo, y quiénes son sus padres y su cónyuge. Con estos datos, podemos reconstruir redes de parentesco extensas para cada individuo, incluso parientes lejanos que son difíciles de captar en un censo o una encuesta. En este taller, mostraremos un ejemplo de cómo han cambiado las tasas de pérdida parientes a lo largo del tiempo. Este enfoque complementa los modelos analíticos de los módulos 2 y 3. Sin embargo, hay muchas más formas de utilizar SOCSIM para estudiar estas y otras cuestiones sobre las dinámicas de parentesco.

[6.1]

library(rsocsim)
library(tidyverse)
library(data.table)

Cargamos los resultados de la simulación del Módulo 5:

[6.2]

archivo_sim <- "data/socsim_resultados.rds"

if (!file.exists(archivo_sim)) {
  stop("Ejecuta primero el Módulo 5: es el que genera ", archivo_sim, ".")
}

sim <- readRDS(archivo_sim)
opop <- sim$opop
omar <- sim$omar

Contenido de este módulo:

6.1 Preparar los datos

SOCSIM registra el tiempo en meses. Una función auxiliar convierte los meses en años calendario, y con ella calculamos el año de nacimiento y de defunción de cada individuo (a quienes siguen vivos al final les asignamos el último mes simulado como fecha de defunción):

[6.3]

asYr <- function(month, last_month, final_sim_year) {
  final_sim_year - trunc((last_month - month) / 12)
}

last_month <- max(opop$dob)
final_sim_year <- 2023

opop <- opop %>%
  mutate(
    dod = if_else(dod == 0, last_month, dod),
    dob_year = asYr(dob, last_month, final_sim_year),
    dod_year = asYr(dod, last_month, final_sim_year)
  )

6.2 Una función para estimar la pérdida de parientes

Para identificar a los parientes en SOCSIM, utilizamos relaciones de parentesco por consanguinidad directa -como padres e hijos- y afinidad -como cónyuges-. Este es el principio en el que se basa la función retrieve_kin() incluida en rsocsim que puede utilizarse para identificar parientes de diversos tipos (padres, hijos, abuelos, hermanos, cónyuges, y mucho más). Puedes leer la documentación completa de esta función escribiendo ?retrieve_kin en la consola.

Además de permitirnos identificar más fácilmente las redes de parentesco, SOCSIM también nos proporciona información valiosa sobre la cronología de los eventos vitales, como nacimientos, muertes y matrimonios, en estas redes. Esto puede ayudarnos a relacionar los cambios en las tasas demográficas con los cambios en las redes de parentesco disponibles para nuestros individuos simulados, a menudo a un nivel temporal muy preciso (meses o años)

En este ejercicio, usamos como grupo de referencia a las mujeres de 25 a 39 años que están vivas en un año determinado (la muestra cambia cada año). La función getKinLoss() identifica a esas mujeres, recupera a sus parientes con rsocsim::retrieve_kin() y calcula, para cada tipo de pariente, qué proporción de la muestra perdió a un familiar ese año y qué proporción tenía un familiar vivo el año anterior. El código es una versión simplificada de las funciones utilizadas en un trabajo de investigación anterior (Snyder et al. 2022).

[6.4]

getKinLoss <- function(year_of_interest, opop, omar) {
  pid_data <- opop %>%
    filter(
      data.table::between(year_of_interest, dob_year, dod_year, incbounds = FALSE),
      fem == 1
    ) %>%
    mutate(age = year_of_interest - dob_year) %>%
    filter(data.table::between(age, 25, 39, incbounds = TRUE))
  pid_vec <- pid_data$pid

  kin <- rsocsim::retrieve_kin(
    opop = opop, omar = omar, pid = pid_vec,
    extra_kintypes = NULL, kin_by_sex = FALSE
  )

  bind_rows(lapply(seq_along(kin), function(x) {
    kin2 <- unlist(kin[[x]], use.names = FALSE)
    names(kin2) <- rep(pid_vec, unlist(lapply(kin[[x]], length)))
    dob_k <- opop$dob_year[match(kin2, opop$pid)]
    dod_k <- opop$dod_year[match(kin2, opop$pid)]
    vivo_antes <- if_else(
      data.table::between(year_of_interest - 1, dob_k, dod_k, NAbounds = NA, incbounds = FALSE),
      TRUE, FALSE
    )
    muere_ahora <- dod_k %in% year_of_interest

    tibble(
      kintype = names(kin[x]),
      year = year_of_interest,
      n_total = length(pid_vec),
      n_losekin = length(unique(names(kin2[muere_ahora]))),
      n_withkin = length(unique(names(kin2[vivo_antes == TRUE]))),
      pc_losekin_total = 100 * n_losekin / n_total,
      pc_withkin = 100 * n_withkin / n_total
    )
  }))
}

6.3 Estimar la pérdida a lo largo del tiempo

Ejecutamos la función para recuperar partientes en intervalos de 10 años entre 1950 y 2020, y guardamos el resultado.

[6.5]

kinloss_data <- bind_rows(lapply(
  seq(1950, 2020, by = 10),
  function(y) getKinLoss(year_of_interest = y, opop = opop, omar = omar)
))
saveRDS(kinloss_data, "data/socsim_kinloss.rds")

Añadimos etiquetas legibles y un orden a los tipos de pariente:

[6.6]

kinloss_data <- kinloss_data %>%
  mutate(
    kintype = recode(kintype,
      ggparents = "Bisabuelos", gparents = "Abuelos", parents = "Padres",
      siblings = "Hermanos", spouse = "Cónyuges", children = "Hijos",
      gchildren = "Nietos"
    ),
    kintype = fct_relevel(
      kintype, "Bisabuelos", "Abuelos", "Padres",
      "Hermanos", "Cónyuges", "Hijos", "Nietos"
    )
  )

6.4 Resultados

Pérdida de parientes de las mujeres de 25–39 años a lo largo del tiempo:

[6.7]

kinloss_data %>%
  ggplot(aes(x = year, y = pc_losekin_total, colour = kintype)) +
  geom_line(linewidth = 1) +
  scale_x_continuous(breaks = seq(1950, 2020, by = 10)) +
  labs(
    x = "Año", y = "Mujeres de 25-39 años que pierden un pariente (%)",
    colour = "Tipo de pariente"
  ) +
  theme_bw()

Disponibilidad de parientes (proporción con un familiar vivo el año anterior):

[6.8]

kinloss_data %>%
  ggplot(aes(x = year, y = pc_withkin, colour = kintype)) +
  geom_line(linewidth = 1) +
  scale_x_continuous(breaks = seq(1950, 2020, by = 10)) +
  labs(
    x = "Año", y = "Mujeres de 25-39 años con un pariente vivo el año anterior (%)",
    colour = "Tipo de pariente"
  ) +
  theme_bw()

Interpretación. Como cabría esperar para este grupo de edad, las tasas más altas de pérdida corresponden a abuelos y padres. El aumento de la disponibilidad de abuelos a lo largo del tiempo refleja la mayor esperanza de vida; la caída en la disponibilidad de hijos y cónyuges refleja el descenso de la fecundidad y la nupcialidad.

6.5 Conclusiones

En este taller recorrimos dos familias de métodos para la demografía del parentesco y del duelo:

  • Los modelos analíticos matriciales (DemoKin, Módulos 2–3), que dan valores esperados de parientes vivos y fallecidos de forma rápida y transparente, y que usamos para estimar el duelo a nivel poblacional (incidencia, multiplicadores, prevalencia y su distribución por edad).
  • La microsimulación (SOCSIM, Módulos 5–6), que genera genealogías completas y permite estudiar redes de parentesco extensas y la cronología de los eventos vitales.

Ambos enfoques son complementarios: los modelos analíticos son eficientes y exactos en la media; la microsimulación captura la variabilidad individual y relaciones de parentesco difíciles de modelar analíticamente. Juntos ofrecen un conjunto de herramientas potente para cuantificar cómo la mortalidad —y en particular la violencia— reverbera a través de las familias.

Más información. Documentación de rsocsim: https://mpidr.github.io/rsocsim/. Documentación de DemoKin: https://github.com/IvanWilli/DemoKin.

Soluciones

Soluciones · ejercicio del Módulo 4 (resuelto para Costa Rica)

Esta pestaña resuelve, paso a paso y con código comentado, el ejercicio del Módulo 4 para Costa Rica, usando solo datos del WPP y el archivo de tasas de mortalidad por homicidio. Es la plantilla que puede adaptar a su país: basta con cambiar el código ISO3.

Tasas de mortalidad por homicidio. Como referencia de mortalidad violenta usamos las tasas específicas por homicidio del país (data/homicide_mortality_rates.csv), calculadas a partir de estimaciones de la Global Burden of Disease 2023 para 20 países de la región. Los resultados reflejan entonces el duelo por mortalidad violenta. Estas tasas cubren 2000–2023, por lo que el análisis del duelo se concentra en ese período.

Contenido:

[S.1]

library(tidyverse)
library(arrow)
library(DemoKin)

S.1 Insumos y estructura de parentesco

[S.2]

iso <- "CRI" # <- cambie por su país
anio_inicial <- 2000 # primer año con datos de homicidio (GBD)
anio_final <- 2023 # último año del análisis (último año disponible)

# Datos WPP del país (supervivencia, fecundidad, población)
pais <- open_dataset("data/wpp_latam_1950_2023/", format = "parquet") |>
  filter(iso3 == iso) |>
  collect() |>
  as_tibble()

# Población focal y exposición (sin ajuste por inmigrantes en este ejemplo)
pop_focal <- pais %>% transmute(year, sex_focal = sex, age_focal = age, pop)
exposicion <- pais %>%
  filter(year == anio_final) %>%
  transmute(sex_focal = sex, age_focal = age, exposicion = pop)
poblacion <- sum(exposicion$exposicion)

# Tasas de mortalidad por homicidio (GBD 2023, 2000-2023).
# Convertimos la tasa mx en probabilidad qx (ax = 0.5).
qx_kin <- read_csv("data/homicide_mortality_rates.csv", show_col_types = FALSE) %>%
  filter(iso3 == iso) %>%
  mutate(qx = mx / (1 + 0.5 * mx)) %>%
  transmute(year, sex_kin = sex, age_kin = age, qx_kin = qx)

# Etiquetas y grupos de familia
etiquetas_kin <- c(
  d = "Hijas e hijos", m = "Madres y padres", s = "Hermanas y hermanos",
  gm = "Abuelas y abuelos", gd = "Nietas y nietos", a = "Tías y tíos",
  n = "Sobrinas y sobrinos", c = "Primas y primos"
)
parientes_cercanos <- c("d", "m", "s")
parientes_extendidos <- c("gm", "gd", "a", "n", "c")

Corremos el modelo de parentesco para el país: kin2sex para Focal mujer y copiamos el resultado para Focal hombre (por eficiencia, como en el Módulo 2). Tarda unos minutos; lo calculamos una vez, lo guardamos y lo reutilizamos (caché).

[S.3]

# reshape_wpp(): toma los datos largos del WPP y devuelve UNA matriz con las
# edades en las filas y los años en las columnas (el formato que espera
# DemoKin). Argumentos: dat = los datos del país; variable = la columna que
# queremos ("px", "fx" o "pop"); which_sex = "f" o "m".
reshape_wpp <- function(dat, variable, which_sex) {
  dat %>%
    filter(sex == which_sex) %>%
    select(age, year, value = all_of(variable)) %>%
    arrange(age, year) %>%
    pivot_wider(names_from = year, values_from = value) %>%
    select(-age) %>%
    as.matrix()
}

archivo_kin <- file.path("data", paste0("kin_", iso, ".parquet"))

if (!file.exists(archivo_kin)) {
  pf <- reshape_wpp(pais, "px", "f")
  pm <- reshape_wpp(pais, "px", "m")
  ff <- reshape_wpp(pais, "fx", "f")
  fm <- ff # supuesto androgino
  nf <- reshape_wpp(pais, "pop", "f")
  nm <- reshape_wpp(pais, "pop", "m")

  # Correr el modelo para Focal mujer y copiarlo para Focal hombre.
  # Acotamos la salida a los años con datos de homicidio (2000-2023).
  kin_f <- kin2sex(
    pf = pf, pm = pm, ff = ff, fm = fm, nf = nf, nm = nm,
    time_invariant = FALSE, output_period = anio_inicial:anio_final,
    output_kin = c("d", "m", "s", "gm", "gd", "a", "n", "c"),
    sex_focal = "f", birth_female = 0.5
  )
  kin <- bind_rows(
    as_tibble(kin_f$kin_full) %>% mutate(sex_focal = "f"),
    as_tibble(kin_f$kin_full) %>% mutate(sex_focal = "m")
  ) %>%
    transmute(year, sex_focal, age_focal, kin, sex_kin, age_kin, living) %>%
    filter(living >= 1e-6)
  write_parquet(kin, archivo_kin)
}

kin <- read_parquet(archivo_kin)

S.2 Probabilidades de pérdida

# Paso 2: probabilidad anual de NO perder ningún pariente del tipo k
p0_anual <- kin %>%
  left_join(qx_kin, by = c("year", "sex_kin", "age_kin")) %>%
  mutate(p0x = (1 - qx_kin)^living) %>%
  summarise(p0 = prod(p0x, na.rm = TRUE), .by = c(year, sex_focal, age_focal, kin))

# Paso 3: probabilidad acumulada (producto por cohorte); nos quedamos con anio_final
p0_acum <- p0_anual %>%
  group_by(sex_focal, cohorte = year - age_focal, kin) %>%
  arrange(age_focal, .by_group = TRUE) %>%
  mutate(p0_acum = cumprod(p0)) %>%
  ungroup() %>%
  filter(year == anio_final)

S.3 Medida 1: incidencia anual

[S.4]

# incidencia_familia_anual(): cuántas personas quedan en duelo CADA AÑO por un
# grupo de parientes. Argumentos: tipos = qué parientes forman el grupo
# (p. ej. c("d","m","s")); etiqueta = el nombre que llevará el grupo en el
# gráfico. Devuelve una fila por año, con las personas en duelo y la etiqueta.
incidencia_familia_anual <- function(tipos, etiqueta) {
  p0_anual %>%
    filter(kin %in% tipos) %>%
    summarise(p0 = prod(p0), .by = c(year, sex_focal, age_focal)) %>%
    left_join(pop_focal, by = c("year", "sex_focal", "age_focal")) %>%
    mutate(en_duelo = (1 - p0) * pop) %>%
    summarise(en_duelo = sum(en_duelo), .by = year) %>%
    mutate(grupo = etiqueta)
}

incidencia_familia <- bind_rows(
  incidencia_familia_anual(parientes_cercanos, "Familia cercana"),
  incidencia_familia_anual(parientes_extendidos, "Familia extendida")
)

incidencia_familia %>%
  ggplot(aes(x = year, y = en_duelo / 1000, fill = grupo)) +
  geom_col(position = position_dodge(width = 0.8), width = 0.7) +
  scale_fill_manual(values = c(
    "Familia cercana" = "#b56576", "Familia extendida" = "#355070"
  )) +
  labs(
    title = paste0("Incidencia anual del duelo por homicidio (", iso, ")"),
    x = "Año", y = "Personas en duelo (miles)", fill = "Grupo de familia"
  ) +
  theme_bw()

S.4 Medida 2: multiplicadores

[S.5]

# muertes totales por homicidio del período (denominador del multiplicador)
muertes_total <- read_csv("data/homicide_mortality_rates.csv", show_col_types = FALSE) %>%
  filter(iso3 == iso, year %in% anio_inicial:anio_final) %>%
  left_join(pais %>% select(year, sex, age, pop), by = c("year", "sex", "age")) %>%
  summarise(m = sum(mx * pop, na.rm = TRUE)) %>%
  pull(m)

# incidencia_grupo(): igual que incidencia_familia_anual(), pero devuelve UN
# SOLO número: el total de personas en duelo de todo el período, sin separar por
# año. Es el numerador del multiplicador de duelo.
incidencia_grupo <- function(tipos) {
  p0_anual %>%
    filter(kin %in% tipos) %>%
    summarise(p0 = prod(p0), .by = c(year, sex_focal, age_focal)) %>%
    left_join(pop_focal, by = c("year", "sex_focal", "age_focal")) %>%
    mutate(en_duelo = (1 - p0) * pop) %>%
    summarise(en_duelo = sum(en_duelo)) %>%
    pull(en_duelo)
}

mult_kin <- p0_anual %>%
  left_join(pop_focal, by = c("year", "sex_focal", "age_focal")) %>%
  mutate(en_duelo = (1 - p0) * pop) %>%
  summarise(personas = sum(en_duelo), .by = kin) %>%
  mutate(kin = recode(kin, !!!etiquetas_kin))

mult_grupos <- tibble(
  kin = c("Familia cercana", "Familia extendida", "Cercana o extendida"),
  personas = c(
    incidencia_grupo(parientes_cercanos),
    incidencia_grupo(parientes_extendidos),
    incidencia_grupo(names(etiquetas_kin))
  )
)

bind_rows(mult_kin, mult_grupos) %>%
  transmute(
    Pariente = kin,
    `Personas en duelo (incidencia)` = round(personas),
    `Muertes` = round(muertes_total),
    Multiplicador = round(personas / muertes_total, 1)
  ) %>%
  knitr::kable(format.args = list(big.mark = ","))
Pariente Personas en duelo (incidencia) Muertes Multiplicador
Tías y tíos 95,107 12,237 7.8
Primas y primos 378,049 12,237 30.9
Hijas e hijos 18,481 12,237 1.5
Nietas y nietos 15,735 12,237 1.3
Abuelas y abuelos 23,855 12,237 1.9
Madres y padres 22,432 12,237 1.8
Sobrinas y sobrinos 84,550 12,237 6.9
Hermanas y hermanos 39,581 12,237 3.2
Familia cercana 80,477 12,237 6.6
Familia extendida 596,337 12,237 48.7
Cercana o extendida 676,315 12,237 55.3

S.5 Medida 3: prevalencia acumulada

[S.6]

# en_duelo_prev(): cuántas personas VIVAS en el año de referencia han perdido al
# menos un pariente del grupo en algún momento. Parte de p0_acum
# (probabilidades ACUMULADAS a lo largo de la vida) y usa la exposición del año
# de referencia. Devuelve un solo número.
en_duelo_prev <- function(tipos) {
  p0_acum %>%
    filter(kin %in% tipos) %>%
    summarise(p0_acum = prod(p0_acum), .by = c(sex_focal, age_focal)) %>%
    left_join(exposicion, by = c("sex_focal", "age_focal")) %>%
    mutate(b = (1 - p0_acum) * exposicion) %>%
    summarise(personas = sum(b)) %>%
    pull(personas)
}

prev_kin <- tibble(kin = names(etiquetas_kin)) %>%
  mutate(
    personas = map_dbl(kin, en_duelo_prev),
    etiqueta = recode(kin, !!!etiquetas_kin),
    grupo = if_else(kin %in% parientes_cercanos, "Cercana", "Extendida")
  )
prev_grupos <- tibble(
  etiqueta = c("Familia cercana", "Familia extendida", "Cercana o extendida"),
  personas = c(
    en_duelo_prev(parientes_cercanos),
    en_duelo_prev(parientes_extendidos),
    en_duelo_prev(names(etiquetas_kin))
  ),
  grupo = "Grupo"
)
prevalencia <- bind_rows(prev_kin %>% select(etiqueta, personas, grupo), prev_grupos) %>%
  mutate(millones = personas / 1e6, pct = 100 * personas / poblacion)

orden_individual <- c(
  "Hijas e hijos", "Madres y padres", "Hermanas y hermanos",
  "Abuelas y abuelos", "Sobrinas y sobrinos", "Nietas y nietos",
  "Primas y primos", "Tías y tíos"
)
orden_grupo <- c("Familia cercana", "Familia extendida", "Cercana o extendida")

prevalencia %>%
  mutate(
    panel = if_else(grupo == "Grupo", "Grupos de familia", "Parientes individuales"),
    panel = factor(panel, levels = c("Parientes individuales", "Grupos de familia")),
    etiqueta = factor(etiqueta, levels = rev(c(orden_individual, orden_grupo)))
  ) %>%
  ggplot(aes(x = etiqueta, y = millones, fill = grupo)) +
  geom_col() +
  geom_text(aes(label = sprintf("%.1f M (%.0f%%)", millones, pct)), hjust = -0.1, size = 3) +
  coord_flip() +
  facet_grid(panel ~ ., scales = "free_y", space = "free_y") +
  scale_fill_manual(values = c(
    "Cercana" = "#b56576", "Extendida" = "#355070", "Grupo" = "grey55"
  )) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.25))) +
  labs(
    title = paste0("Prevalencia acumulada del duelo en ", anio_final, " (", iso, ")"),
    x = NULL, y = "Personas en duelo (millones)", fill = "Grupo"
  ) +
  theme_bw()

S.6 Medida 4: distribución por edad (pirámide)

[S.7]

pop_final <- pais %>%
  filter(year == anio_final) %>%
  transmute(sex_focal = sex, age_focal = age, pop)

# p0_grupo(): probabilidad acumulada de NO haber perdido a ningún pariente del
# grupo, por sexo y edad de Focal. A diferencia de en_duelo_prev(), no
# multiplica por la población: devuelve la probabilidad, que es lo que necesita
# la pirámide.
p0_grupo <- function(tipos) {
  p0_acum %>%
    filter(kin %in% tipos) %>%
    summarise(p0 = prod(p0_acum), .by = c(sex_focal, age_focal))
}
pC <- p0_grupo(parientes_cercanos) %>% rename(p0_C = p0)
pD <- p0_grupo(parientes_extendidos) %>% rename(p0_D = p0)

piramide <- pC %>%
  left_join(pD, by = c("sex_focal", "age_focal")) %>%
  left_join(pop_final, by = c("sex_focal", "age_focal")) %>%
  mutate(
    `No en duelo` = p0_C * p0_D * pop,
    `Solo familia cercana` = (1 - p0_C) * p0_D * pop,
    `Solo familia extendida` = p0_C * (1 - p0_D) * pop,
    `Familia cercana y extendida` = (1 - p0_C) * (1 - p0_D) * pop
  ) %>%
  pivot_longer(c(
    `No en duelo`, `Solo familia cercana`,
    `Solo familia extendida`, `Familia cercana y extendida`
  ), names_to = "categoria", values_to = "personas") %>%
  mutate(
    categoria = factor(categoria, levels = c(
      "No en duelo", "Solo familia extendida",
      "Familia cercana y extendida", "Solo familia cercana"
    )),
    personas = ifelse(sex_focal == "f", -personas, personas) / 1000
  )

piramide %>%
  ggplot(aes(x = age_focal, y = personas, fill = categoria)) +
  geom_col(width = 1) +
  geom_hline(yintercept = 0, linewidth = 0.2) +
  coord_flip() +
  scale_fill_manual(values = c(
    "No en duelo" = "grey75",
    "Solo familia extendida" = "#355070",
    "Familia cercana y extendida" = "#eaac8b",
    "Solo familia cercana" = "#b56576"
  )) +
  scale_y_continuous(labels = function(x) scales::comma(abs(x))) +
  labs(
    title = paste0("Población de ", iso, " en ", anio_final, " según duelo"),
    subtitle = "Mujeres a la izquierda, hombres a la derecha",
    x = "Edad", y = "Población (miles)", fill = "Situación de duelo"
  ) +
  theme_bw() +
  theme(legend.position = "bottom")

Datos

Datos del taller

Esta pestaña documenta todos los insumos que usamos a lo largo del taller: qué contiene cada archivo, sus columnas, de dónde viene y cómo citarlo o descargarlo. Todos los archivos de entrada se distribuyen en la carpeta data/ del repositorio y pueden descargarse directamente desde los enlaces de abajo.

Convención de columnas comunes: year = año calendario; sex = sexo ("f" mujeres, "m" hombres); age = edad en años simples (0–100).

Contenido:

D.1 World Population Prospects 2024 — América Latina

Base demográfica del taller. Son los insumos (supervivencia, fecundidad y población) que alimentan los modelos de parentesco de todos los módulos de laboratorio. Se usan en los Módulos 1, 2, 4, 5, 6 y en las Soluciones.

Archivo Descripción
data/wpp_latam_1950_2023/ Carpeta con un archivo .parquet por país (wpp_<ISO3>.parquet). Cubre 20 países de América Latina y el Caribe, 1950–2023 (los mismos 20 con datos de homicidio; véase D.2).
data/countries.csv Lista de países incluidos (iso3, country).

Columnas de cada wpp_<ISO3>.parquet (una fila por year × sex × age):

Columna Significado
iso3, country código ISO3 y nombre del país
year, sex, age año (1950–2023), sexo, edad (0–100)
px probabilidad de sobrevivir de la edad x a x+1
qx, mx probabilidad y tasa de mortalidad por edad
fx tasa de fecundidad específica por edad (mujeres; 0 en hombres)
pop población al 1 de enero (personas)

Fuente y referencia. United Nations, Department of Economic and Social Affairs, Population Division (2024). World Population Prospects 2024. Tablas de vida completas por sexo, fecundidad por edad simple y población por edad y sexo. Disponible en https://population.un.org/wpp/. Licencia CC BY 3.0 IGO.

D.2 Tasas de mortalidad por homicidio (Módulo 4)

Insumo del ejercicio del Módulo 4 y de las Soluciones: la mortalidad de referencia con la que se estima el duelo por violencia en el país elegido.

Archivo Descripción
data/homicide_mortality_rates.csv Tasas de mortalidad por homicidio por país, año, sexo y edad.

Columnas: iso3, year, sex, age, mx (tasa de mortalidad por homicidio). Cubre 20 países de la región y los años 2000–2023.

Fuente y referencia. Tasas específicas por homicidio calculadas a partir de estimaciones del Global Burden of Disease 2023 (GBD 2023) para 20 países de América Latina y el Caribe. Institute for Health Metrics and Evaluation (IHME), Global Burden of Disease Study 2023, https://www.healthdata.org/gbd.

D.3 Datos del conflicto colombiano (Módulo 3)

Insumos para reproducir las estimaciones de duelo del conflicto armado colombiano. Provienen del paquete de replicación del artículo Weaponizing Kinship (Acosta et al. 2026). Están en data/colombia/.

Archivo Descripción Columnas
col_demo_1950_2018.parquet Tasas demográficas colombianas 1950–2018: insumos del modelo de parentesco y base para el duelo. year, sex, age, fx (fecundidad), px (supervivencia), nx (población usada como insumo del modelo), pop (población), ax (fracción del último año de vida, convierte mxqx)
col_homicidios_1985_2018.parquet Muertes por homicidio relacionadas con el conflicto, por año, sexo y edad de la víctima (1985–2018). Solo homicidios (se excluyen las desapariciones forzadas). Su suma sobre edad y sexo da el total del conflicto (~618 000), denominador de los multiplicadores de duelo. year, sex, age, dx (número de muertes)
col_inmigrantes_2018.parquet Proporción de inmigrantes por sexo y edad (censo 2018). Se excluyen del riesgo de duelo porque no estuvieron expuestos al conflicto. sex, age, imm_r (proporción inmigrante)

Fuente y referencia. Acosta, E., Alburez-Gutierrez, D., Gargiulo, M., & Torres, C. (2026). Weaponizing Kinship: A Demographic Analysis of Bereavement in the Colombian Conflict. Population and Development Review. doi:10.1111/padr.70048. Los datos originales del conflicto provienen del Joint Non-State Actor and State Violence dataset del proyecto de estadística de derechos humanos; véase el artículo y su material de replicación para el detalle de fuentes y métodos.

D.4 Insumos de la microsimulación SOCSIM (Módulos 5–6)

La microsimulación reutiliza las mismas tasas del WPP (D.1), convertidas al formato de texto que exige SOCSIM. El único archivo propio de esta parte es el archivo de supervisión que ya viene en el repositorio; las funciones que escriben las tasas se definen dentro del propio Módulo 5.

Archivo Descripción
socsim/socsim_Colombia.sup Archivo de supervisión de SOCSIM: define los segmentos a simular (100 años de calentamiento con tasas de 1950 y luego un segmento por año hasta 2023).

Fuente y referencia. SOCSIM: Hammel et al. (1976); Mason (2016). Interfaz en R rsocsim: https://mpidr.github.io/rsocsim/. Las tasas de entrada provienen del WPP 2024 (D.1). Esta parte está adaptada del taller de la Escuela ALAP 2024.

D.5 Archivos que se generan al ejecutar el taller

Los siguientes archivos no se distribuyen: son salidas que el propio código crea la primera vez que se ejecuta y luego reutiliza (caché). Aparecen en el .gitignore.

Archivo Se genera en Descripción
data/colombia/col_kin_1985_2018.parquet Módulo 2 (lo reutiliza el Módulo 3) Estructura de parentesco de Colombia (salida de kin2sex), ~21 MB.
data/kin_<ISO3>.parquet Soluciones (Módulo 4) Estructura de parentesco del país elegido.
data/socsim_resultados.rds Módulo 5 Población (.opop) y matrimonios (.omar) simulados.
data/socsim_kinloss.rds Módulo 6 Pérdida y disponibilidad de parientes estimadas de la simulación.
socsim/rates/, socsim/presim.opop, socsim/presim.omar, socsim/sim_results_*/ Módulos 5–6 Archivos intermedios de SOCSIM.

Como estos archivos se regeneran a partir de los insumos documentados arriba, no es necesario descargarlos: se crean solos al correr los laboratorios en orden.

Bibliografía

Referencias citadas a lo largo del taller:

Acosta, Enrique, Diego Alburez‐Gutierrez, Maria Gargiulo, and Catalina Torres. 2026. “Weaponizing Kinship: A Demographic Analysis of Bereavement in the Colombian Conflict.” Population and Development Review, March, padr.70048. https://doi.org/10.1111/padr.70048.
Alburez‐Gutierrez, Diego, Carl Mason, and Emilio Zagheni. 2021. “The Sandwich Generation Revisited: Global Demographic Drivers of Care Time Demands.” Population and Development Review 47 (4): 997–1023. https://doi.org/10.1111/padr.12436.
Caswell, Hal. 2019. “The Formal Demography of Kinship: A Matrix Formulation.” Demographic Research 41 (September): 679–712. https://doi.org/10.4054/DemRes.2019.41.24.
Caswell, Hal. 2022. “The Formal Demography of Kinship IV: Two-Sex Models and Their Approximations.” Demographic Research 47 (September): 359–96. https://doi.org/10.4054/DemRes.2022.47.13.
Caswell, Hal, and Xi Song. 2021. “The Formal Demography of Kinship. III. Kinship Dynamics with Time-Varying Demographic Rates.” Demographic Research 45: 517–46.
Goodman, Leo A, Nathan Keyfitz, and Thomas W. Pullum. 1974. “Family Formation and the Frequency of Various Kinship Relationships.” Theoretical Population Biology, 27. https://doi.org/10.1016/0040-5809(74)90049-5.
Hammel, E., D Hutchinson, K Wachter, R Lundy, and R Deuel. 1976. The SOCSIM Demographic-Sociological Microsimulation Program: Operating Manual. Institute of International Studies. University of California Berkeley.
Keyfitz, Nathan, and Hal Caswell. 2005. Applied Mathematical Demography. Springer.
Mason, Carl. 2016. Socsim Oversimplified. Berkeley: Demography Lab, University of California.
Snyder, Mallika, Diego Alburez-Gutierrez, Iván Williams, and Emilio Zagheni. 2022. “Estimates from 31 Countries Show the Significant Impact of COVID-19 Excess Mortality on the Incidence of Family Bereavement.” Proceedings of the National Academy of Sciences 119 (26): e2202686119. https://doi.org/10.1073/pnas.2202686119.