Este documento reproduce, de principio a fin, el cálculo de las tasas específicas de fecundidad (TEF) y de la tasa global de fecundidad (TGF) de México para 1985-2025:
NACIM85 a NACIM25 (formato DBF).tabla_nacimientos: grupos de edad de la madre
(filas) por año de ocurrencia (columnas), sumando los
registros de todos los años de registro.tabla_mujeres: población femenina a mitad de
año de CONAPO por grupo de edad y año.Los chunks se ejecutan en el orden en que aparecen y cada uno depende de los anteriores. A lo largo del documento, cada chunk va precedido de una explicación de lo que hace.
El encabezado define el título, el formato HTML (índice flotante,
secciones numeradas, código plegable) y los parámetros
que controlan el comportamiento del documento. Los chunks los leen con
params$nombre.
| Parámetro | Valor por defecto | Para qué sirve |
|---|---|---|
directorio |
ruta de Downloads |
Carpeta con los ZIP, los DBF y el Excel de CONAPO. Es el único lugar donde se define el directorio de trabajo. |
archivo_poblacion |
Pob_Mitad_1950_2070.xlsx |
Nombre del Excel de población a mitad de año de CONAPO. |
extraer_zip |
true |
Si es false, se omite la descompresión (útil cuando los
DBF ya están extraídos). |
recalcular_nacimientos |
true |
Si es false, se reutiliza
resumen_nacimientos.rds en lugar de volver a leer los 41
DBF. |
exportar_excel |
false |
Si es true, genera un Excel con las tres tablas y la
gráfica. |
setup (oculto)No aparece en el HTML (include=FALSE), pero se ejecuta
primero. Hace dos cosas:
opts_knit$set(root.dir = params$directorio) fija el
directorio de trabajo de todos los chunks. Debe usarse
opts_knit y no opts_chunk. Reemplaza al
setwd(), que dentro de un Rmd solo tiene efecto dentro de
su propio chunk.opts_chunk$set(...) define los valores por defecto de
todos los chunks: mostrar el código, ocultar los mensajes,
mostrar las advertencias (útiles para detectar años
faltantes) y centrar las figuras.css (oculto)No es código R sino CSS. Hace que las tablas se desplacen horizontalmente en lugar de desbordar la página (las tablas de 41 años son muy anchas), sin saltos de línea y con letra un poco más pequeña. También amplía el ancho máximo del contenido.
paquetesEste chunk hace cuatro cosas:
foreign
(read.dbf), readxl (lee el Excel de CONAPO),
dplyr, tidyr y purrr
(manipulación de datos y map), stringr
(str_extract), ggplot2 (gráfica) y
knitr (kable).anio_ini, anio_fin, anios (vector
de texto “1985”, …, “2025”, que coincide con los nombres de columna de
las tablas), variables_requeridas y
orden_edades.tabla_html(), que
formatea una tabla con kable, con decimales y separador de
miles.library(foreign)
library(readxl)
library(dplyr)
library(purrr)
library(tidyr)
library(stringr)
library(ggplot2)
library(knitr)
anio_ini <- 1985
anio_fin <- 2025
anios <- as.character(anio_ini:anio_fin)
variables_requeridas <- c("ANO_NAC", "ANO_REG", "EDAD_MADN")
orden_edades <- c("12-14", "15-19", "20-24", "25-29",
"30-34", "35-39", "40-44", "45-49")
# Formato de tablas para HTML
tabla_html <- function(x, digits = 0) {
kable(x, digits = digits, format.args = list(big.mark = ","), align = "r")
}
cat("Directorio de trabajo:", getwd(), "\n")
## Directorio de trabajo: C:/Users/fcrigel/Downloads/natalidad_base_datos_1985_dbf
descomprimir (solo si extraer_zip: true).zip de la carpeta.unzip(list = TRUE) consulta qué contiene
sin extraerlo, y grepl selecciona los
nombres que terminan en .dbf.exdir = "." y
junkpaths = TRUE, que descarta las subcarpetas internas del
ZIP.extraccion) con cuántos DBF
salieron de cada ZIP, y se imprime el total.# Lista todos los .zip de la carpeta y extrae solo los .dbf a la raíz
archivos_zip <- list.files(pattern = "\\.zip$", full.names = TRUE,
ignore.case = TRUE)
cat("Archivos ZIP encontrados:", length(archivos_zip), "\n")
## Archivos ZIP encontrados: 41
extraccion <- map_dfr(archivos_zip, function(zip_path) {
contenido <- unzip(zip_path, list = TRUE)
dbf <- contenido$Name[grepl("\\.dbf$", contenido$Name, ignore.case = TRUE)]
if (length(dbf) > 0) {
unzip(zip_path, files = dbf, exdir = ".", junkpaths = TRUE)
} else {
warning("No se encontró ningún archivo .dbf en: ", basename(zip_path))
}
tibble(zip = basename(zip_path), dbf_extraidos = length(dbf))
})
cat("Total de archivos DBF extraídos:", sum(extraccion$dbf_extraidos), "\n")
## Total de archivos DBF extraídos: 82
verificar-basesNACIMxx.dbf
(sin distinguir mayúsculas) y se detiene con un error claro si no hay
ninguno.NACIM00 antes que
NACIM85.archivos <- list.files(
path = ".",
pattern = "^NACIM[0-9]{2}\\.dbf$",
full.names = TRUE,
ignore.case = TRUE
)
if (length(archivos) == 0) {
stop("No se encontraron archivos NACIM85.dbf a NACIM25.dbf en: ", getwd())
}
# Año de cada base según su nombre (85-99 -> 1985-1999; 00-25 -> 2000-2025)
aa <- as.numeric(str_extract(basename(archivos), "[0-9]{2}"))
anio_archivo <- ifelse(aa >= 85, 1900 + aa, 2000 + aa)
# Orden cronológico (no alfabético)
archivos <- archivos[order(anio_archivo)]
anio_archivo <- sort(anio_archivo)
cat("Bases NACIM encontradas:", length(archivos), "(esperadas: 41)\n")
## Bases NACIM encontradas: 41 (esperadas: 41)
cat(basename(archivos), fill = 100)
## NACIM85.dbf NACIM86.dbf NACIM87.dbf NACIM88.dbf NACIM89.dbf NACIM90.dbf NACIM91.dbf NACIM92.dbf
## NACIM93.dbf NACIM94.dbf NACIM95.dbf NACIM96.dbf NACIM97.dbf NACIM98.dbf NACIM99.dbf NACIM00.dbf
## NACIM01.dbf NACIM02.dbf NACIM03.dbf NACIM04.dbf NACIM05.dbf NACIM06.dbf NACIM07.dbf NACIM08.dbf
## NACIM09.dbf NACIM10.dbf NACIM11.dbf NACIM12.dbf NACIM13.dbf NACIM14.dbf NACIM15.dbf NACIM16.DBF
## NACIM17.DBF NACIM18.DBF NACIM19.DBF NACIM20.DBF nacim21.dbf nacim22.dbf nacim23.dbf nacim24.dbf
## nacim25.dbf
anios_faltantes <- setdiff(anio_ini:anio_fin, anio_archivo)
if (length(anios_faltantes) > 0) {
warning("No se encontró base para los años: ",
paste(anios_faltantes, collapse = ", "))
}
nacimientos-procesoEs el chunk más pesado y tiene dos partes. Cada base se resume dentro de la función (conteo por año de ocurrencia y grupo de edad) para no mantener decenas de millones de registros en memoria.
La función procesar_base(), que se
aplica a cada DBF:
as.is = TRUE para evitar que convierta
textos a factores, y pone los nombres de columna en mayúsculas.ANO_NAC, ANO_REG y
EDAD_MADN; si falta alguna, se detiene indicando el archivo
y la variable.NA sin generar error.rm(df)) y asigna el grupo de
edad con case_when. Las edades fuera de 12-49 o no
especificadas quedan como NA.count(Ano_nac, grupo_edad),
conservando los NA para poder controlarlos después. Así no
se guardan los microdatos, solo unas pocas filas por archivo.gc().La lógica de caché y consolidación:
recalcular_nacimientos es true, o aún
no existe resumen_nacimientos.rds, procesa los 41 archivos
y los combina. Luego suma por año de ocurrencia y grupo de
edad: un mismo año de ocurrencia aparece en varios archivos
(los nacimientos de 1985 registrados en 1985, 1986, etc.), y esa suma
implementa el objetivo de acumular los registros de todos los años de
registro. Después guarda el resultado en el .rds..rds guardado, lo que evita
releer los DBF.procesar_base <- function(ruta_archivo) {
df <- read.dbf(ruta_archivo, as.is = TRUE)
names(df) <- toupper(trimws(names(df)))
faltantes <- setdiff(variables_requeridas, names(df))
if (length(faltantes) > 0) {
stop("Faltan variables en: ", basename(ruta_archivo),
" -> ", paste(faltantes, collapse = ", "))
}
a_num <- function(x) suppressWarnings(as.numeric(trimws(as.character(x))))
datos <- tibble(
Ano_nac = a_num(df$ANO_NAC),
Ano_reg = a_num(df$ANO_REG),
edad_num = a_num(df$EDAD_MADN)
)
rm(df)
datos <- datos %>%
mutate(
grupo_edad = case_when(
edad_num >= 12 & edad_num <= 14 ~ "12-14",
edad_num >= 15 & edad_num <= 19 ~ "15-19",
edad_num >= 20 & edad_num <= 24 ~ "20-24",
edad_num >= 25 & edad_num <= 29 ~ "25-29",
edad_num >= 30 & edad_num <= 34 ~ "30-34",
edad_num >= 35 & edad_num <= 39 ~ "35-39",
edad_num >= 40 & edad_num <= 44 ~ "40-44",
edad_num >= 45 & edad_num <= 49 ~ "45-49",
TRUE ~ NA_character_
)
)
resumen <- datos %>%
count(Ano_nac, grupo_edad, name = "nacimientos") %>%
mutate(archivo = basename(ruta_archivo))
diagnostico <- tibble(
archivo = basename(ruta_archivo),
registros = nrow(datos),
ano_nac_fuera_rango = sum(is.na(datos$Ano_nac) |
datos$Ano_nac < anio_ini |
datos$Ano_nac > anio_fin),
ano_nac_min = suppressWarnings(min(datos$Ano_nac, na.rm = TRUE)),
ano_nac_max = suppressWarnings(max(datos$Ano_nac, na.rm = TRUE)),
ano_reg_min = suppressWarnings(min(datos$Ano_reg, na.rm = TRUE)),
ano_reg_max = suppressWarnings(max(datos$Ano_reg, na.rm = TRUE)),
edad_sin_grupo = sum(is.na(datos$grupo_edad))
)
rm(datos)
gc(verbose = FALSE)
list(resumen = resumen, diagnostico = diagnostico)
}
rds_nac <- "resumen_nacimientos.rds"
if (params$recalcular_nacimientos || !file.exists(rds_nac)) {
resultados <- map(archivos, procesar_base)
resumen_total <- map_dfr(resultados, "resumen") %>%
group_by(Ano_nac, grupo_edad) %>%
summarise(nacimientos = sum(nacimientos), .groups = "drop")
diagnostico_archivos <- map_dfr(resultados, "diagnostico")
saveRDS(list(resumen_total = resumen_total,
diagnostico_archivos = diagnostico_archivos), rds_nac)
} else {
guardado <- readRDS(rds_nac)
resumen_total <- guardado$resumen_total
diagnostico_archivos <- guardado$diagnostico_archivos
}
cat("Total de registros leídos:",
format(sum(diagnostico_archivos$registros), big.mark = ","), "\n")
## Total de registros leídos: 101,799,025
tabla-nacimientosConstruye la tabla de nacimientos (grupos de edad en filas, años de ocurrencia en columnas):
complete() garantiza los 8 grupos por 41 años, con 0
donde no hubo nacimientos. Se hace antes del pivote para que no queden
NA ni columnas faltantes.pivot_wider()
convierte los años en columnas.Total (suma por grupo de edad) y la
fila Total (suma por año), y muestra la tabla.tabla_nacimientos <- resumen_total %>%
filter(
!is.na(grupo_edad),
Ano_nac >= anio_ini, Ano_nac <= anio_fin
) %>%
complete(
grupo_edad = orden_edades,
Ano_nac = as.numeric(anio_ini:anio_fin),
fill = list(nacimientos = 0)
) %>%
mutate(grupo_edad = factor(grupo_edad, levels = orden_edades)) %>%
arrange(grupo_edad, Ano_nac) %>%
pivot_wider(names_from = Ano_nac, values_from = nacimientos) %>%
mutate(grupo_edad = as.character(grupo_edad))
tabla_nacimientos <- tabla_nacimientos %>%
mutate(Total = rowSums(across(-grupo_edad)))
fila_total <- tabla_nacimientos %>%
summarise(across(-grupo_edad, sum)) %>%
mutate(grupo_edad = "Total", .before = 1)
tabla_nacimientos <- bind_rows(tabla_nacimientos, fila_total)
tabla_html(tabla_nacimientos)
| grupo_edad | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 | 1998 | 1999 | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | Total |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 12-14 | 467 | 461 | 563 | 721 | 701 | 1,050 | 1,030 | 1,468 | 1,767 | 2,031 | 2,431 | 2,850 | 4,098 | 7,848 | 8,195 | 9,511 | 8,817 | 8,359 | 8,001 | 8,328 | 8,529 | 8,667 | 8,962 | 9,417 | 9,680 | 9,323 | 8,984 | 9,384 | 9,072 | 8,937 | 8,604 | 7,800 | 7,854 | 7,274 | 6,502 | 4,948 | 5,209 | 5,227 | 4,543 | 4,035 | 2,832 | 234,480 |
| 15-19 | 3,561 | 3,994 | 4,704 | 5,480 | 6,569 | 9,207 | 11,783 | 19,981 | 29,357 | 40,042 | 52,907 | 71,155 | 165,796 | 407,097 | 413,426 | 429,535 | 415,314 | 410,061 | 397,614 | 395,003 | 394,775 | 392,619 | 407,843 | 427,267 | 438,763 | 435,950 | 443,352 | 445,942 | 435,657 | 417,405 | 395,293 | 374,935 | 374,563 | 348,780 | 312,488 | 268,268 | 239,528 | 219,105 | 192,751 | 168,339 | 118,852 | 10,545,061 |
| 20-24 | 5,755 | 6,400 | 7,369 | 8,362 | 10,729 | 14,315 | 19,152 | 32,969 | 46,789 | 63,952 | 84,458 | 112,645 | 287,929 | 773,308 | 769,720 | 783,541 | 751,279 | 743,684 | 728,444 | 718,424 | 703,358 | 702,587 | 704,617 | 707,579 | 700,441 | 699,324 | 702,510 | 714,907 | 705,672 | 693,747 | 681,535 | 649,482 | 626,694 | 588,317 | 539,489 | 497,159 | 450,008 | 431,674 | 383,493 | 336,574 | 247,682 | 18,436,073 |
| 25-29 | 4,995 | 5,730 | 6,504 | 7,325 | 9,333 | 12,421 | 16,222 | 26,522 | 37,209 | 49,733 | 64,784 | 85,386 | 222,586 | 648,337 | 653,788 | 674,282 | 652,033 | 644,339 | 626,406 | 615,835 | 603,954 | 598,641 | 597,309 | 596,581 | 586,049 | 582,020 | 579,804 | 573,421 | 561,439 | 552,348 | 553,575 | 543,105 | 542,444 | 528,987 | 506,478 | 474,549 | 430,101 | 417,416 | 368,957 | 324,202 | 253,216 | 15,838,366 |
| 30-34 | 3,408 | 3,802 | 4,283 | 4,970 | 6,257 | 8,516 | 11,381 | 18,750 | 26,271 | 35,184 | 45,130 | 57,473 | 140,595 | 390,932 | 390,955 | 406,164 | 399,206 | 404,863 | 402,895 | 408,868 | 408,517 | 408,868 | 407,507 | 406,327 | 396,299 | 391,635 | 387,975 | 384,331 | 376,735 | 374,861 | 373,498 | 367,190 | 364,578 | 356,123 | 344,007 | 330,069 | 307,214 | 311,873 | 285,411 | 256,081 | 202,450 | 10,611,452 |
| 35-39 | 2,035 | 2,238 | 2,660 | 2,977 | 3,798 | 4,973 | 6,747 | 10,696 | 14,868 | 19,721 | 25,866 | 33,311 | 75,425 | 182,326 | 181,314 | 188,373 | 182,890 | 181,464 | 179,417 | 179,610 | 180,072 | 182,414 | 186,175 | 190,502 | 191,217 | 192,476 | 194,860 | 187,525 | 183,646 | 182,319 | 181,141 | 178,464 | 178,373 | 176,959 | 172,659 | 166,251 | 155,009 | 157,293 | 144,841 | 129,907 | 103,723 | 5,096,535 |
| 40-44 | 910 | 951 | 1,132 | 1,087 | 1,459 | 2,042 | 2,692 | 4,457 | 6,314 | 8,224 | 10,588 | 13,569 | 26,527 | 51,837 | 51,104 | 52,726 | 49,884 | 48,626 | 48,120 | 46,994 | 46,024 | 46,154 | 45,099 | 44,623 | 44,453 | 43,745 | 43,925 | 45,362 | 44,908 | 45,463 | 45,594 | 44,572 | 44,530 | 44,258 | 43,522 | 42,287 | 39,341 | 39,805 | 36,345 | 32,263 | 24,224 | 1,315,740 |
| 45-49 | 288 | 301 | 358 | 404 | 442 | 574 | 704 | 1,084 | 1,457 | 1,833 | 2,498 | 2,975 | 4,863 | 7,739 | 7,331 | 7,126 | 6,497 | 6,022 | 5,564 | 5,493 | 5,340 | 4,994 | 4,641 | 4,315 | 4,308 | 3,936 | 3,668 | 3,500 | 3,396 | 3,344 | 3,410 | 3,500 | 3,510 | 3,516 | 3,501 | 3,532 | 3,124 | 3,053 | 2,687 | 2,364 | 1,820 | 139,012 |
| Total | 21,419 | 23,877 | 27,573 | 31,326 | 39,288 | 53,098 | 69,711 | 115,927 | 164,032 | 220,720 | 288,662 | 379,364 | 927,819 | 2,469,424 | 2,475,833 | 2,551,258 | 2,465,920 | 2,447,418 | 2,396,461 | 2,378,555 | 2,350,569 | 2,344,944 | 2,362,153 | 2,386,611 | 2,371,210 | 2,358,409 | 2,365,078 | 2,364,372 | 2,320,525 | 2,278,424 | 2,242,650 | 2,169,048 | 2,142,546 | 2,054,214 | 1,928,646 | 1,787,063 | 1,629,534 | 1,585,446 | 1,419,028 | 1,253,765 | 954,799 | 62,216,719 |
control-nacimientosPara cada año de ocurrencia calcula el total de nacimientos, cuántos tienen grupo de edad, cuántos no y el porcentaje sin grupo. Sirve para ver cuánto se pierde por edad no especificada o fuera de 12-49 años.
control_anual <- resumen_total %>%
filter(Ano_nac >= anio_ini, Ano_nac <= anio_fin) %>%
group_by(Ano_nac) %>%
summarise(
total_nacimientos = sum(nacimientos),
con_grupo_edad = sum(nacimientos[!is.na(grupo_edad)]),
sin_grupo_edad = sum(nacimientos[is.na(grupo_edad)]),
.groups = "drop"
) %>%
mutate(pct_sin_grupo = round(100 * sin_grupo_edad / total_nacimientos, 2))
tabla_html(control_anual)
| Ano_nac | total_nacimientos | con_grupo_edad | sin_grupo_edad | pct_sin_grupo |
|---|---|---|---|---|
| 1,985 | 31,372 | 21,419 | 9,953 | 32 |
| 1,986 | 33,368 | 23,877 | 9,491 | 28 |
| 1,987 | 36,761 | 27,573 | 9,188 | 25 |
| 1,988 | 41,269 | 31,326 | 9,943 | 24 |
| 1,989 | 48,940 | 39,288 | 9,652 | 20 |
| 1,990 | 64,857 | 53,098 | 11,759 | 18 |
| 1,991 | 81,346 | 69,711 | 11,635 | 14 |
| 1,992 | 129,180 | 115,927 | 13,253 | 10 |
| 1,993 | 177,714 | 164,032 | 13,682 | 8 |
| 1,994 | 235,202 | 220,720 | 14,482 | 6 |
| 1,995 | 303,984 | 288,662 | 15,322 | 5 |
| 1,996 | 395,784 | 379,364 | 16,420 | 4 |
| 1,997 | 946,268 | 927,819 | 18,449 | 2 |
| 1,998 | 2,497,680 | 2,469,424 | 28,256 | 1 |
| 1,999 | 2,504,433 | 2,475,833 | 28,600 | 1 |
| 2,000 | 2,580,918 | 2,551,258 | 29,660 | 1 |
| 2,001 | 2,495,027 | 2,465,920 | 29,107 | 1 |
| 2,002 | 2,477,304 | 2,447,418 | 29,886 | 1 |
| 2,003 | 2,425,408 | 2,396,461 | 28,947 | 1 |
| 2,004 | 2,407,144 | 2,378,555 | 28,589 | 1 |
| 2,005 | 2,379,913 | 2,350,569 | 29,344 | 1 |
| 2,006 | 2,372,982 | 2,344,944 | 28,038 | 1 |
| 2,007 | 2,388,445 | 2,362,153 | 26,292 | 1 |
| 2,008 | 2,410,505 | 2,386,611 | 23,894 | 1 |
| 2,009 | 2,396,969 | 2,371,210 | 25,759 | 1 |
| 2,010 | 2,377,010 | 2,358,409 | 18,601 | 1 |
| 2,011 | 2,383,883 | 2,365,078 | 18,805 | 1 |
| 2,012 | 2,378,246 | 2,364,372 | 13,874 | 1 |
| 2,013 | 2,334,129 | 2,320,525 | 13,604 | 1 |
| 2,014 | 2,291,428 | 2,278,424 | 13,004 | 1 |
| 2,015 | 2,256,528 | 2,242,650 | 13,878 | 1 |
| 2,016 | 2,182,066 | 2,169,048 | 13,018 | 1 |
| 2,017 | 2,157,276 | 2,142,546 | 14,730 | 1 |
| 2,018 | 2,070,173 | 2,054,214 | 15,959 | 1 |
| 2,019 | 1,954,398 | 1,928,646 | 25,752 | 1 |
| 2,020 | 1,850,916 | 1,787,063 | 63,853 | 3 |
| 2,021 | 1,700,606 | 1,629,534 | 71,072 | 4 |
| 2,022 | 1,670,634 | 1,585,446 | 85,188 | 5 |
| 2,023 | 1,530,190 | 1,419,028 | 111,162 | 7 |
| 2,024 | 1,381,457 | 1,253,765 | 127,692 | 9 |
| 2,025 | 1,058,332 | 954,799 | 103,533 | 10 |
diagnostico-basesMuestra la tabla de diagnóstico por archivo generada en
nacimientos-proceso. Los valores infinitos (que aparecen
cuando una base no tiene datos para el mínimo o el máximo) se reemplazan
por NA. Es la tabla para detectar problemas como años de
dos dígitos o registros fuera de rango.
diagnostico_archivos %>%
mutate(across(where(is.numeric), ~ ifelse(is.finite(.x), .x, NA))) %>%
tabla_html()
| archivo | registros | ano_nac_fuera_rango | ano_nac_min | ano_nac_max | ano_reg_min | ano_reg_max | edad_sin_grupo |
|---|---|---|---|---|---|---|---|
| NACIM85.dbf | 2,655,571 | 2,655,571 | 1 | 99 | 85 | 85 | 87,156 |
| NACIM86.dbf | 2,579,301 | 2,579,301 | 1 | 99 | 86 | 86 | 79,890 |
| NACIM87.dbf | 2,794,390 | 2,794,390 | 1 | 99 | 87 | 87 | 87,238 |
| NACIM88.dbf | 2,622,031 | 2,622,031 | 1 | 99 | 88 | 88 | 95,622 |
| NACIM89.dbf | 2,620,262 | 2,620,262 | 1 | 99 | 89 | 89 | 94,837 |
| NACIM90.dbf | 2,735,312 | 2,735,312 | 1 | 99 | 90 | 90 | 140,803 |
| NACIM91.dbf | 2,756,447 | 2,756,447 | 1 | 99 | 91 | 91 | 133,533 |
| NACIM92.dbf | 2,797,397 | 2,797,397 | 1 | 99 | 92 | 92 | 119,841 |
| NACIM93.dbf | 2,839,686 | 2,839,686 | 1 | 99 | 93 | 93 | 144,719 |
| NACIM94.dbf | 2,904,389 | 2,904,389 | 1 | 99 | 94 | 94 | 178,750 |
| NACIM95.dbf | 2,750,444 | 2,750,444 | 1 | 99 | 95 | 95 | 138,157 |
| NACIM96.dbf | 2,707,718 | 2,707,718 | 1 | 99 | 96 | 96 | 120,429 |
| NACIM97.dbf | 2,698,425 | 2,698,425 | 1 | 99 | 97 | 97 | 128,376 |
| NACIM98.dbf | 2,668,428 | 139,273 | 1,901 | 9,999 | 1,998 | 1,998 | 118,031 |
| NACIM99.dbf | 2,769,089 | 187,733 | 1,901 | 9,999 | 1,999 | 1,999 | 160,071 |
| NACIM00.dbf | 2,798,339 | 233,176 | 1,901 | 9,999 | 2,000 | 2,000 | 189,482 |
| NACIM01.dbf | 2,767,610 | 264,386 | 1,901 | 9,999 | 2,001 | 2,001 | 222,278 |
| NACIM02.dbf | 2,699,084 | 210,390 | 1,901 | 9,999 | 2,002 | 2,002 | 189,844 |
| NACIM03.dbf | 2,655,894 | 226,941 | 1,901 | 9,999 | 2,003 | 2,003 | 203,277 |
| NACIM04.dbf | 2,625,056 | 195,549 | 1,901 | 9,999 | 2,004 | 2,004 | 181,392 |
| NACIM05.dbf | 2,567,906 | 142,876 | 1,901 | 9,999 | 2,005 | 2,005 | 138,658 |
| NACIM06.dbf | 2,505,939 | 127,524 | 1,901 | 9,999 | 2,006 | 2,006 | 126,651 |
| NACIM07.dbf | 2,655,083 | 144,641 | 1,901 | 9,999 | 2,007 | 2,007 | 144,273 |
| NACIM08.dbf | 2,636,110 | 130,854 | 1,901 | 9,999 | 2,008 | 2,008 | 134,372 |
| NACIM09.dbf | 2,577,214 | 101,591 | 1,901 | 9,999 | 2,009 | 2,009 | 116,169 |
| NACIM10.dbf | 2,643,908 | 109,405 | 1,901 | 9,999 | 2,010 | 2,010 | 117,013 |
| NACIM11.dbf | 2,586,287 | 106,591 | 1,901 | 9,999 | 2,011 | 2,011 | 121,744 |
| NACIM12.dbf | 2,498,880 | 70,567 | 1,901 | 9,999 | 2,012 | 2,012 | 82,622 |
| NACIM13.dbf | 2,478,889 | 59,578 | 1,901 | 9,999 | 2,013 | 2,013 | 71,424 |
| NACIM14.dbf | 2,463,420 | 65,271 | 1,901 | 9,999 | 2,014 | 2,014 | 75,402 |
| NACIM15.dbf | 2,353,596 | 52,166 | 1,901 | 9,999 | 2,015 | 2,015 | 66,459 |
| NACIM16.DBF | 2,293,708 | 46,465 | 1,902 | 9,999 | 2,016 | 2,016 | 58,224 |
| NACIM17.DBF | 2,234,039 | 36,856 | 1,902 | 9,999 | 2,017 | 2,017 | 54,271 |
| NACIM18.DBF | 2,162,535 | 31,926 | 1,901 | 9,999 | 2,018 | 2,018 | 46,738 |
| NACIM19.DBF | 2,092,214 | 31,265 | 1,901 | 9,999 | 2,019 | 2,019 | 47,302 |
| NACIM20.DBF | 1,629,211 | 13,875 | 1,923 | 9,999 | 2,020 | 2,020 | 62,688 |
| nacim21.dbf | 1,912,178 | 24,038 | 1,924 | 9,999 | 2,021 | 2,021 | 95,749 |
| nacim22.dbf | 1,891,388 | 29,391 | 1,925 | 9,999 | 2,022 | 2,022 | 120,715 |
| nacim23.dbf | 1,820,888 | 33,928 | 1,926 | 9,999 | 2,023 | 2,023 | 168,386 |
| nacim24.dbf | 1,672,227 | 34,678 | 1,927 | 9,999 | 2,024 | 2,024 | 196,047 |
| nacim25.dbf | 1,678,532 | 46,673 | 1,928 | 9,999 | 2,025 | 2,025 | 259,268 |
tabla-mujeresarchivo_poblacion.^A.{1,2}O$), para no depender de cómo se codifique
la Ñ. La renombra a ANIO y verifica las demás columnas
requeridas.CVE_GEO == 0. Ese último filtro usa solo el renglón
“República Mexicana”, que ya es la suma de las 32 entidades, para no
duplicar la población.complete, pivot_wider y totales del chunk
tabla-nacimientos.conapo <- read_excel(params$archivo_poblacion)
# Estandarizar nombres. La columna del año ("AÑO") se detecta por patrón
# para evitar problemas de codificación con la Ñ.
names(conapo) <- toupper(trimws(names(conapo)))
col_anio <- grep("^A.{1,2}O$", names(conapo), value = TRUE)
if (length(col_anio) != 1) stop("No se pudo identificar la columna del año.")
names(conapo)[names(conapo) == col_anio] <- "ANIO"
variables_pob <- c("ANIO", "CVE_GEO", "EDAD", "SEXO", "POBLACION")
faltantes <- setdiff(variables_pob, names(conapo))
if (length(faltantes) > 0) {
stop("Faltan variables: ", paste(faltantes, collapse = ", "))
}
# El archivo incluye "República Mexicana" (CVE_GEO = 0), que ya es la suma
# de las 32 entidades: se usa solo ese renglón para no duplicar población.
mujeres <- conapo %>%
transmute(
anio = as.numeric(ANIO),
cve_geo = as.numeric(CVE_GEO),
edad = as.numeric(EDAD),
sexo = trimws(as.character(SEXO)),
poblacion = as.numeric(POBLACION)
) %>%
filter(
tolower(sexo) == "mujeres",
cve_geo == 0,
anio >= anio_ini, anio <= anio_fin
) %>%
mutate(
grupo_edad = case_when(
edad >= 12 & edad <= 14 ~ "12-14",
edad >= 15 & edad <= 19 ~ "15-19",
edad >= 20 & edad <= 24 ~ "20-24",
edad >= 25 & edad <= 29 ~ "25-29",
edad >= 30 & edad <= 34 ~ "30-34",
edad >= 35 & edad <= 39 ~ "35-39",
edad >= 40 & edad <= 44 ~ "40-44",
edad >= 45 & edad <= 49 ~ "45-49",
TRUE ~ NA_character_
)
) %>%
filter(!is.na(grupo_edad))
tabla_mujeres <- mujeres %>%
group_by(grupo_edad, anio) %>%
summarise(mujeres = sum(poblacion, na.rm = TRUE), .groups = "drop") %>%
complete(
grupo_edad = orden_edades,
anio = as.numeric(anio_ini:anio_fin),
fill = list(mujeres = 0)
) %>%
mutate(grupo_edad = factor(grupo_edad, levels = orden_edades)) %>%
arrange(grupo_edad, anio) %>%
pivot_wider(names_from = anio, values_from = mujeres) %>%
mutate(grupo_edad = as.character(grupo_edad))
tabla_mujeres <- tabla_mujeres %>%
mutate(Total = rowSums(across(-grupo_edad)))
fila_total <- tabla_mujeres %>%
summarise(across(-grupo_edad, sum)) %>%
mutate(grupo_edad = "Total", .before = 1)
tabla_mujeres <- bind_rows(tabla_mujeres, fila_total)
# Años sin información en el archivo (columnas en cero)
anios_vacios <- names(tabla_mujeres)[
sapply(tabla_mujeres, function(x) is.numeric(x) && all(x == 0))
]
if (length(anios_vacios) > 0) {
warning("Años sin datos en el archivo: ", paste(anios_vacios, collapse = ", "))
}
tabla_html(tabla_mujeres)
| grupo_edad | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 | 1998 | 1999 | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | Total |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 12-14 | 2,965,709 | 3,026,474 | 3,072,211 | 3,098,444 | 3,105,623 | 3,101,053 | 3,095,339 | 3,096,325 | 3,106,144 | 3,124,439 | 3,149,378 | 3,178,147 | 3,206,819 | 3,231,817 | 3,252,316 | 3,271,142 | 3,293,979 | 3,324,378 | 3,361,471 | 3,398,207 | 3,426,105 | 3,440,664 | 3,442,781 | 3,434,080 | 3,419,778 | 3,411,371 | 3,417,233 | 3,433,721 | 3,447,246 | 3,444,108 | 3,422,467 | 3,394,152 | 3,371,302 | 3,359,236 | 3,356,516 | 3,359,673 | 3,363,710 | 3,361,458 | 3,346,574 | 3,317,416 | 3,280,231 | 134,709,237 |
| 15-19 | 4,340,793 | 4,460,789 | 4,579,243 | 4,691,893 | 4,794,115 | 4,879,625 | 4,941,934 | 4,979,055 | 4,995,447 | 4,999,419 | 4,999,936 | 5,005,318 | 5,020,931 | 5,047,211 | 5,081,462 | 5,123,040 | 5,173,306 | 5,228,556 | 5,283,480 | 5,335,204 | 5,391,588 | 5,460,816 | 5,538,324 | 5,609,600 | 5,662,657 | 5,693,010 | 5,698,945 | 5,686,745 | 5,670,895 | 5,662,384 | 5,662,037 | 5,666,681 | 5,670,370 | 5,665,627 | 5,647,119 | 5,618,427 | 5,589,928 | 5,571,193 | 5,564,568 | 5,564,987 | 5,563,771 | 216,820,429 |
| 20-24 | 3,591,645 | 3,704,955 | 3,813,261 | 3,917,894 | 4,019,889 | 4,121,716 | 4,225,149 | 4,328,479 | 4,428,691 | 4,521,998 | 4,602,322 | 4,662,358 | 4,698,233 | 4,711,792 | 4,709,007 | 4,702,153 | 4,707,898 | 4,734,160 | 4,778,766 | 4,834,588 | 4,900,753 | 4,977,631 | 5,061,681 | 5,144,267 | 5,220,877 | 5,297,863 | 5,378,733 | 5,457,736 | 5,526,888 | 5,577,279 | 5,599,663 | 5,595,305 | 5,577,115 | 5,561,170 | 5,556,576 | 5,563,996 | 5,576,853 | 5,586,722 | 5,585,055 | 5,567,936 | 5,540,050 | 201,669,103 |
| 25-29 | 2,883,443 | 2,997,711 | 3,113,326 | 3,228,571 | 3,341,521 | 3,449,799 | 3,552,393 | 3,651,208 | 3,747,978 | 3,843,814 | 3,941,089 | 4,040,999 | 4,140,639 | 4,234,982 | 4,318,150 | 4,386,113 | 4,437,969 | 4,473,200 | 4,494,617 | 4,507,680 | 4,524,140 | 4,556,880 | 4,611,735 | 4,681,088 | 4,757,034 | 4,838,502 | 4,920,910 | 4,999,836 | 5,074,361 | 5,143,314 | 5,207,133 | 5,270,719 | 5,334,712 | 5,394,519 | 5,442,117 | 5,469,917 | 5,475,466 | 5,467,669 | 5,459,302 | 5,459,620 | 5,470,611 | 184,344,787 |
| 30-34 | 2,273,097 | 2,376,872 | 2,483,854 | 2,591,902 | 2,699,260 | 2,806,098 | 2,914,751 | 3,025,341 | 3,136,392 | 3,245,983 | 3,351,765 | 3,452,469 | 3,549,037 | 3,641,887 | 3,730,704 | 3,818,475 | 3,909,773 | 4,003,903 | 4,097,853 | 4,187,403 | 4,269,769 | 4,342,228 | 4,402,270 | 4,445,875 | 4,475,571 | 4,502,522 | 4,535,847 | 4,581,196 | 4,639,278 | 4,705,567 | 4,773,373 | 4,839,056 | 4,902,679 | 4,965,833 | 5,028,763 | 5,093,463 | 5,162,202 | 5,233,563 | 5,299,979 | 5,352,822 | 5,385,792 | 166,234,467 |
| 35-39 | 1,894,238 | 1,940,947 | 1,994,042 | 2,057,119 | 2,133,923 | 2,225,299 | 2,326,059 | 2,430,336 | 2,536,096 | 2,641,535 | 2,746,777 | 2,853,895 | 2,962,418 | 3,070,271 | 3,174,792 | 3,274,049 | 3,368,711 | 3,461,001 | 3,552,629 | 3,644,463 | 3,740,524 | 3,844,629 | 3,955,206 | 4,064,445 | 4,165,518 | 4,254,770 | 4,326,617 | 4,378,164 | 4,412,314 | 4,434,339 | 4,450,911 | 4,471,878 | 4,505,826 | 4,555,120 | 4,616,369 | 4,683,563 | 4,750,981 | 4,819,107 | 4,887,520 | 4,954,478 | 5,023,257 | 147,584,136 |
| 40-44 | 1,619,498 | 1,668,344 | 1,717,286 | 1,765,714 | 1,812,010 | 1,856,178 | 1,901,832 | 1,954,014 | 2,016,170 | 2,091,961 | 2,182,182 | 2,281,492 | 2,383,847 | 2,486,944 | 2,588,631 | 2,689,275 | 2,792,011 | 2,897,178 | 3,003,515 | 3,109,137 | 3,212,893 | 3,315,138 | 3,417,535 | 3,518,642 | 3,617,565 | 3,717,699 | 3,821,049 | 3,925,478 | 4,027,716 | 4,122,653 | 4,203,558 | 4,265,596 | 4,308,448 | 4,336,383 | 4,355,421 | 4,371,237 | 4,391,928 | 4,428,573 | 4,481,896 | 4,546,015 | 4,616,724 | 129,819,366 |
| 45-49 | 1,355,513 | 1,397,976 | 1,442,049 | 1,487,435 | 1,534,725 | 1,582,835 | 1,630,791 | 1,679,044 | 1,726,895 | 1,772,729 | 1,816,537 | 1,861,561 | 1,912,624 | 1,973,056 | 2,046,210 | 2,133,028 | 2,229,037 | 2,328,740 | 2,430,350 | 2,532,220 | 2,635,114 | 2,741,988 | 2,852,885 | 2,964,417 | 3,073,624 | 3,179,078 | 3,280,118 | 3,377,909 | 3,473,944 | 3,568,248 | 3,661,986 | 3,757,511 | 3,854,661 | 3,951,283 | 4,042,905 | 4,120,099 | 4,176,773 | 4,219,707 | 4,252,152 | 4,275,120 | 4,296,374 | 112,629,251 |
| Total | 20,923,936 | 21,574,068 | 22,215,272 | 22,838,972 | 23,441,066 | 24,022,603 | 24,588,248 | 25,143,802 | 25,693,813 | 26,241,878 | 26,789,986 | 27,336,239 | 27,874,548 | 28,397,960 | 28,901,272 | 29,397,275 | 29,912,684 | 30,451,116 | 31,002,681 | 31,548,902 | 32,100,886 | 32,679,974 | 33,282,417 | 33,862,414 | 34,392,624 | 34,894,815 | 35,379,452 | 35,840,785 | 36,272,642 | 36,657,892 | 36,981,128 | 37,260,898 | 37,525,113 | 37,789,171 | 38,045,786 | 38,280,375 | 38,487,841 | 38,687,992 | 38,877,046 | 39,038,394 | 39,176,810 | 1,293,810,776 |
TEF = nacimientos / mujeres, por grupo de edad y año. El renglón Total (TGF) es la suma de las tasas específicas multiplicada por 5.
tasaspreparar() quita la fila y la columna
Total de ambas tablas y ordena los grupos de edad igual en
las dos.stopifnot() comprueba que los grupos coincidan entre
tablas y que estén todos los años; si no, el documento se detiene con un
mensaje específico.Inf o
NaN se convierten en NA.colSums(tasas) × 5, es decir, la suma de las tasas por año
multiplicada por la amplitud del grupo.tabla_tasas con los ocho grupos más el renglón
Total (TGF) y la muestra con 4 decimales.preparar <- function(tabla) {
tabla %>%
filter(grupo_edad != "Total") %>%
select(-any_of("Total")) %>%
arrange(match(grupo_edad, orden_edades))
}
nac <- preparar(tabla_nacimientos)
muj <- preparar(tabla_mujeres)
stopifnot(
"Los grupos de edad no coinciden entre tablas" =
identical(nac$grupo_edad, muj$grupo_edad),
"Faltan años en tabla_nacimientos" = all(anios %in% names(nac)),
"Faltan años en tabla_mujeres" = all(anios %in% names(muj))
)
tasas <- as.matrix(nac[, anios]) / as.matrix(muj[, anios])
tasas[!is.finite(tasas)] <- NA # evita Inf/NaN si mujeres = 0
# Total = TGF = (suma de las tasas específicas) * 5
tgf <- colSums(tasas, na.rm = TRUE) * 5
tabla_tasas <- bind_rows(
data.frame(grupo_edad = nac$grupo_edad, tasas, check.names = FALSE),
data.frame(grupo_edad = "Total (TGF)", t(tgf), check.names = FALSE)
) %>% as_tibble()
tabla_html(tabla_tasas, digits = 4)
| grupo_edad | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 | 1998 | 1999 | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 12-14 | 0.0002 | 0.0002 | 0.0002 | 0.0002 | 0.0002 | 0.0003 | 0.0003 | 0.0005 | 0.0006 | 0.0007 | 0.0008 | 0.0009 | 0.0013 | 0.0024 | 0.0025 | 0.0029 | 0.0027 | 0.0025 | 0.0024 | 0.0025 | 0.0025 | 0.0025 | 0.0026 | 0.0027 | 0.0028 | 0.0027 | 0.0026 | 0.0027 | 0.0026 | 0.0026 | 0.0025 | 0.0023 | 0.0023 | 0.0022 | 0.0019 | 0.0015 | 0.0015 | 0.0016 | 0.0014 | 0.0012 | 0.0009 |
| 15-19 | 0.0008 | 0.0009 | 0.0010 | 0.0012 | 0.0014 | 0.0019 | 0.0024 | 0.0040 | 0.0059 | 0.0080 | 0.0106 | 0.0142 | 0.0330 | 0.0807 | 0.0814 | 0.0838 | 0.0803 | 0.0784 | 0.0753 | 0.0740 | 0.0732 | 0.0719 | 0.0736 | 0.0762 | 0.0775 | 0.0766 | 0.0778 | 0.0784 | 0.0768 | 0.0737 | 0.0698 | 0.0662 | 0.0661 | 0.0616 | 0.0553 | 0.0477 | 0.0428 | 0.0393 | 0.0346 | 0.0302 | 0.0214 |
| 20-24 | 0.0016 | 0.0017 | 0.0019 | 0.0021 | 0.0027 | 0.0035 | 0.0045 | 0.0076 | 0.0106 | 0.0141 | 0.0184 | 0.0242 | 0.0613 | 0.1641 | 0.1635 | 0.1666 | 0.1596 | 0.1571 | 0.1524 | 0.1486 | 0.1435 | 0.1411 | 0.1392 | 0.1375 | 0.1342 | 0.1320 | 0.1306 | 0.1310 | 0.1277 | 0.1244 | 0.1217 | 0.1161 | 0.1124 | 0.1058 | 0.0971 | 0.0894 | 0.0807 | 0.0773 | 0.0687 | 0.0604 | 0.0447 |
| 25-29 | 0.0017 | 0.0019 | 0.0021 | 0.0023 | 0.0028 | 0.0036 | 0.0046 | 0.0073 | 0.0099 | 0.0129 | 0.0164 | 0.0211 | 0.0538 | 0.1531 | 0.1514 | 0.1537 | 0.1469 | 0.1440 | 0.1394 | 0.1366 | 0.1335 | 0.1314 | 0.1295 | 0.1274 | 0.1232 | 0.1203 | 0.1178 | 0.1147 | 0.1106 | 0.1074 | 0.1063 | 0.1030 | 0.1017 | 0.0981 | 0.0931 | 0.0868 | 0.0786 | 0.0763 | 0.0676 | 0.0594 | 0.0463 |
| 30-34 | 0.0015 | 0.0016 | 0.0017 | 0.0019 | 0.0023 | 0.0030 | 0.0039 | 0.0062 | 0.0084 | 0.0108 | 0.0135 | 0.0166 | 0.0396 | 0.1073 | 0.1048 | 0.1064 | 0.1021 | 0.1011 | 0.0983 | 0.0976 | 0.0957 | 0.0942 | 0.0926 | 0.0914 | 0.0885 | 0.0870 | 0.0855 | 0.0839 | 0.0812 | 0.0797 | 0.0782 | 0.0759 | 0.0744 | 0.0717 | 0.0684 | 0.0648 | 0.0595 | 0.0596 | 0.0539 | 0.0478 | 0.0376 |
| 35-39 | 0.0011 | 0.0012 | 0.0013 | 0.0014 | 0.0018 | 0.0022 | 0.0029 | 0.0044 | 0.0059 | 0.0075 | 0.0094 | 0.0117 | 0.0255 | 0.0594 | 0.0571 | 0.0575 | 0.0543 | 0.0524 | 0.0505 | 0.0493 | 0.0481 | 0.0474 | 0.0471 | 0.0469 | 0.0459 | 0.0452 | 0.0450 | 0.0428 | 0.0416 | 0.0411 | 0.0407 | 0.0399 | 0.0396 | 0.0388 | 0.0374 | 0.0355 | 0.0326 | 0.0326 | 0.0296 | 0.0262 | 0.0206 |
| 40-44 | 0.0006 | 0.0006 | 0.0007 | 0.0006 | 0.0008 | 0.0011 | 0.0014 | 0.0023 | 0.0031 | 0.0039 | 0.0049 | 0.0059 | 0.0111 | 0.0208 | 0.0197 | 0.0196 | 0.0179 | 0.0168 | 0.0160 | 0.0151 | 0.0143 | 0.0139 | 0.0132 | 0.0127 | 0.0123 | 0.0118 | 0.0115 | 0.0116 | 0.0111 | 0.0110 | 0.0108 | 0.0104 | 0.0103 | 0.0102 | 0.0100 | 0.0097 | 0.0090 | 0.0090 | 0.0081 | 0.0071 | 0.0052 |
| 45-49 | 0.0002 | 0.0002 | 0.0002 | 0.0003 | 0.0003 | 0.0004 | 0.0004 | 0.0006 | 0.0008 | 0.0010 | 0.0014 | 0.0016 | 0.0025 | 0.0039 | 0.0036 | 0.0033 | 0.0029 | 0.0026 | 0.0023 | 0.0022 | 0.0020 | 0.0018 | 0.0016 | 0.0015 | 0.0014 | 0.0012 | 0.0011 | 0.0010 | 0.0010 | 0.0009 | 0.0009 | 0.0009 | 0.0009 | 0.0009 | 0.0009 | 0.0009 | 0.0007 | 0.0007 | 0.0006 | 0.0006 | 0.0004 |
| Total (TGF) | 0.0383 | 0.0411 | 0.0460 | 0.0503 | 0.0612 | 0.0802 | 0.1023 | 0.1645 | 0.2258 | 0.2951 | 0.3763 | 0.4813 | 1.1404 | 2.9590 | 2.9198 | 2.9698 | 2.8332 | 2.7750 | 2.6828 | 2.6296 | 2.5645 | 2.5214 | 2.4972 | 2.4815 | 2.4291 | 2.3841 | 2.3602 | 2.3307 | 2.2637 | 2.2042 | 2.1554 | 2.0738 | 2.0382 | 1.9462 | 1.8205 | 1.6808 | 1.5274 | 1.4822 | 1.3224 | 1.1650 | 0.8856 |
grafica (fig.width=10,
fig.height=6)seq(1985, 2025, by = 5), nueve años) y excluye el renglón
de TGF.pivot_longer() pasa los datos a formato largo (grupo de
edad, año, tasa) y convierte ambas variables en factores para controlar
el orden.ggplot dibuja una línea con puntos por año.
group = anio hace que cada año sea una línea continua a
través de los grupos de edad, y scale_color_viridis_d
asigna una paleta secuencial de colores.grafica) es la que hace que la figura
aparezca en el HTML.anios_graf <- seq(anio_ini, anio_fin, by = 5) # 1985, 1990, ..., 2025
datos_graf <- tabla_tasas %>%
filter(grupo_edad != "Total (TGF)") %>%
select(grupo_edad, all_of(as.character(anios_graf))) %>%
pivot_longer(-grupo_edad, names_to = "anio", values_to = "tasa") %>%
mutate(
grupo_edad = factor(grupo_edad, levels = orden_edades),
anio = factor(anio, levels = as.character(anios_graf))
)
grafica <- ggplot(datos_graf,
aes(x = grupo_edad, y = tasa, color = anio, group = anio)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
scale_color_viridis_d(name = "Año", option = "D") +
labs(
title = "Tasas específicas de fecundidad por grupo de edad",
subtitle = "México, años quinquenales 1985-2025",
x = "Grupo de edad de la madre",
y = "Nacimientos por mujer"
) +
theme_minimal(base_size = 12) +
theme(legend.position = "right")
grafica
exportar (solo si exportar_excel: true)Con el valor por defecto (false) no se ejecuta. Si se
activa, carga openxlsx (solo aquí, así no es necesario
tenerlo instalado en otro caso), guarda la gráfica como PNG y crea
Fecundidad_1985_2025.xlsx con tres hojas (nacimientos,
mujeres y tasas), con la imagen insertada debajo de la tabla de
tasas.
# Solo se ejecuta con el parámetro exportar_excel: true
library(openxlsx)
ggsave("Tasas_especificas_fecundidad.png", grafica,
width = 10, height = 6, dpi = 300, bg = "white")
wb <- createWorkbook()
addWorksheet(wb, "Nacimientos por edad"); writeData(wb, 1, tabla_nacimientos)
addWorksheet(wb, "Mujeres por edad"); writeData(wb, 2, tabla_mujeres)
addWorksheet(wb, "Tasas especificas"); writeData(wb, 3, tabla_tasas)
insertImage(wb, 3, "Tasas_especificas_fecundidad.png",
width = 10, height = 6, startRow = 13, startCol = 1)
saveWorkbook(wb, "Fecundidad_1985_2025.xlsx", overwrite = TRUE)
CVE_GEO = 0).