Geodatos ancestrales: con R

Automatizando y mapeando los censos con R

Rodrigo Zumaya Tapia · Ana Laura Salguero Melgar

Logo UAM Xochimilco

1 ✨ Introducción

En Geotitlán, los saberes antiguos se entrelazan con las nuevas geotecnologías.
Guiados por Tochtli, la teporingo programadora, este taller nos invita a descubrir cómo la automatización puede transformar la forma en que entendemos el territorio.

A partir del uso de R y sus librerías geoespaciales, aprenderemos a descargar, procesar y mapear datos del INEGI, construyendo indicadores que revelan la diversidad y complejidad del espacio.

Así, lo que antes requería horas de trabajo manual, hoy puede convertirse en un flujo ágil y reproducible: un ritual de código y cartografía, donde la ciencia de datos se convierte en herramienta de cuidado y reflexión sobre el territorio.

Tochtli, la teporingo programadora

Tochtli, la teporingo programadora, nos guía por los senderos del código y la cartografía 🐇💻


1.1 🎯 Objetivo general

Explorar cómo R y sus herramientas geoespaciales permiten automatizar el análisis territorial y crear mapas temáticos, fortaleciendo una lectura crítica y creativa del territorio desde la mirada de Tochtli, guardiana de la geointeligencia en Geotitlán.


1.2 🎯 Objetivos específicos

  • Conocer las principales librerías de R para análisis y visualización geoespacial.
  • Aprender a usar datos del INEGI para generar indicadores territoriales y mapas automatizados.
  • Comprender la importancia de los indicadores sociales, urbanos y ambientales en la caracterización del territorio.
  • Comparar la eficiencia del flujo de trabajo automatizado en R frente a métodos tradicionales en software SIG.
  • Fomentar el pensamiento reproducible y colaborativo en la construcción del conocimiento territorial.

1.3 🧠 Justificación

En el viaje por Geotitlán, cada punto, línea y polígono guarda una historia.
Los nuevos exploradores del territorio necesitan no solo observar, sino interpretar y automatizar los procesos que transforman esos datos en conocimiento.

Inspirados por Tochtli, aprenderemos que programar también es una forma de tejer vínculos con la Tierra:
cada línea de código es un trazo que une el pasado con el futuro, la técnica con la memoria.


1.4 💬 Preguntas conductoras

  1. ¿Qué es un SIG en el lenguaje de los viajeros de Geotitlán?
  2. ¿Puede Tochtli usar R como si fuera un SIG?
  3. Si R no es un SIG, ¿por qué es una herramienta tan poderosa para leer el territorio?
  4. ¿Cómo logra Tochtli hacer que R lea, analice y pinte los datos espaciales del valle?

1.5 🗺️ ¿Qué es un SIG en Geotitlán?

En los caminos de Geotitlán, un Sistema de Información Geográfica (SIG) es como un gran códice que guarda las huellas del territorio.
Permite:

  • Capturar, almacenar y analizar la información que habita en coordenadas.
  • Superponer capas de puntos, líneas y polígonos para contar historias espaciales.
  • Calcular distancias, crear zonas de influencia o visualizar cómo se agrupan los fenómenos.
  • Traducir los datos en mapas temáticos que ayudan a decidir dónde y cómo actuar.
🟢 En palabras de Tochtli:
> “Un SIG combina la memoria del territorio (la base de datos) con su rostro visible (la cartografía).”
Tochtli, la teporingo programadora

Tochtli, la teporingo Usuaria de SIG 🐇💻


1.6 💻 ¿R es un SIG?

“Si Tochtli abre shapefiles, calcula áreas, genera buffers y produce mapas… ¿acaso R es un SIG?”

Respuesta: No exactamente.
R no es un SIG tradicional, pero sí puede comportarse como uno gracias a sus librerías geoespaciales.
En lugar de hacerlo con clics, R lo hace con código, y eso le da algo más poderoso: repetición, automatización y reproducibilidad.

🧩 Tochtli sonríe mientras dice:
> “Un SIG puede hacer un mapa.
> R puede hacer mil mapas con solo cambiar una línea.”


1.7 🧠 ¿Por qué R no es un SIG, pero sí una plataforma geoespacial?

🔹 R no es un SIG porque:
- No tiene una interfaz visual donde arrastrar capas.
- No administra bases espaciales de forma nativa (aunque puede conectarse a PostGIS o GeoPackage).
- No fue creado para la cartografía, sino para pensar con datos.

🔹 Pero sí es una plataforma geoespacial porque:
- Interpreta geometrías, proyecciones y coordenadas.
- Calcula, combina y transforma información espacial.
- Permite integrar análisis estadístico, modelado y visualización geográfica en un mismo lenguaje.

💬 Tochtli lo explica así:
> “Mientras un SIG tradicional analiza el territorio una vez,
> R aprende a hacerlo para siempre.”


1.8 🧭 ¿Cómo puede R operar datos espaciales?

Gracias a sus librerías geoespaciales, R entiende las formas del territorio y las convierte en objetos que se pueden analizar, transformar y mapear.

Función Librería Descripción
Lectura y manejo de geometrías sf (simple features) Abre shapefiles, GeoPackage, GeoJSON; maneja puntos, líneas y polígonos.
Análisis y operaciones espaciales sf, terra, rmapshaper Calcula distancias, buffers, uniones espaciales e intersecciones.
Estadística espacial spdep, spatialreg, gstat Evalúa autocorrelación espacial, modelos SAR/SEM, interpolaciones.
Visualización y cartografía tmap, ggplot2, leaflet, plotly Genera mapas estáticos, temáticos e interactivos.
Conexión y datos externos readr, geojsonio, httr, RPostgres Conecta R con APIs, PostGIS o fuentes abiertas.

🪶 Tochtli dice mientras dibuja un mapa:
> “Cada librería es como una herramienta del viajero:
> una para leer el suelo, otra para medir el aire, otra para pintar la historia.”


1.9 ⚙️ Actividad práctica: Preparar el entorno de trabajo

Antes de que Tochtli inicie su viaje de datos, debe abrir su mochila digital y decirle a R dónde guardará sus hallazgos.
Esto se llama definir el directorio de trabajo, el lugar donde se almacenan los mapas y tablas del viaje.

“Aquí están mis semillas de código y mis rutas geográficas.”

En RStudio, puedes crear un nuevo chunk (una celda de código) con:

  • Ctrl + Alt + I (Windows)
  • Cmd + Option + I (Mac)
# Definir la ruta del taller
ruta_trabajo <- "C:\\geodatos"  # O también: "C:/geodatos"

# Establecer el directorio de trabajo
setwd(ruta_trabajo)

# Confirmar el cambio
getwd()
## [1] "C:/geodatos"

1.10 🧱 ¿Qué es un data frame (df)?

Para Tochtli, un data frame es como una milpa ordenada:
cada fila es una parcela (una observación) y cada columna una planta distinta (una variable).

🌾 Cada fila = una unidad territorial (municipio, AGEB, colonia).
🌿 Cada columna = una característica (población, densidad, índice de juventud, etc.).

💡 En resumen:
Un data frame es una tabla viva, donde cada columna puede tener números, texto o coordenadas,
y donde se siembran los datos que luego florecen en mapas.

🧩 Tochtli concluye:
> “R es nuestro códice digital.
> Si aprendemos a leerlo, el territorio se revela línea a línea, dato a dato, mapa a mapa.”

Tochtli, la teporingo en campo

Tochtli, la teporingo Usuaria de datos de SIG 🐇💻

1.11 1️⃣ Cargar las librerías básicas

Antes de abrir los códices, Tochtli revisa sus herramientas.
En R, estas herramientas se llaman librerías, y permiten leer, limpiar y explorar los datos.

Con ellas puede:

  • 📂 Leer archivos del INEGI.
  • 🧹 Transformar las tablas del censo en estructuras ordenadas.
  • 🗺️ Preparar el terreno para generar indicadores y mapas.

“Sin librerías, el código no florece —recuerda Tochtli—.
Cada función es una semilla que hace crecer el conocimiento.”

library(readr)     # para leer archivos CSV
library(dplyr)     # para manipular datos (filtrar, seleccionar, agrupar)
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(janitor)   # para limpiar nombres de columnas fácilmente
## 
## Adjuntando el paquete: 'janitor'
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
# 🧭 Cargando los códices del territorio
# Tochtli abre los registros del INEGI para iniciar su viaje de datos

# Cargar los archivos de los censos desde la nueva carpeta
iter_2010 <- read_csv("C:/geodatos/Censos/iter_2010.csv")
## Rows: 198488 Columns: 200
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (195): entidad, nom_ent, mun, nom_mun, loc, nom_loc, longitud, altitud, ...
## dbl   (5): latitud, pobtot, vivtot, tvivhab, tam_loc
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
iter_2020 <- read_csv("C:/geodatos/Censos/iter_2020.csv")
## Rows: 195662 Columns: 286
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (283): ENTIDAD, NOM_ENT, MUN, NOM_MUN, LOC, NOM_LOC, LONGITUD, LATITUD, ...
## dbl   (3): POBTOT, VIVTOT, TVIVHAB
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Confirmar que las tablas fueron leídas correctamente
glimpse(iter_2010)
## Rows: 198,488
## Columns: 200
## $ entidad    <chr> "00", "00", "00", "01", "01", "01", "01", "01", "01", "01",…
## $ nom_ent    <chr> "Total nacional", "Total nacional", "Total nacional", "Agua…
## $ mun        <chr> "000", "000", "000", "000", "000", "000", "001", "001", "00…
## $ nom_mun    <chr> "Total nacional", "Total nacional", "Total nacional", "Tota…
## $ loc        <chr> "0000", "9998", "9999", "0000", "9998", "9999", "0000", "00…
## $ nom_loc    <chr> "Total nacional", "Localidades de una vivienda", "Localidad…
## $ longitud   <chr> NA, NA, NA, NA, NA, NA, NA, "1021746", "1022225", "1022127"…
## $ latitud    <dbl> NA, NA, NA, NA, NA, NA, NA, 215251, 215219, 215303, 215116,…
## $ altitud    <chr> NA, NA, NA, NA, NA, NA, NA, "1885", "1903", "1863", "1880",…
## $ pobtot     <dbl> 112336538, 260087, 173056, 1184996, 3395, 2800, 797010, 722…
## $ pobmas     <chr> "54855231", "152757", "98232", "576638", "1803", "1634", "3…
## $ pobfem     <chr> "57481307", "107330", "74824", "608358", "1592", "1166", "4…
## $ p_0a2      <chr> "6157867", "12459", "9369", "71484", "194", "178", "44873",…
## $ p_0a2_m    <chr> "3132624", "6281", "4767", "36375", "94", "99", "22835", "2…
## $ p_0a2_f    <chr> "3025243", "6178", "4602", "35109", "100", "79", "22038", "…
## $ p_3ymas    <chr> "104781265", "245319", "162593", "1109480", "3191", "2609",…
## $ p_3ymas_m  <chr> "51022388", "145291", "92885", "538279", "1705", "1530", "3…
## $ p_3ymas_f  <chr> "53758877", "100028", "69708", "571201", "1486", "1079", "3…
## $ p_5ymas    <chr> "100410810", "236360", "156057", "1059407", "3043", "2507",…
## $ p_5ymas_m  <chr> "48808069", "140703", "89629", "512713", "1624", "1482", "3…
## $ p_5ymas_f  <chr> "51602741", "95657", "66428", "546694", "1419", "1025", "37…
## $ p_12ymas   <chr> "84927468", "205923", "133734", "879679", "2517", "2103", "…
## $ p_12ymas_m <chr> "40947872", "124895", "77973", "421255", "1342", "1260", "2…
## $ p_12ymas_f <chr> "43979596", "81028", "55761", "458424", "1175", "843", "315…
## $ p_15ymas   <chr> "78423336", "191195", "124165", "806727", "2268", "1945", "…
## $ p_15ymas_m <chr> "37656281", "116592", "73001", "384526", "1220", "1181", "2…
## $ p_15ymas_f <chr> "40767055", "74603", "51164", "422201", "1048", "764", "291…
## $ p_18ymas   <chr> "71712388", "176265", "114519", "732571", "2032", "1796", "…
## $ p_18ymas_m <chr> "34279833", "108213", "67873", "347337", "1096", "1089", "2…
## $ p_18ymas_f <chr> "37432555", "68052", "46646", "385234", "936", "707", "2678…
## $ p_3a5      <chr> "6535234", "13306", "9686", "75453", "224", "171", "47951",…
## $ p_3a5_m    <chr> "3316316", "6795", "4869", "38521", "122", "83", "24520", "…
## $ p_3a5_f    <chr> "3218918", "6511", "4817", "36932", "102", "88", "23431", "…
## $ p_6a11     <chr> "13318563", "26090", "19173", "154348", "450", "335", "9822…
## $ p_6a11_m   <chr> "6758200", "13601", "10043", "78503", "241", "187", "50005"…
## $ p_6a11_f   <chr> "6560363", "12489", "9130", "75845", "209", "148", "48216",…
## $ p_8a14     <chr> "15443365", "32498", "22366", "176175", "544", "378", "1128…
## $ p_8a14_m   <chr> "7831926", "17695", "11715", "89301", "286", "200", "57191"…
## $ p_8a14_f   <chr> "7611439", "14803", "10651", "86874", "258", "178", "55629"…
## $ p_12a14    <chr> "6504132", "14728", "9569", "72952", "249", "158", "47148",…
## $ p_12a14_m  <chr> "3291591", "8303", "4972", "36729", "122", "79", "23725", "…
## $ p_12a14_f  <chr> "3212541", "6425", "4597", "36223", "127", "79", "23423", "…
## $ p_15a17    <chr> "6710948", "14930", "9646", "74156", "236", "149", "47860",…
## $ p_15a17_m  <chr> "3376448", "8379", "5128", "37189", "124", "92", "23913", "…
## $ p_15a17_f  <chr> "3334500", "6551", "4518", "36967", "112", "57", "23947", "…
## $ p_18a24    <chr> "14207435", "31095", "21749", "153577", "426", "360", "1036…
## $ p_18a24_m  <chr> "6956877", "18069", "12205", "74878", "245", "196", "51067"…
## $ p_18a24_f  <chr> "7250558", "13026", "9544", "78699", "181", "164", "52537",…
## $ p_15a49_f  <chr> "30703546", "52730", "36553", "327632", "772", "586", "2239…
## $ p_60ymas   <chr> "10055379", "34340", "20494", "89605", "376", "244", "61285…
## $ p_60ymas_m <chr> "4679538", "22119", "11928", "41163", "225", "146", "27248"…
## $ p_60ymas_f <chr> "5375841", "12221", "8566", "48442", "151", "98", "34037", …
## $ rel_h_m    <chr> "95.43", "*", "*", "94.79", "*", "*", "94.12", "93.36", "*"…
## $ pob0_14    <chr> "32515796", "66583", "47797", "374237", "1117", "842", "238…
## $ pob15_64   <chr> "71484423", "166964", "109473", "746380", "2008", "1790", "…
## $ pob65_mas  <chr> "6938913", "24231", "14692", "60347", "260", "155", "40309"…
## $ prom_hnv   <chr> "2.34", "*", "*", "2.35", "*", "*", "2.20", "2.16", "*", "1…
## $ pnacent    <chr> "89918571", "214116", "147458", "936435", "2707", "2145", "…
## $ pnacent_m  <chr> "44019967", "123701", "82083", "459070", "1434", "1224", "2…
## $ pnacent_f  <chr> "45898604", "90415", "65375", "477365", "1273", "921", "306…
## $ pnacoe     <chr> "19747511", "39947", "22462", "233073", "637", "570", "1869…
## $ pnacoe_m   <chr> "9490776", "25764", "14434", "109757", "338", "356", "87621…
## $ pnacoe_f   <chr> "10256735", "14183", "8028", "123316", "299", "214", "99351…
## $ pres2005   <chr> "95431977", "219565", "147917", "998392", "2785", "2280", "…
## $ pres2005_m <chr> "46127432", "128555", "84233", "479423", "1469", "1316", "3…
## $ pres2005_f <chr> "49304545", "91010", "63684", "518969", "1316", "964", "350…
## $ presoe05   <chr> "3292310", "12401", "5279", "41061", "194", "133", "32756",…
## $ presoe05_m <chr> "1640195", "9055", "3408", "20167", "108", "97", "16011", "…
## $ presoe05_f <chr> "1652115", "3346", "1871", "20894", "86", "36", "16745", "1…
## $ p3ym_hli   <chr> "6913362", "25138", "21198", "2493", "10", "10", "1790", "1…
## $ p3ym_hli_m <chr> "3397199", "14563", "11414", "1453", "6", "10", "1032", "94…
## $ p3ym_hli_f <chr> "3516163", "10575", "9784", "1040", "4", "0", "758", "695",…
## $ p3hlinhe   <chr> "1096512", "3552", "4315", "5", "0", "0", "4", "4", "*", "0…
## $ p3hlinhe_m <chr> "422143", "1420", "1687", "3", "0", "0", "2", "2", "*", "0"…
## $ p3hlinhe_f <chr> "674369", "2132", "2628", "2", "0", "0", "2", "2", "*", "0"…
## $ p3hli_he   <chr> "5562979", "20637", "16247", "1223", "8", "6", "939", "875"…
## $ p3hli_he_m <chr> "2849099", "12556", "9375", "741", "5", "6", "563", "525", …
## $ p3hli_he_f <chr> "2713880", "8081", "6872", "482", "3", "0", "376", "350", "…
## $ p5_hli     <chr> "6695228", "24305", "20290", "2436", "10", "10", "1752", "1…
## $ p5_hli_nhe <chr> "980894", "3144", "3814", "4", "0", "0", "3", "3", "*", "0"…
## $ p5_hli_he  <chr> "5467527", "20243", "15864", "1212", "8", "6", "933", "870"…
## $ phog_ind   <chr> "10788615", "31908", "26036", "5660", "20", "5", "4018", "3…
## $ pcon_lim   <chr> "4527784", "14949", "9237", "49226", "197", "165", "30563",…
## $ pclim_mot  <chr> "2437397", "7766", "4768", "27580", "103", "70", "17286", "…
## $ pclim_vis  <chr> "1292201", "4485", "2645", "13345", "46", "54", "8176", "74…
## $ pclim_leng <chr> "401534", "1275", "838", "4339", "28", "18", "2738", "2438"…
## $ pclim_aud  <chr> "498640", "1733", "1182", "5011", "28", "17", "3041", "2767…
## $ pclim_mot2 <chr> "229029", "612", "371", "2837", "8", "5", "1874", "1721", "…
## $ pclim_men  <chr> "209306", "641", "349", "2992", "15", "12", "1876", "1638",…
## $ pclim_men2 <chr> "448873", "1744", "1023", "5490", "18", "17", "3645", "3244…
## $ psin_lim   <chr> "105646736", "240607", "157833", "1128583", "3172", "2562",…
## $ p3a5_noa   <chr> "2942092", "8467", "6172", "37663", "132", "107", "23224", …
## $ p3a5_noa_m <chr> "1500801", "4376", "3106", "19324", "74", "54", "11967", "1…
## $ p3a5_noa_f <chr> "1441291", "4091", "3066", "18339", "58", "53", "11257", "9…
## $ p6a11_noa  <chr> "407458", "4035", "2884", "3748", "32", "26", "2415", "2116…
## $ p6a11_noam <chr> "215711", "2061", "1504", "2031", "22", "15", "1316", "1138…
## $ p6a11_noaf <chr> "191747", "1974", "1380", "1717", "10", "11", "1099", "978"…
## $ p12a14noa  <chr> "538920", "3596", "2565", "5941", "45", "25", "3574", "3071…
## $ p12a14noam <chr> "283536", "1947", "1328", "3184", "25", "13", "1894", "1631…
## $ p12a14noaf <chr> "255384", "1649", "1237", "2757", "20", "12", "1680", "1440…
## $ p15a17a    <chr> "4499305", "6780", "4048", "47571", "116", "80", "32330", "…
## $ p15a17a_m  <chr> "2233341", "3922", "2187", "23334", "60", "53", "15929", "1…
## $ p15a17a_f  <chr> "2265964", "2858", "1861", "24237", "56", "27", "16401", "1…
## $ p18a24a    <chr> "3955759", "4758", "2972", "42172", "89", "62", "33116", "3…
## $ p18a24a_m  <chr> "1978232", "3074", "1876", "20731", "57", "38", "16580", "1…
## $ p18a24a_f  <chr> "1977527", "1684", "1096", "21441", "32", "24", "16536", "1…
## $ p8a14an    <chr> "554204", "3930", "2928", "3006", "33", "25", "1742", "1509…
## $ p8a14an_m  <chr> "315715", "2196", "1654", "1838", "23", "16", "1044", "906"…
## $ p8a14an_f  <chr> "238489", "1734", "1274", "1168", "10", "9", "698", "603", …
## $ p15ym_an   <chr> "5393665", "32262", "22243", "26269", "223", "179", "14326"…
## $ p15ym_an_m <chr> "2099269", "18111", "11285", "11391", "126", "98", "5715", …
## $ p15ym_an_f <chr> "3294396", "14151", "10958", "14878", "97", "81", "8611", "…
## $ p15ym_se   <chr> "5646147", "35502", "24022", "32064", "245", "199", "18759"…
## $ p15ym_se_m <chr> "2326976", "20731", "12686", "14799", "148", "111", "8178",…
## $ p15ym_se_f <chr> "3319171", "14771", "11336", "17265", "97", "88", "10581", …
## $ p15pri_in  <chr> "9947945", "50636", "31182", "86763", "575", "417", "44967"…
## $ p15pri_inm <chr> "4707350", "31110", "18493", "41421", "322", "233", "20243"…
## $ p15pri_inf <chr> "5240595", "19526", "12689", "45342", "253", "184", "24724"…
## $ p15pri_co  <chr> "12565410", "39138", "25058", "128807", "471", "310", "8240…
## $ p15pri_com <chr> "5832568", "23590", "14409", "58883", "241", "176", "37173"…
## $ p15pri_cof <chr> "6732842", "15548", "10649", "69924", "230", "134", "45228"…
## $ p15sec_in  <chr> "4082402", "10634", "7820", "39284", "120", "101", "25592",…
## $ p15sec_inm <chr> "2234373", "7163", "5413", "22034", "72", "70", "14311", "1…
## $ p15sec_inf <chr> "1848029", "3471", "2407", "17250", "48", "31", "11281", "1…
## $ p15sec_co  <chr> "17181221", "29863", "20208", "203516", "420", "480", "1334…
## $ p15sec_com <chr> "8491006", "18526", "12552", "97269", "210", "316", "64820"…
## $ p15sec_cof <chr> "8690215", "11337", "7656", "106247", "210", "164", "68613"…
## $ p18ym_pb   <chr> "26057800", "22016", "13846", "283254", "368", "345", "2265…
## $ p18ym_pb_m <chr> "12797492", "13719", "8403", "136375", "203", "217", "10923…
## $ p18ym_pb_f <chr> "13260308", "8297", "5443", "146879", "165", "128", "117266…
## $ graproes   <chr> "8.63", "*", "*", "9.23", "*", "*", "9.81", "10.01", "*", "…
## $ graproes_m <chr> "8.79", "*", "*", "9.30", "*", "*", "9.95", "10.18", "*", "…
## $ graproes_f <chr> "8.48", "*", "*", "9.17", "*", "*", "9.69", "9.86", "*", "5…
## $ pea        <chr> "44701044", "114327", "67165", "475207", "1273", "1101", "3…
## $ pea_m      <chr> "30045138", "102367", "59141", "307381", "1040", "935", "20…
## $ pea_f      <chr> "14655906", "11960", "8024", "167826", "233", "166", "12736…
## $ pe_inac    <chr> "39657833", "90326", "59919", "401248", "1232", "945", "263…
## $ pe_inac_m  <chr> "10551884", "21737", "12748", "111981", "296", "286", "7676…
## $ pe_inac_f  <chr> "29105949", "68589", "47171", "289267", "936", "659", "1870…
## $ pocupada   <chr> "42669675", "112669", "65758", "443826", "1233", "1060", "3…
## $ pocupada_m <chr> "28447257", "100913", "57896", "282532", "1007", "901", "19…
## $ pocupada_f <chr> "14222418", "11756", "7862", "161294", "226", "159", "12211…
## $ pdesocup   <chr> "2031369", "1658", "1407", "31381", "40", "41", "21020", "1…
## $ pdesocup_m <chr> "1597881", "1454", "1245", "24849", "33", "34", "15770", "1…
## $ pdesocup_f <chr> "433488", "204", "162", "6532", "7", "7", "5250", "4969", "…
## $ psinder    <chr> "38020372", "120820", "79539", "249596", "1031", "982", "17…
## $ pder_ss    <chr> "72514513", "136035", "86192", "930149", "2347", "1775", "6…
## $ pder_imss  <chr> "35380021", "42422", "23108", "530445", "877", "711", "4159…
## $ pder_iste  <chr> "6303630", "3397", "2000", "85564", "112", "46", "62219", "…
## $ pder_istee <chr> "900884", "489", "314", "3470", "12", "5", "2056", "1949", …
## $ pder_segp  <chr> "26229071", "75338", "55607", "303287", "1318", "1011", "12…
## $ p12ym_solt <chr> "29853117", "69720", "44845", "323815", "951", "706", "2237…
## $ p12ym_casa <chr> "46651603", "118495", "77984", "482578", "1408", "1158", "3…
## $ p12ym_sepa <chr> "8162339", "17302", "10477", "71817", "157", "186", "54101"…
## $ pcatolica  <chr> "92924489", "208751", "141704", "1101785", "3235", "2525", …
## $ pncatolica <chr> "10924103", "24117", "15620", "51766", "68", "123", "40707"…
## $ potras_rel <chr> "172891", "1847", "1333", "835", "3", "0", "709", "682", "*…
## $ psin_relig <chr> "5262546", "19260", "11032", "21235", "38", "69", "17073", …
## $ tothog     <chr> "28159373", "63531", "39674", "289575", "799", "557", "2010…
## $ hogjef_m   <chr> "21243167", "57943", "34821", "224643", "716", "478", "1527…
## $ hogjef_f   <chr> "6916206", "5588", "4853", "64932", "83", "79", "48317", "4…
## $ pobhog     <chr> "110610075", "231430", "153907", "1178123", "3349", "2366",…
## $ phogjef_m  <chr> "87382237", "210660", "137176", "959212", "3022", "2027", "…
## $ phogjef_f  <chr> "23227838", "20770", "16731", "218911", "327", "339", "1588…
## $ vivtot     <dbl> 35625147, 104004, 63685, 361676, 1300, 771, 247792, 225328,…
## $ tvivhab    <dbl> 28614991, 64433, 40054, 290877, 803, 566, 202141, 185120, 2…
## $ tvivpar    <chr> "35169529", "103102", "63305", "360374", "1296", "762", "24…
## $ vivpar_hab <chr> "28159373", "63531", "39674", "289575", "799", "557", "2010…
## $ tvivparhab <chr> "28607568", "64241", "39979", "290777", "802", "561", "2020…
## $ vivpar_des <chr> "4997806", "17696", "11781", "56875", "299", "149", "36893"…
## $ vivpar_ut  <chr> "2012350", "21875", "11850", "13924", "198", "56", "8758", …
## $ ocupvivpar <chr> "110610075", "231430", "153907", "1178123", "3349", "2366",…
## $ prom_ocup  <chr> "3.93", "*", "*", "4.07", "*", "*", "3.94", "3.90", "*", "3…
## $ pro_ocup_c <chr> "1.06", "*", "*", "0.96", "*", "*", "0.89", "0.87", "*", "0…
## $ vph_pisodt <chr> "26224791", "49413", "28677", "284121", "747", "522", "1980…
## $ vph_pisoti <chr> "1731414", "13552", "10604", "4802", "51", "30", "2596", "1…
## $ vph_1dor   <chr> "9929668", "32183", "20167", "71256", "300", "238", "44360"…
## $ vph_2ymasd <chr> "18079707", "30850", "19111", "217742", "498", "313", "1563…
## $ vph_1cuart <chr> "2036147", "7332", "4755", "7006", "43", "40", "3495", "264…
## $ vph_2cuart <chr> "4768838", "17504", "11457", "25342", "150", "134", "13433"…
## $ vph_3ymasc <chr> "21172227", "38137", "23030", "256273", "603", "375", "1834…
## $ vph_c_elec <chr> "27515030", "40662", "25785", "287266", "659", "477", "2001…
## $ vph_s_elec <chr> "513482", "22243", "13460", "1923", "139", "76", "668", "29…
## $ vph_aguadv <chr> "24808420", "20538", "13432", "283042", "514", "356", "1975…
## $ vph_aguafv <chr> "3174979", "42258", "25732", "5840", "283", "194", "3097", …
## $ vph_excsa  <chr> "26848166", "47803", "27893", "284565", "664", "458", "1993…
## $ vph_drenaj <chr> "25410351", "36996", "21226", "283977", "614", "429", "1986…
## $ vph_nodren <chr> "2523821", "25263", "17581", "4795", "181", "121", "1922", …
## $ vph_c_serv <chr> "23207764", "14359", "8980", "278631", "414", "279", "19588…
## $ vph_snbien <chr> "782716", "8196", "6127", "1300", "26", "25", "500", "367",…
## $ vph_radio  <chr> "22373499", "43368", "26213", "256790", "658", "445", "1824…
## $ vph_tv     <chr> "26048531", "38574", "23519", "282484", "676", "475", "1974…
## $ vph_refri  <chr> "23091296", "29064", "17793", "264623", "537", "382", "1882…
## $ vph_lavad  <chr> "18692852", "19361", "12413", "238954", "449", "325", "1706…
## $ vph_autom  <chr> "12429083", "27168", "15497", "171795", "477", "293", "1244…
## $ vph_pc     <chr> "8279619", "3435", "2193", "99579", "97", "59", "81576", "7…
## $ vph_telef  <chr> "12161965", "3973", "2530", "137911", "48", "44", "109090",…
## $ vph_cel    <chr> "18318374", "30417", "16841", "208209", "511", "357", "1576…
## $ vph_inter  <chr> "6004315", "1418", "940", "66075", "36", "19", "56788", "55…
## $ tam_loc    <dbl> NA, NA, NA, NA, NA, NA, NA, 13, 1, 1, 1, 1, 1, 4, 1, 3, 3, …
glimpse(iter_2020)
## Rows: 195,662
## Columns: 286
## $ ENTIDAD     <chr> "00", "00", "00", "01", "01", "01", "01", "01", "01", "01"…
## $ NOM_ENT     <chr> "Total nacional", "Total nacional", "Total nacional", "Agu…
## $ MUN         <chr> "000", "000", "000", "000", "000", "000", "001", "001", "0…
## $ NOM_MUN     <chr> "Total nacional", "Total nacional", "Total nacional", "Tot…
## $ LOC         <chr> "0000", "9998", "9999", "0000", "9998", "9999", "0000", "0…
## $ NOM_LOC     <chr> "Total nacional", "Localidades de una vivienda", "Localida…
## $ LONGITUD    <chr> NA, NA, NA, NA, NA, NA, NA, "102°17'45.768\" W", "102°22'2…
## $ LATITUD     <chr> NA, NA, NA, NA, NA, NA, NA, "21°52'47.362\" N", "21°52'18.…
## $ ALTITUD     <chr> NA, NA, NA, NA, NA, NA, NA, "1878", "1902", "1861", "1861"…
## $ POBTOT      <dbl> 126014024, 250354, 147125, 1425607, 3697, 3021, 948990, 86…
## $ POBFEM      <chr> "64540634", "96869", "61324", "728924", "1510", "1013", "4…
## $ POBMAS      <chr> "61473390", "153485", "85801", "696683", "2187", "2008", "…
## $ P_0A2       <chr> "5764054", "10493", "6798", "71864", "165", "119", "44372"…
## $ P_0A2_F     <chr> "2848875", "5193", "3407", "35604", "81", "54", "21893", "…
## $ P_0A2_M     <chr> "2915179", "5300", "3391", "36260", "84", "65", "22479", "…
## $ P_3YMAS     <chr> "119976584", "239441", "139757", "1352235", "3532", "2902"…
## $ P_3YMAS_F   <chr> "61554567", "91463", "57628", "692561", "1429", "959", "46…
## $ P_3YMAS_M   <chr> "58422017", "147978", "82129", "659674", "2103", "1943", "…
## $ P_5YMAS     <chr> "115693273", "232086", "135028", "1299669", "3420", "2829"…
## $ P_5YMAS_F   <chr> "59433559", "87931", "55256", "666713", "1377", "925", "44…
## $ P_5YMAS_M   <chr> "56259714", "144155", "79772", "632956", "2043", "1904", "…
## $ P_12YMAS    <chr> "100528155", "207748", "119223", "1116719", "3018", "2553"…
## $ P_12YMAS_F  <chr> "51962264", "76111", "47543", "576593", "1179", "798", "39…
## $ P_12YMAS_M  <chr> "48565891", "131637", "71680", "540126", "1839", "1755", "…
## $ P_15YMAS    <chr> "93985354", "197411", "111530", "1038904", "2836", "2444",…
## $ P_15YMAS_F  <chr> "48732991", "71344", "44275", "538387", "1086", "740", "36…
## $ P_15YMAS_M  <chr> "45252363", "126067", "67255", "500517", "1750", "1704", "…
## $ P_18YMAS    <chr> "87492680", "186968", "104612", "960764", "2609", "2341", …
## $ P_18YMAS_F  <chr> "45530857", "66514", "41184", "500089", "987", "699", "343…
## $ P_18YMAS_M  <chr> "41961823", "120454", "63428", "460675", "1622", "1642", "…
## $ P_3A5       <chr> "6462212", "10900", "7028", "78833", "169", "113", "48767"…
## $ P_3A5_F     <chr> "3193548", "5270", "3511", "38679", "80", "47", "23951", "…
## $ P_3A5_M     <chr> "3268664", "5630", "3517", "40154", "89", "66", "24816", "…
## $ P_6A11      <chr> "12986217", "20793", "13506", "156683", "345", "236", "979…
## $ P_6A11_F    <chr> "6398755", "10082", "6574", "77289", "170", "114", "48353"…
## $ P_6A11_M    <chr> "6587462", "10711", "6932", "79394", "175", "122", "49594"…
## $ P_8A14      <chr> "15287375", "24342", "16724", "181905", "427", "262", "114…
## $ P_8A14_F    <chr> "7531118", "11538", "7679", "89383", "211", "133", "56248"…
## $ P_8A14_M    <chr> "7756257", "12804", "9045", "92522", "216", "129", "58303"…
## $ P_12A14     <chr> "6542801", "10337", "7693", "77815", "182", "109", "49497"…
## $ P_12A14_F   <chr> "3229273", "4767", "3268", "38206", "93", "58", "24224", "…
## $ P_12A14_M   <chr> "3313528", "5570", "4425", "39609", "89", "51", "25273", "…
## $ P_15A17     <chr> "6492674", "10443", "6918", "78140", "227", "103", "49934"…
## $ P_15A17_F   <chr> "3202134", "4830", "3091", "38298", "99", "41", "24477", "…
## $ P_15A17_M   <chr> "3290540", "5613", "3827", "39842", "128", "62", "25457", …
## $ P_18A24     <chr> "14736111", "27841", "16336", "180847", "438", "439", "120…
## $ P_18A24_F   <chr> "7398617", "11140", "6760", "90632", "180", "123", "60159"…
## $ P_18A24_M   <chr> "7337494", "16701", "9576", "90215", "258", "316", "60293"…
## $ P_15A49_F   <chr> "33885546", "47693", "29297", "388917", "750", "531", "260…
## $ P_60YMAS    <chr> "15142976", "37383", "21277", "145376", "448", "281", "102…
## $ P_60YMAS_F  <chr> "8139094", "13442", "8916", "78703", "190", "116", "56724"…
## $ P_60YMAS_M  <chr> "7003882", "23941", "12361", "66673", "258", "165", "46263…
## $ REL_H_M     <chr> "95.25", "158.45", "139.91", "95.58", "144.83", "198.22", …
## $ POB0_14     <chr> "31755284", "52523", "35025", "385195", "861", "577", "240…
## $ POB15_64    <chr> "83663440", "171209", "96250", "941834", "2524", "2241", "…
## $ POB65_MAS   <chr> "10321914", "26202", "15280", "97070", "312", "203", "6794…
## $ P_0A4       <chr> "10047365", "17848", "11527", "124430", "277", "192", "768…
## $ P_0A4_F     <chr> "4969883", "8725", "5779", "61452", "133", "88", "37897", …
## $ P_0A4_M     <chr> "5077482", "9123", "5748", "62978", "144", "104", "38966",…
## $ P_5A9       <chr> "10764379", "17380", "11274", "131048", "281", "199", "817…
## $ P_5A9_F     <chr> "5311288", "8526", "5558", "64689", "142", "88", "40366", …
## $ P_5A9_M     <chr> "5453091", "8854", "5716", "66359", "139", "111", "41347",…
## $ P_10A14     <chr> "10943540", "17295", "12224", "129717", "303", "186", "820…
## $ P_10A14_F   <chr> "5389280", "8061", "5423", "63637", "149", "97", "40158", …
## $ P_10A14_M   <chr> "5554260", "9234", "6801", "66080", "154", "89", "41849", …
## $ P_15A19     <chr> "10806690", "18303", "11484", "131967", "348", "201", "851…
## $ P_15A19_F   <chr> "5344540", "8138", "5140", "65064", "148", "75", "41939", …
## $ P_15A19_M   <chr> "5462150", "10165", "6344", "66903", "200", "126", "43222"…
## $ P_20A24     <chr> "10422095", "19981", "11770", "127020", "317", "341", "852…
## $ P_20A24_F   <chr> "5256211", "7832", "4711", "63866", "131", "89", "42697", …
## $ P_20A24_M   <chr> "5165884", "12149", "7059", "63154", "186", "252", "42528"…
## $ P_25A29     <chr> "9993001", "20584", "12238", "118426", "300", "367", "8007…
## $ P_25A29_F   <chr> "5131597", "7125", "4427", "60285", "109", "87", "40446", …
## $ P_25A29_M   <chr> "4861404", "13459", "7811", "58141", "191", "280", "39631"…
## $ P_30A34     <chr> "9420827", "19601", "11315", "106825", "280", "346", "7185…
## $ P_30A34_F   <chr> "4893101", "6309", "4074", "55174", "89", "87", "36831", "…
## $ P_30A34_M   <chr> "4527726", "13292", "7241", "51651", "191", "259", "35019"…
## $ P_35A39     <chr> "9020276", "18645", "10357", "99257", "272", "275", "66892…
## $ P_35A39_F   <chr> "4688746", "6289", "3825", "51483", "85", "80", "34639", "…
## $ P_35A39_M   <chr> "4331530", "12356", "6532", "47774", "187", "195", "32253"…
## $ P_40A44     <chr> "8503586", "17934", "9705", "92378", "259", "223", "62159"…
## $ P_40A44_F   <chr> "4441282", "6060", "3743", "48539", "103", "64", "32704", …
## $ P_40A44_M   <chr> "4062304", "11874", "5962", "43839", "156", "159", "29455"…
## $ P_45A49     <chr> "7942413", "16840", "8668", "84669", "238", "170", "58264"…
## $ P_45A49_F   <chr> "4130069", "5940", "3377", "44506", "85", "49", "31021", "…
## $ P_45A49_M   <chr> "3812344", "10900", "5291", "40163", "153", "121", "27243"…
## $ P_50A54     <chr> "7037532", "15070", "7878", "74121", "177", "137", "52400"…
## $ P_50A54_F   <chr> "3705369", "5481", "3239", "39510", "72", "52", "28200", "…
## $ P_50A54_M   <chr> "3332163", "9589", "4639", "34611", "105", "85", "24200", …
## $ P_55A59     <chr> "5695958", "13070", "6838", "58865", "197", "103", "42458"…
## $ P_55A59_F   <chr> "3002982", "4728", "2823", "31257", "74", "41", "22827", "…
## $ P_55A59_M   <chr> "2692976", "8342", "4015", "27608", "123", "62", "19631", …
## $ P_60A64     <chr> "4821062", "11181", "5997", "48306", "136", "78", "35046",…
## $ P_60A64_F   <chr> "2563200", "4050", "2511", "25871", "54", "34", "18957", "…
## $ P_60A64_M   <chr> "2257862", "7131", "3486", "22435", "82", "44", "16089", "…
## $ P_65A69     <chr> "3645077", "9160", "5052", "35823", "106", "87", "25677", …
## $ P_65A69_F   <chr> "1938227", "3343", "2130", "19125", "44", "33", "13907", "…
## $ P_65A69_M   <chr> "1706850", "5817", "2922", "16698", "62", "54", "11770", "…
## $ P_70A74     <chr> "2647340", "6903", "3852", "25586", "78", "49", "18157", "…
## $ P_70A74_F   <chr> "1413848", "2421", "1575", "13804", "35", "21", "9980", "9…
## $ P_70A74_M   <chr> "1233492", "4482", "2277", "11782", "43", "28", "8177", "7…
## $ P_75A79     <chr> "1814582", "4765", "2920", "16581", "58", "38", "11458", "…
## $ P_75A79_F   <chr> "966684", "1639", "1182", "8842", "26", "14", "6228", "584…
## $ P_75A79_M   <chr> "847898", "3126", "1738", "7739", "32", "24", "5230", "477…
## $ P_80A84     <chr> "1175364", "3017", "1868", "10186", "38", "18", "6872", "6…
## $ P_80A84_F   <chr> "651552", "1081", "793", "5789", "19", "7", "4055", "3819"…
## $ P_80A84_M   <chr> "523812", "1936", "1075", "4397", "19", "11", "2817", "256…
## $ P_85YMAS    <chr> "1039551", "2357", "1588", "8894", "32", "11", "5777", "53…
## $ P_85YMAS_F  <chr> "605583", "908", "725", "5272", "12", "7", "3597", "3373",…
## $ P_85YMAS_M  <chr> "433968", "1449", "863", "3622", "20", "4", "2180", "1973"…
## $ PROM_HNV    <chr> "2.09", "*", "*", "2.11", "*", "*", "1.98", "1.95", "*", "…
## $ PNACENT     <chr> "102724322", "177757", "117805", "1133247", "2908", "2370"…
## $ PNACENT_F   <chr> "52519974", "75977", "52686", "576781", "1216", "811", "36…
## $ PNACENT_M   <chr> "50204348", "101780", "65119", "556466", "1692", "1559", "…
## $ PNACOE      <chr> "21611963", "54046", "20274", "276430", "749", "616", "214…
## $ PNACOE_F    <chr> "11222300", "18910", "7205", "144420", "275", "198", "1128…
## $ PNACOE_M    <chr> "10389663", "35136", "13069", "132010", "474", "418", "102…
## $ PRES2015    <chr> "111075594", "184423", "114178", "1232234", "2721", "1638"…
## $ PRES2015_F  <chr> "57288776", "79893", "52604", "635320", "1298", "779", "42…
## $ PRES2015_M  <chr> "53786818", "104530", "61574", "596914", "1423", "859", "3…
## $ PRESOE15    <chr> "3807844", "16172", "6214", "56422", "152", "77", "42481",…
## $ PRESOE15_F  <chr> "1889986", "6089", "1664", "27956", "69", "36", "21032", "…
## $ PRESOE15_M  <chr> "1917858", "10083", "4550", "28466", "83", "41", "21449", …
## $ P3YM_HLI    <chr> "7364645", "26486", "18640", "2539", "20", "14", "1839", "…
## $ P3YM_HLI_F  <chr> "3783447", "10908", "8181", "1043", "3", "3", "754", "704"…
## $ P3YM_HLI_M  <chr> "3581198", "15578", "10459", "1496", "17", "11", "1085", "…
## $ P3HLINHE    <chr> "865972", "2712", "3098", "25", "0", "0", "8", "6", "*", "…
## $ P3HLINHE_F  <chr> "547528", "1652", "1901", "13", "0", "0", "4", "4", "*", "…
## $ P3HLINHE_M  <chr> "318444", "1060", "1197", "12", "0", "0", "4", "2", "*", "…
## $ P3HLI_HE    <chr> "6423548", "22906", "14758", "2461", "15", "6", "1792", "1…
## $ P3HLI_HE_F  <chr> "3198595", "9203", "6205", "1012", "3", "3", "737", "688",…
## $ P3HLI_HE_M  <chr> "3224953", "13703", "8553", "1449", "12", "3", "1055", "99…
## $ P5_HLI      <chr> "7177185", "25743", "17992", "2508", "20", "14", "1822", "…
## $ P5_HLI_NHE  <chr> "785361", "2412", "2742", "22", "0", "0", "8", "6", "*", "…
## $ P5_HLI_HE   <chr> "6317027", "22464", "14467", "2437", "15", "6", "1776", "1…
## $ PHOG_IND    <chr> "11800247", "27252", "21531", "5552", "5", "7", "4050", "3…
## $ POB_AFRO    <chr> "2576213", "4122", "2816", "22425", "52", "32", "15170", "…
## $ POB_AFRO_F  <chr> "1297617", "1614", "1056", "11211", "20", "11", "7560", "7…
## $ POB_AFRO_M  <chr> "1278596", "2508", "1760", "11214", "32", "21", "7610", "7…
## $ PCON_DISC   <chr> "6179890", "12126", "8058", "71294", "212", "123", "47525"…
## $ PCDISC_MOT  <chr> "2939986", "5875", "4079", "34507", "110", "67", "23117", …
## $ PCDISC_VIS  <chr> "2691338", "5008", "3590", "29888", "69", "35", "20047", "…
## $ PCDISC_LENG <chr> "945162", "1940", "1664", "9297", "18", "7", "5894", "5317…
## $ PCDISC_AUD  <chr> "1350802", "2895", "2295", "12989", "39", "27", "8636", "7…
## $ PCDISC_MOT2 <chr> "1168098", "2123", "1808", "12726", "38", "13", "8226", "7…
## $ PCDISC_MEN  <chr> "1149257", "2179", "1825", "12967", "27", "12", "8618", "7…
## $ PCON_LIMI   <chr> "13934448", "28067", "16685", "165482", "418", "290", "116…
## $ PCLIM_CSB   <chr> "4365234", "10653", "6309", "49636", "161", "109", "34873"…
## $ PCLIM_VIS   <chr> "8974853", "17059", "10523", "103289", "226", "159", "7366…
## $ PCLIM_HACO  <chr> "864662", "2092", "1279", "8940", "30", "16", "5980", "539…
## $ PCLIM_OAUD  <chr> "2900108", "6916", "3982", "30298", "75", "53", "21547", "…
## $ PCLIM_MOT2  <chr> "673540", "1625", "1085", "6368", "24", "13", "4413", "399…
## $ PCLIM_RE_CO <chr> "2698640", "5763", "3479", "34556", "95", "62", "24523", "…
## $ PCLIM_PMEN  <chr> "1590583", "2823", "1579", "20169", "56", "31", "13945", "…
## $ PSIND_LIM   <chr> "104815785", "207052", "120888", "1177938", "3044", "2590"…
## $ P3A5_NOA    <chr> "2359716", "5620", "3783", "31495", "84", "57", "18639", "…
## $ P3A5_NOA_F  <chr> "1155636", "2689", "1873", "15371", "36", "26", "9130", "8…
## $ P3A5_NOA_M  <chr> "1204080", "2931", "1910", "16124", "48", "31", "9509", "8…
## $ P6A11_NOA   <chr> "577029", "2920", "1782", "4941", "25", "6", "2877", "2525…
## $ P6A11_NOAF  <chr> "275189", "1403", "874", "2292", "17", "3", "1360", "1183"…
## $ P6A11_NOAM  <chr> "301840", "1517", "908", "2649", "8", "3", "1517", "1342",…
## $ P12A14NOA   <chr> "618233", "2699", "1674", "6812", "34", "13", "3907", "341…
## $ P12A14NOAF  <chr> "283195", "1190", "766", "2901", "16", "7", "1671", "1467"…
## $ P12A14NOAM  <chr> "335038", "1509", "908", "3911", "18", "6", "2236", "1948"…
## $ P15A17A     <chr> "4726359", "4952", "3557", "55493", "133", "56", "36490", …
## $ P15A17A_F   <chr> "2390407", "2386", "1509", "28286", "53", "22", "18550", "…
## $ P15A17A_M   <chr> "2335952", "2566", "2048", "27207", "80", "34", "17940", "…
## $ P18A24A     <chr> "4894125", "4157", "2738", "59978", "93", "77", "44885", "…
## $ P18A24A_F   <chr> "2482980", "1610", "1053", "31114", "33", "23", "23031", "…
## $ P18A24A_M   <chr> "2411145", "2547", "1685", "28864", "60", "54", "21854", "…
## $ P8A14AN     <chr> "412725", "2393", "1527", "3178", "19", "7", "1851", "1609…
## $ P8A14AN_F   <chr> "178152", "1080", "712", "1318", "10", "4", "772", "683", …
## $ P8A14AN_M   <chr> "234573", "1313", "815", "1860", "9", "3", "1079", "926", …
## $ P15YM_AN    <chr> "4456431", "24331", "15092", "21908", "180", "113", "11618…
## $ P15YM_AN_F  <chr> "2677192", "10532", "7074", "11762", "78", "41", "6599", "…
## $ P15YM_AN_M  <chr> "1779239", "13799", "8018", "10146", "102", "72", "5019", …
## $ P15YM_SE    <chr> "4841952", "28014", "17660", "25567", "209", "119", "14576…
## $ P15YM_SE_F  <chr> "2791237", "11278", "7476", "13286", "79", "43", "7917", "…
## $ P15YM_SE_M  <chr> "2050715", "16736", "10184", "12281", "130", "76", "6659",…
## $ P15PRI_IN   <chr> "7731820", "38545", "21620", "65609", "378", "301", "33308…
## $ P15PRI_INF  <chr> "4042527", "13056", "8064", "33542", "152", "86", "18056",…
## $ P15PRI_INM  <chr> "3689293", "25489", "13556", "32067", "226", "215", "15252…
## $ P15PRI_CO   <chr> "12325433", "38809", "22033", "122405", "470", "409", "762…
## $ P15PRI_COF  <chr> "6515268", "14762", "9009", "64730", "207", "132", "41402"…
## $ P15PRI_COM  <chr> "5810165", "24047", "13024", "57675", "263", "277", "34854…
## $ P15SEC_IN   <chr> "2913915", "14833", "5040", "30347", "157", "145", "19144"…
## $ P15SEC_INF  <chr> "1297269", "3143", "1561", "12806", "37", "27", "8184", "7…
## $ P15SEC_INM  <chr> "1616646", "11690", "3479", "17541", "120", "118", "10960"…
## $ P15SEC_CO   <chr> "22833912", "40180", "24056", "288036", "832", "807", "182…
## $ P15SEC_COF  <chr> "11857736", "15578", "9485", "151759", "291", "220", "9543…
## $ P15SEC_COM  <chr> "10976176", "24602", "14571", "136277", "541", "587", "871…
## $ P18YM_PB    <chr> "39977750", "33907", "19102", "467249", "722", "617", "354…
## $ P18YM_PB_F  <chr> "20408275", "11972", "7672", "240419", "289", "211", "1818…
## $ P18YM_PB_M  <chr> "19569475", "21935", "11430", "226830", "433", "406", "172…
## $ GRAPROES    <chr> "9.74", "6.5", "6.45", "10.35", "8.14", "8.37", "10.84", "…
## $ GRAPROES_F  <chr> "9.64", "6.51", "6.48", "10.32", "8.2", "8.53", "10.75", "…
## $ GRAPROES_M  <chr> "9.84", "6.5", "6.43", "10.38", "8.11", "8.3", "10.93", "1…
## $ PEA         <chr> "62281634", "128289", "68904", "706930", "2077", "1748", "…
## $ PEA_F       <chr> "25465693", "33067", "18475", "293533", "506", "363", "208…
## $ PEA_M       <chr> "36815941", "95222", "50429", "413397", "1571", "1385", "2…
## $ PE_INAC     <chr> "37891261", "68766", "46162", "407903", "939", "801", "269…
## $ PE_INAC_F   <chr> "26379060", "42827", "28959", "282320", "673", "435", "182…
## $ PE_INAC_M   <chr> "11512201", "25939", "17203", "125583", "266", "366", "862…
## $ POCUPADA    <chr> "61121324", "127469", "68215", "692983", "2060", "1741", "…
## $ POCUPADA_F  <chr> "25137019", "32906", "18365", "289268", "497", "361", "205…
## $ POCUPADA_M  <chr> "35984305", "94563", "49850", "403715", "1563", "1380", "2…
## $ PDESOCUP    <chr> "1160310", "820", "689", "13947", "17", "7", "10173", "949…
## $ PDESOCUP_F  <chr> "328674", "161", "110", "4265", "9", "2", "3386", "3224", …
## $ PDESOCUP_M  <chr> "831636", "659", "579", "9682", "8", "5", "6787", "6274", …
## $ PSINDER     <chr> "32999713", "86676", "56232", "262088", "1067", "1289", "1…
## $ PDER_SS     <chr> "92582812", "153663", "90057", "1161139", "2472", "1730", …
## $ PDER_IMSS   <chr> "47245909", "53559", "23569", "780525", "1090", "828", "57…
## $ PDER_ISTE   <chr> "7165164", "3795", "2312", "92771", "113", "87", "65237", …
## $ PDER_ISTEE  <chr> "1041534", "552", "350", "3786", "4", "9", "2352", "2243",…
## $ PAFIL_PDOM  <chr> "1192255", "649", "485", "3196", "0", "1", "2563", "2494",…
## $ PDER_SEGP   <chr> "32842765", "84849", "59445", "271996", "1242", "775", "12…
## $ PDER_IMSSB  <chr> "958787", "2883", "1956", "1680", "2", "1", "1064", "969",…
## $ PAFIL_IPRIV <chr> "2615213", "3288", "1300", "31789", "31", "20", "25703", "…
## $ PAFIL_OTRAI <chr> "1149542", "6284", "1504", "3179", "13", "25", "2346", "21…
## $ P12YM_SOLT  <chr> "34370381", "63913", "38355", "402370", "1037", "787", "27…
## $ P12YM_CASA  <chr> "54036478", "124916", "68874", "593273", "1695", "1454", "…
## $ P12YM_SEPA  <chr> "12049313", "18433", "10660", "120740", "285", "312", "873…
## $ PCATOLICA   <chr> "97864218", "187464", "112351", "1272419", "3250", "2732",…
## $ PRO_CRIEVA  <chr> "14095307", "29725", "16630", "73359", "223", "95", "55328…
## $ POTRAS_REL  <chr> "248169", "1117", "675", "1900", "11", "22", "1539", "1457…
## $ PSIN_RELIG  <chr> "13314516", "29624", "16432", "74439", "195", "169", "5853…
## $ TOTHOG      <chr> "35219141", "62516", "36568", "386445", "807", "516", "266…
## $ HOGJEF_F    <chr> "11474983", "8292", "6620", "119453", "123", "100", "85732…
## $ HOGJEF_M    <chr> "23744158", "54224", "29948", "266992", "684", "416", "181…
## $ POBHOG      <chr> "125514839", "198544", "125099", "1421200", "3137", "1918"…
## $ PHOGJEF_F   <chr> "37418569", "28805", "21860", "395735", "532", "385", "273…
## $ PHOGJEF_M   <chr> "88096270", "169739", "103239", "1025465", "2605", "1533",…
## $ VIVTOT      <dbl> 43903443, 101390, 61435, 463972, 1368, 869, 313256, 286646…
## $ TVIVHAB     <dbl> 35233462, 62767, 36676, 386671, 813, 518, 266942, 246259, …
## $ TVIVPAR     <chr> "42300700", "99591", "60317", "453099", "1354", "858", "30…
## $ VIVPAR_HAB  <chr> "33630719", "60968", "35558", "375798", "799", "507", "257…
## $ VIVPARH_CV  <chr> "35156897", "62091", "36359", "386011", "801", "516", "266…
## $ TVIVPARHAB  <chr> "35219141", "62516", "36568", "386445", "807", "516", "266…
## $ VIVPAR_DES  <chr> "6155682", "18117", "12225", "60327", "233", "164", "37113…
## $ VIVPAR_UT   <chr> "2514299", "20506", "12534", "16974", "322", "187", "9201"…
## $ OCUPVIVPAR  <chr> "125514839", "198544", "125099", "1421200", "3137", "1918"…
## $ PROM_OCUP   <chr> "3.56", "3.18", "3.42", "3.68", "3.89", "3.72", "3.54", "3…
## $ PRO_OCUP_C  <chr> "0.96", "1.03", "1.03", "0.89", "1.02", "1.03", "0.84", "0…
## $ VPH_PISODT  <chr> "33833470", "53169", "29302", "382634", "771", "499", "264…
## $ VPH_PISOTI  <chr> "1235550", "8797", "6891", "2899", "30", "17", "1530", "10…
## $ VPH_1DOR    <chr> "11186214", "30115", "17038", "86423", "270", "175", "5543…
## $ VPH_2YMASD  <chr> "23887498", "31851", "19157", "299141", "531", "341", "210…
## $ VPH_1CUART  <chr> "2085925", "7333", "4351", "6390", "39", "27", "3185", "24…
## $ VPH_2CUART  <chr> "5460133", "16206", "9491", "30686", "116", "85", "17449",…
## $ VPH_3YMASC  <chr> "27527131", "38424", "22351", "348487", "646", "404", "245…
## $ VPH_C_ELEC  <chr> "34805976", "48426", "28586", "384361", "723", "477", "265…
## $ VPH_S_ELEC  <chr> "268863", "13538", "7607", "1210", "78", "39", "438", "300…
## $ VPH_AGUADV  <chr> "33858339", "45470", "26499", "383430", "694", "463", "265…
## $ VPH_AEASP   <chr> "29541708", "8198", "5054", "355192", "195", "136", "25415…
## $ VPH_AGUAFV  <chr> "1215497", "16498", "9696", "2137", "107", "53", "989", "3…
## $ VPH_TINACO  <chr> "22629812", "34143", "18089", "295903", "608", "361", "199…
## $ VPH_CISTER  <chr> "9652823", "13743", "7029", "152521", "405", "241", "12280…
## $ VPH_EXCSA   <chr> "33081729", "44688", "24348", "382597", "708", "455", "265…
## $ VPH_LETR    <chr> "1396774", "9825", "6050", "1011", "27", "19", "520", "60"…
## $ VPH_DRENAJ  <chr> "33564054", "47253", "26036", "383148", "719", "459", "265…
## $ VPH_NODREN  <chr> "1498766", "14708", "10155", "2379", "82", "57", "798", "1…
## $ VPH_C_SERV  <chr> "32671764", "35091", "19807", "380982", "610", "418", "264…
## $ VPH_NDEAED  <chr> "79584", "4842", "2935", "184", "16", "10", "53", "19", "*…
## $ VPH_DSADMA  <chr> "32979844", "43668", "23841", "382121", "704", "445", "264…
## $ VPH_NDACMM  <chr> "16874580", "24373", "16122", "130744", "203", "119", "883…
## $ VPH_SNBIEN  <chr> "581095", "5136", "4115", "876", "12", "8", "380", "313", …
## $ VPH_REFRI   <chr> "30811260", "38199", "21775", "365189", "632", "436", "254…
## $ VPH_LAVAD   <chr> "25610544", "26412", "15880", "335710", "561", "377", "234…
## $ VPH_HMICRO  <chr> "16651199", "13608", "7902", "238571", "276", "218", "1760…
## $ VPH_AUTOM   <chr> "16340788", "30940", "16699", "240381", "529", "343", "169…
## $ VPH_MOTO    <chr> "4227460", "15001", "8076", "45642", "216", "143", "26624"…
## $ VPH_BICI    <chr> "7469168", "13600", "6330", "105752", "407", "241", "54393…
## $ VPH_RADIO   <chr> "23772973", "36738", "20009", "312002", "650", "405", "221…
## $ VPH_TV      <chr> "32031555", "40001", "23198", "370411", "684", "466", "257…
## $ VPH_PC      <chr> "13204680", "5797", "3588", "177149", "167", "114", "13692…
## $ VPH_TELEF   <chr> "13184550", "3523", "2177", "147818", "43", "37", "116647"…
## $ VPH_CEL     <chr> "30775898", "47005", "25581", "359895", "732", "470", "251…
## $ VPH_INTER   <chr> "18307193", "8385", "5027", "236003", "205", "146", "17861…
## $ VPH_STVP    <chr> "15211306", "18981", "11306", "174089", "212", "156", "130…
## $ VPH_SPMVPI  <chr> "6616141", "1732", "971", "98724", "48", "35", "80951", "7…
## $ VPH_CVJ     <chr> "4047100", "1113", "708", "70126", "41", "38", "56131", "5…
## $ VPH_SINRTV  <chr> "1788552", "12775", "8247", "6021", "39", "25", "3299", "2…
## $ VPH_SINLTC  <chr> "3170894", "14143", "10065", "15323", "62", "44", "7293", …
## $ VPH_SINCINT <chr> "15108204", "51293", "29741", "128996", "530", "330", "742…
## $ VPH_SINTIC  <chr> "852871", "7154", "5283", "1711", "20", "11", "731", "595"…
## $ TAMLOC      <chr> "*", "*", "*", "*", "*", "*", "*", "13", "1", "1", "1", "1…

1.12 🧩 Limpieza y selección de los totales municipales

Los censos no hablan siempre el mismo idioma.
Cada año, el INEGI cambió ligeramente la forma de nombrar las columnas y los valores que representan los totales municipales.
Por eso, Tochtli debe armonizar los datos, creando un lenguaje común entre los tres censos.

  • En el Censo 2000, el total municipal aparece como "TOTAL MUNICIPAL".
  • En 2010 y 2020, se registra como "Total del Municipio".
  • En algunos casos, hay una columna loc con valor 0, pero su nombre y formato varían.

Así, Tochtli crea tres filtros diferentes, uno para cada año, asegurando que cada tabla contenga únicamente los totales municipales.

Luego añade dos elementos esenciales:

  1. 🧩 Una columna cve_mun, combinación de la clave de entidad (ENTIDAD) y municipio (MUN), para formar un identificador único de cinco dígitos.
  2. 🕓 Una columna anio, que indica el año del censo al que pertenece cada observación.
iter_2010 <- clean_names(iter_2010)
iter_2020 <- clean_names(iter_2020)

1.13 🔍 Explorando los códices con Tochtli

Antes de empezar a construir indicadores, Tochtli se detiene a observar los datos recién cargados.
Cada fila representa una historia, un hogar, una coordenada en el mapa de Geotitlán.
Para explorar este territorio de números y palabras, usará una tabla interactiva con la librería DT,
una herramienta que le permite recorrer los censos como si caminara por un valle de datos.

“Observar es el primer paso del análisis —dice Tochtli—.
Los datos no se dominan: se escuchan, se leen, se sienten.”

💻 Código:

library(DT)

# 🧭 Tabla interactiva del Censo 2020
DT::datatable(
  head(iter_2020, 100),  # muestra las primeras 100 filas del censo
  options = list(
    pageLength = 10,     # número de filas visibles por página
    scrollX = TRUE       # permite desplazamiento horizontal
  ),
  caption = "🌾 Visualización interactiva de los primeros registros del Censo 2020 en Geotitlán"
)

1.14 🧩 Limpieza y selección de los totales municipales

Entre los códices del INEGI, Tochtli descubre un pequeño enigma:
los censos no hablan siempre el mismo idioma.
A lo largo de los años, los escribas cambiaron las palabras y el orden de las columnas,
haciendo que una misma idea —el total municipal— aparezca con distintos nombres.

🪶 Por ejemplo: - En el Censo 2000, el campo nom_loc usa el texto “TOTAL MUNICIPAL” (en mayúsculas).
- En los Censos 2010 y 2020, aparece como “Total del Municipio” (con mayúsculas y minúsculas).
- En algunas tablas, incluso surge una columna loc con el valor 0, pero su presencia y nombre varían.

Así que, para evitar que los datos se confundan entre sí,
Tochtli diseña tres filtros distintos, uno para cada censo,
garantizando que solo se conserven los registros que representan el total por municipio.

# ------------------------------------------------------------
# TOTALES MUNICIPALES POR AÑO (filtros específicos por nom_loc)
# ------------------------------------------------------------
library(dplyr)
library(janitor)
library(stringr)

# Utilidad pequeña: limpiar nombres y corregir posible BOM en la 1ª columna
prep_names <- function(df){
  df <- janitor::clean_names(df)
  names(df)[1] <- sub("^\ufeff", "", names(df)[1])  # quita BOM si aparece
  df
}


# --- 2010: nom_loc == "Total del Municipio"
mun_2010 <- iter_2010 %>%
  prep_names() %>%
  filter(nom_loc == "Total del Municipio") %>%    # filtro exacto
  mutate(
    entidad = suppressWarnings(as.integer(entidad)),
    mun     = suppressWarnings(as.integer(mun)),
    cve_mun = paste0(sprintf("%02d", entidad), sprintf("%03d", mun)),
    anio    = 2010
  )

# --- 2020: nom_loc == "Total del Municipio"
mun_2020 <- iter_2020 %>%
  prep_names() %>%
  filter(nom_loc == "Total del Municipio") %>%    # filtro exacto
  mutate(
    entidad = suppressWarnings(as.integer(entidad)),
    mun     = suppressWarnings(as.integer(mun)),
    cve_mun = paste0(sprintf("%02d", entidad), sprintf("%03d", mun)),
    anio    = 2020
  )

# Contamos cuántos municipios hay en cada año
tabla_municipios <- bind_rows(
  
  dplyr::count(mun_2010, anio),
  dplyr::count(mun_2020, anio)
) %>%
  arrange(anio) %>%
  mutate(
    incremento = n - lag(n),                     # diferencia con respecto al censo anterior
    variacion_pct = round((incremento / lag(n)) * 100, 2) # cambio porcentual
  )

# Mostramos la tabla resultante
tabla_municipios
## # A tibble: 2 × 4
##    anio     n incremento variacion_pct
##   <dbl> <int>      <int>         <dbl>
## 1  2010  2456         NA         NA   
## 2  2020  2469         13          0.53
# ------------------------------------------------------------
# NORMALIZAR CLAVES Y CREAR cve_mun = ENTIDAD(2) + MUN(3)
# - Soluciona el problema de ceros a la izquierda (01, 003, etc.)
# - Limpia espacios y caracteres no numéricos
# ------------------------------------------------------------
library(dplyr)
library(stringr)

# Función para pad con ceros (robusta a num/char/factor y basura no numérica)
pad_code <- function(x, width){
  v <- as.character(x) |> 
    str_trim() |> 
    str_replace_all("[^0-9]", "") |>          # deja solo dígitos
    suppressWarnings(as.integer())             # a entero (pierde ceros, está bien)
  ifelse(is.na(v), NA_character_, stringr::str_pad(as.character(v), width, pad = "0"))
}

# Función para estandarizar y crear cve_mun en un df municipal
with_cve_mun <- function(df){
  df %>%
    mutate(
      entidad = pad_code(entidad, 2),          # "1" -> "01"
      mun     = pad_code(mun, 3),              # "7" -> "007"
      cve_mun = ifelse(is.na(entidad) | is.na(mun), NA_character_, paste0(entidad, mun))
    )
}

# Aplicar a cada año

mun_2010 <- with_cve_mun(mun_2010)
mun_2020 <- with_cve_mun(mun_2020)
# ------------------------------------------------------------
# 🔑 Generar la clave municipal (cve_mun)
# ------------------------------------------------------------

# Ya tenemos las columnas 'entidad' y 'mun' estandarizadas.
# Ahora combinamos ambas para formar la clave municipal de 5 dígitos:
# Ejemplo: Aguascalientes (entidad = 01) + Aguascalientes (mun = 001) -> 01001


mun_2010 <- mun_2010 %>%
  mutate(cve_mun = paste0(entidad, mun))

mun_2020 <- mun_2020 %>%
  mutate(cve_mun = paste0(entidad, mun))

# Verificamos que las claves se hayan creado correctamente

mun_2010 %>% select(entidad, mun, cve_mun) %>% head()
## # A tibble: 6 × 3
##   entidad mun   cve_mun
##   <chr>   <chr> <chr>  
## 1 01      001   01001  
## 2 01      002   01002  
## 3 01      003   01003  
## 4 01      004   01004  
## 5 01      005   01005  
## 6 01      006   01006
mun_2020 %>% select(entidad, mun, cve_mun) %>% head()
## # A tibble: 6 × 3
##   entidad mun   cve_mun
##   <chr>   <chr> <chr>  
## 1 01      001   01001  
## 2 01      002   01002  
## 3 01      003   01003  
## 4 01      004   01004  
## 5 01      005   01005  
## 6 01      006   01006

2 🧮 Del dato al indicador: construyendo información territorial con R

2.1 🧩 El reto de trabajar con datos del INEGI

En los valles de Geotitlán, Tochtli observa que los códices del INEGI guardan una enorme sabiduría,
pero sus signos no siempre son fáciles de leer.
Cada censo está escrito con un estilo diferente: nombres cambiantes, columnas dispersas, estructuras que se transforman con el tiempo.

Antes de convertir esos datos en mapas, Tochtli debe ordenar, estandarizar y seleccionar las variables esenciales.
Solo entonces los datos se transformarán en indicadores territoriales, capaces de revelar cómo crecen, envejecen y se mueven los habitantes del valle.


2.2 📊 De las tablas al análisis espacial

Con paciencia y precisión, Tochtli toma las tablas del ITER y selecciona las variables necesarias para darles voz.
El objetivo es que los datos censales se conviertan en cartografías vivas, donde podamos leer las transformaciones del territorio:
sus procesos de crecimiento, envejecimiento y migración.

“Un indicador no es solo un número —dice Tochtli—.
Es una historia del territorio contada en lenguaje de datos.”


2.3 📈 1. Tasa de crecimiento medio anual

Mide la velocidad con la que crece la población en un periodo determinado.

\[ TCMA = \left( \frac{P_2}{P_1} \right)^{\frac{1}{t}} - 1 \]

  • P₁ = población inicial (año 2000)
  • P₂ = población final (año 2020)
  • t = número de años transcurridos (20 años)

📖 Interpretación:
Este indicador permite comparar el crecimiento relativo entre municipios, independientemente de su tamaño.
En Geotitlán, Tochtli lo ve como la pulsación vital del territorio, el ritmo con que cada municipio late y se expande.


2.4 🌆 2. Densidad de población

Expresa cuántas personas viven, en promedio, por kilómetro cuadrado.

\[ Densidad = \frac{Población \ total}{Superficie \ territorial} \]

  • Población total = obtenida del censo correspondiente
  • Superficie = derivada de la capa espacial del municipio (INEGI)

📖 Interpretación:
La densidad muestra cómo se concentra la vida en el territorio.
Tochtli la compara con las chinampas del valle: algunas rebosan de actividad, otras se extienden en silencio.


2.5 👵 3. Índice de envejecimiento

Mide la proporción de personas mayores respecto a la población joven.

\[ Índice = \frac{P_{65+}}{P_{0-64}} \times 100 \]

📖 Interpretación:
Cuando este índice es alto, Tochtli dice que el territorio cuenta sus historias con voces sabias y pausadas.
Cuando es bajo, el territorio canta con energía y juventud.


2.6 👶 4. Índice de juventud

Mide la proporción de población joven frente a la adulta.

\[ Índice = \frac{P_{0-14}}{P_{15+}} \times 100 \]

📖 Interpretación:
Refleja la estructura por edades de la población.
Junto con el índice de envejecimiento, Tochtli lo usa para prever las necesidades sociales y educativas de cada municipio.
> “En la pirámide de edades —dice— se esconden las semillas del futuro.”


2.7 🧭 5. Atracción migratoria reciente

Mide la llegada de población proveniente de otras entidades en los últimos años.

\[ AM_{reciente} = \frac{Población \ residente \ en \ otra \ entidad}{Población \ total} \times 100 \]

📖 Interpretación:
Este indicador revela los caminos del movimiento humano.
Tochtli lo interpreta como el pulso de los viajeros que llegan a Geotitlán buscando nuevas raíces.


2.8 🧳 6. Atracción migratoria acumulada

Evalúa la proporción de población nacida en otra entidad federativa.

\[ AM_{acumulada} = \frac{Población \ nacida \ en \ otra \ entidad}{Población \ total} \times 100 \]

📖 Interpretación:
Muestra el atractivo histórico de un municipio como destino migratorio.
Cada cifra representa una historia de desplazamiento, adaptación y encuentro.


2.9 ⚙️ 7. Tasa de actividad económica

Mide el porcentaje de población mayor de 12 años que participa en actividades económicas.

\[ Tasa_{actividad} = \frac{Población \ económicamente \ activa}{Población_{12+}} \times 100 \]

📖 Interpretación:
Indica la energía productiva del territorio.
Tochtli dice que aquí se ve cómo las manos y los oficios dan forma al valle.


2.10 ⚖️ 8. Índice de dependencia económica

Compara la población dependiente (niños y adultos mayores) con la población en edad laboral.

\[ IDE = \frac{P_{0-14} + P_{65+}}{P_{15-64}} \times 100 \]

📖 Interpretación:
Un valor alto implica más personas que dependen de cada 100 en edad laboral.
Para Tochtli, este equilibrio habla de solidaridad y sostenibilidad: territorios que cuidan de muchos, pero deben planear con cuidado su futuro.


2.11 🏙️ 9. Grado de urbanización

Mide la proporción de población que vive en localidades urbanas respecto al total municipal.

📖 Interpretación:
Este indicador refleja el proceso de concentración urbana.
Desde lo alto, Tlacolotl —el aguililla guardián— observa las luces de la ciudad crecer,
mientras Tochtli analiza sus causas con código y paciencia.


💡 Reflexión final:

ese es el viaje de Tochtli por Geotitlán.
Porque los datos solo cobran sentido cuando nos ayudan a cuidar el territorio que habitamos.”

# ============================================================
# 🧩 SELECCIÓN, HOMOLOGACIÓN Y UNIÓN DE VARIABLES CENSALES
# ============================================================
# Objetivo: dejar un solo dataframe con las variables de 2010 y 2020
# comparables por municipio (cve_mun), incluyendo el nombre del municipio.
# ============================================================

library(dplyr)
library(janitor)
library(stringr)
library(tidyr)

# ------------------------------------------------------------
# 1️⃣ LIMPIAR NOMBRES DE COLUMNAS
# ------------------------------------------------------------
mun_2010 <- mun_2010 %>% clean_names()
mun_2020 <- mun_2020 %>% clean_names()

# ------------------------------------------------------------
# 2️⃣ SELECCIONAR VARIABLES CLAVE PARA 2010
# ------------------------------------------------------------
mun_2010_vars <- mun_2010 %>%
  select(
    cve_mun,
    anio,
    pob_total      = pobtot,      # población total
    pob_12_mas     = p_12ymas,    # población de 12 años y más
    pob_0_14       = pob0_14,     # población de 0 a 14 años
    pob_15_64      = pob15_64,    # población de 15 a 64 años
    pob_65_mas     = pob65_mas,   # población de 65 años y más
    pob_nac_ot     = pnacoe,      # nacidos en otra entidad
    pob_econ_act   = pea          # población económicamente activa
  )

# ------------------------------------------------------------
# 3️⃣ SELECCIONAR VARIABLES CLAVE PARA 2020
# ------------------------------------------------------------
mun_2020_vars <- mun_2020 %>%
  select(
    cve_mun,
    anio,
    nom_ent,
    nom_mun,
    pob_total      = pobtot,      # población total (POBTOT)
    pob_12_mas     = p_12ymas,    # población de 12 años y más
    pob_15_mas     = p_15ymas,    # población de 15 años y más
    pob_0_14       = pob0_14,     # población de 0 a 14 años
    pob_15_64      = pob15_64,    # población de 15 a 64 años
    pob_65_mas     = pob65_mas,   # población de 65 años y más
    pob_nac_ot     = pnacoe,      # nacidos en otra entidad
    pob_econ_act   = pea          # población económicamente activa
  )

# ------------------------------------------------------------
# 4️⃣ RENOMBRAR VARIABLES CON SUFIJO DE AÑO (_10 y _20)
# ------------------------------------------------------------
mun_2010_wide <- mun_2010_vars %>%
  rename_with(~ paste0(., "_10"), .cols = -cve_mun)

mun_2020_wide <- mun_2020_vars %>%
  rename_with(~ paste0(., "_20"), .cols = -cve_mun)

# ------------------------------------------------------------
# 5️⃣ UNIR POR CLAVE MUNICIPAL (cve_mun)
# ------------------------------------------------------------
mun_10_20 <- full_join(mun_2010_wide, mun_2020_wide, by = "cve_mun")

# ------------------------------------------------------------
# 6️⃣ CHEQUEOS RÁPIDOS
# ------------------------------------------------------------
glimpse(mun_10_20)
## Rows: 2,469
## Columns: 20
## $ cve_mun         <chr> "01001", "01002", "01003", "01004", "01005", "01006", …
## $ anio_10         <dbl> 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, …
## $ pob_total_10    <dbl> 797010, 45492, 54136, 15042, 99590, 41862, 49156, 8443…
## $ pob_12_mas_10   <chr> "602719", "32320", "39898", "10801", "69970", "30172",…
## $ pob_0_14_10     <chr> "238193", "16209", "17800", "5255", "35746", "14373", …
## $ pob_15_64_10    <chr> "515262", "26623", "32248", "8930", "59840", "25250", …
## $ pob_65_mas_10   <chr> "40309", "2627", "4034", "844", "3640", "2169", "2520"…
## $ pob_nac_ot_10   <chr> "186972", "5194", "6379", "1378", "16300", "4636", "37…
## $ pob_econ_act_10 <chr> "336974", "14319", "19310", "4819", "39315", "14892", …
## $ anio_20         <dbl> 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, …
## $ nom_ent_20      <chr> "Aguascalientes", "Aguascalientes", "Aguascalientes", …
## $ nom_mun_20      <chr> "Aguascalientes", "Asientos", "Calvillo", "Cosío", "Je…
## $ pob_total_20    <dbl> 948990, 51536, 58250, 17000, 129929, 47646, 57369, 955…
## $ pob_12_mas_20   <chr> "756970", "38399", "44778", "12820", "99250", "36250",…
## $ pob_15_mas_20   <chr> "707473", "35250", "41495", "11817", "91487", "33468",…
## $ pob_0_14_20     <chr> "240583", "16266", "16720", "5183", "38303", "14140", …
## $ pob_15_64_20    <chr> "639532", "31919", "35854", "10699", "84949", "30491",…
## $ pob_65_mas_20   <chr> "67941", "3331", "5641", "1118", "6538", "2977", "3579…
## $ pob_nac_ot_20   <chr> "214908", "6025", "6566", "1385", "23898", "4416", "49…
## $ pob_econ_act_20 <chr> "486675", "21440", "25976", "7010", "65839", "22097", …
# Municipios presentes solo en un año
missing_2010 <- mun_10_20 %>% filter(is.na(pob_total_10)) %>% nrow()
missing_2020 <- mun_10_20 %>% filter(is.na(pob_total_20)) %>% nrow()

cat("🟡 Municipios que aparecen en 2020 pero no en 2010:", missing_2010, "\n")
## 🟡 Municipios que aparecen en 2020 pero no en 2010: 13
cat("🟡 Municipios que aparecen en 2010 pero no en 2020:", missing_2020, "\n")
## 🟡 Municipios que aparecen en 2010 pero no en 2020: 0
# Vista rápida de las columnas principales
mun_10_20 %>%
  select(cve_mun, nom_ent_20, nom_mun_20, 
         starts_with("pob_total"), starts_with("pob_econ_act")) %>%
 head() 
## # A tibble: 6 × 7
##   cve_mun nom_ent_20     nom_mun_20    pob_total_10 pob_total_20 pob_econ_act_10
##   <chr>   <chr>          <chr>                <dbl>        <dbl> <chr>          
## 1 01001   Aguascalientes Aguascalient…       797010       948990 336974         
## 2 01002   Aguascalientes Asientos             45492        51536 14319          
## 3 01003   Aguascalientes Calvillo             54136        58250 19310          
## 4 01004   Aguascalientes Cosío                15042        17000 4819           
## 5 01005   Aguascalientes Jesús María          99590       129929 39315          
## 6 01006   Aguascalientes Pabellón de …        41862        47646 14892          
## # ℹ 1 more variable: pob_econ_act_20 <chr>
# ------------------------------------------------------------
# 📊 Vista interactiva con DT de columnas clave (2010 vs 2020)
# ------------------------------------------------------------
library(DT)

tabla_vista <- mun_10_20 %>%
  select(
    cve_mun, nom_ent_20, nom_mun_20,
    pob_total_10, pob_total_20,
    pob_econ_act_10, pob_econ_act_20
  )

DT::datatable(
  tabla_vista,
  options = list(
    pageLength = 10,
    scrollX = TRUE,
    autoWidth = TRUE,
    language = list(url = '//cdn.datatables.net/plug-ins/1.13.1/i18n/es-ES.json')
  ),
  filter = "top",
  caption = "Comparativo municipal 2010 vs 2020 (población total y PEA)"
)

2.12 🧭 Identificando nuevos municipios

Mientras explora las tablas del Censo 2010 y del Censo 2020,
Tochtli nota algo fascinante: el territorio no es estático, también cambia y se reconfigura.
A veces, los municipios se dividen, se renombran o nacen de otros, como brotes nuevos en el mapa de Geotitlán.

Para descubrirlos, Tochtli compara los códices del 2010 y 2020, buscando aquellos lugares que: - 🌱 Sí tienen datos en 2020 (pob_total_20 no es NA),
- 🌾 Pero no aparecen en 2010 (pob_total_10 sí es NA).

Con esta comparación, obtiene una lista de municipios nuevos creados o reconocidos oficialmente durante el periodo 2010–2020,
junto con su población y entidad correspondiente.

# ------------------------------------------------------------
# 🆕 DETECTAR NUEVOS MUNICIPIOS (presentes en 2020, ausentes en 2010)
# ------------------------------------------------------------
library(dplyr)

# Filtramos los municipios que existen en 2020 pero no en 2010
nuevos_municipios <- mun_10_20 %>%
  filter(is.na(pob_total_10) & !is.na(pob_total_20)) %>%
  select(cve_mun, nom_ent_20, nom_mun_20, pob_total_20)

# Mostramos los resultados
cat("Número de nuevos municipios en 2020:", nrow(nuevos_municipios), "\n")
## Número de nuevos municipios en 2020: 13
# Vista rápida
nuevos_municipios %>% 
  arrange(nom_ent_20, nom_mun_20) %>% 
  head(20)
## # A tibble: 13 × 4
##    cve_mun nom_ent_20      nom_mun_20               pob_total_20
##    <chr>   <chr>           <chr>                           <dbl>
##  1 02006   Baja California San Quintín                    117568
##  2 04012   Campeche        Seybaplaya                      15297
##  3 07120   Chiapas         Capitán Luis Ángel Vidal         4315
##  4 07122   Chiapas         El Parral                       15587
##  5 07123   Chiapas         Emiliano Zapata                 10783
##  6 07125   Chiapas         Honduras de la Sierra           11650
##  7 07124   Chiapas         Mezcalapa                       23847
##  8 07121   Chiapas         Rincón Chamula San Pedro         8718
##  9 17034   Morelos         Coatetelco                      11347
## 10 17036   Morelos         Hueyapan                         7855
## 11 17035   Morelos         Xoxocotla                       27805
## 12 23010   Quintana Roo    Bacalar                         41754
## 13 23011   Quintana Roo    Puerto Morelos                  26921

3 🧮 Del dato al indicador: el arte de traducir el territorio

3.1 🧩 El reto de descifrar los códices del INEGI

En los caminos de Geotitlán, Tochtli descubre que los censos del INEGI son como códices antiguos:
repletos de información valiosa, pero escritos en lenguajes cambiantes.
Cada edición guarda sus secretos —nombres distintos, estructuras modificadas, nuevas variables—
y solo quien aprende a leerlos puede revelar las historias que el territorio esconde.

Antes de mapear, Tochtli debe ordenar los datos, depurarlos y elegir los campos que servirán para construir indicadores territoriales,
aquellos que narran cómo crecen, envejecen y se mueven los pueblos del valle.


3.2 📊 De las tablas al territorio

Con paciencia de artesana, Tochtli toma los datos del ITER
y selecciona las variables que darán vida a los mapas de Geotitlán.
Cada tabla se transforma en una representación del espacio y del tiempo,
un tejido de cifras que refleja la diversidad y el ritmo de cada municipio.

“Un indicador —dice Tochtli— no es solo una fórmula.
Es una historia del territorio escrita con números.”


3.3 📈 1. Tasa de crecimiento medio anual 🌱

Mide la velocidad con que la población crece en un periodo determinado:

\[ TCMA = \left( \frac{P_2}{P_1} \right)^{\frac{1}{t}} - 1 \]

  • P₁: población inicial (año 2000)
  • P₂: población final (año 2020)
  • t: 20 años transcurridos

📖 Lectura en Geotitlán:
Cada municipio tiene su propio pulso.
La TCMA revela su latido demográfico: los que crecen rápido son fuegos nuevos;
los que decrecen, ecos de antiguos asentamientos.


3.4 🌆 2. Densidad de población 🏞️

Expresa cuántas personas habitan, en promedio, por kilómetro cuadrado:

\[ Densidad = \frac{Población \ total}{Superficie \ territorial} \]

📖 Lectura en Geotitlán:
En los mapas de Tochtli, las zonas densas se iluminan como mercados bulliciosos,
mientras las zonas dispersas respiran el silencio del campo.
Ambas son parte del equilibrio vital del territorio.


3.5 👵 3. Índice de envejecimiento 🌾

Mide la proporción de personas mayores respecto a la población joven:

\[ Índice = \frac{P_{65+}}{P_{0-64}} \times 100 \]

📖 Lectura:
Cuando el valor es alto, el territorio habla con voces sabias y pausadas.
Cuando es bajo, predomina la energía del futuro.


3.6 👶 4. Índice de juventud 🌺

Evalúa la proporción de población joven frente a la adulta:

\[ Índice = \frac{P_{0-14}}{P_{15+}} \times 100 \]

📖 Lectura:
Los municipios jóvenes son como campos recién sembrados:
prometen cosechas, pero necesitan cuidado y planificación.


3.7 🧭 5. Atracción migratoria reciente 🚶‍♀️

Mide la llegada de población de otras entidades en los últimos años:

\[ A.M. \ Reciente = \frac{Población \ residente \ en \ otra \ entidad}{Población \ total} \times 100 \]

📖 Lectura:
Revela los caminos del movimiento humano.
Tochtli lo llama el pulso del viento, que trae nuevas raíces a las tierras de Geotitlán.


3.8 🧳 6. Atracción migratoria acumulada 🌍

Evalúa la proporción de personas nacidas en otra entidad:

\[ A.M. \ Acumulada = \frac{Población \ nacida \ en \ otra \ entidad}{Población \ total} \times 100 \]

📖 Lectura:
Cada cifra es una historia de desplazamiento.
Geotitlán crece con la memoria de quienes llegaron de lejos a quedarse.


3.9 ⚙️ 7. Tasa de actividad económica ⚒️

Mide el porcentaje de población mayor de 12 años que participa en actividades económicas:

\[ Tasa \ de \ actividad = \frac{Población \ económicamente \ activa}{Población_{12+}} \times 100 \]

📖 Lectura:
Aquí late la fuerza productiva del territorio:
manos, oficios y saberes que sostienen la vida cotidiana.


3.10 ⚖️ 8. Índice de dependencia económica 🤝

Compara la población dependiente (niños y mayores) con la población en edad laboral:

\[ Índice = \frac{P_{0-14} + P_{65+}}{P_{15-64}} \times 100 \]

📖 Lectura:
Un valor alto revela municipios solidarios pero presionados;
un valor bajo, territorios con estructura más estable.
Ambos enseñan lecciones sobre cómo se distribuye el esfuerzo colectivo.


3.11 🏙️ 9. Grado de urbanización 🌇

Mide la proporción de población que vive en localidades urbanas:

📖 Lectura:
El territorio urbano brilla con intensidad,
pero Tochtli recuerda que la ciudad también debe escuchar al campo que la rodea.
El equilibrio entre ambos mundos es clave para la armonía de Geotitlán.


4 🧩 Los nombres del dato: homologando los censos

Tochtli descubre que los censos del 2000, 2010 y 2020 usan palabras distintas para nombrar las mismas cosas.
Por eso, antes de combinarlos, debe homologar los nombres para que las fórmulas entiendan el mismo idioma.

Concepto 2010 2020 Descripción
Población total pobtot POBTOT Habitantes del municipio
Población de 0 a 14 años pob0_14 POB0_14 Infancia
Población de 15 a 64 años pob15_64 POB15_64 Edad laboral
Población 65 y más pob65_mas POB65_MAS Personas mayores
Población nacida en otra entidad pnacoe PNACOE Migración interna
Población económicamente activa pea PEA Fuerza laboral

“Cuando los datos hablan el mismo idioma —dice Tochtli—
el territorio puede contarse a sí mismo con claridad.”


4.1 🔗 Tejiendo los censos con la clave municipal 🧵

Para unir los años 2010 y 2020, Tochtli usa la clave municipal (cve_mun) como hilo conductor.
Primero renombra las columnas con sufijos _10 y _20, luego las enlaza con full_join().

Así obtiene una gran tabla donde cada municipio muestra su evolución a través del tiempo:
su población, su estructura por edades, su actividad económica y sus flujos migratorios.

“En cada unión de tablas —dice Tochtli mientras observa el código correr—
los datos tejen la memoria del territorio.”


💡 Reflexión final:
> En Geotitlán, programar es también una forma de cuidar.
> Los indicadores no son solo estadísticas:
> son espejos del territorio, semillas de planeación y caminos de conocimiento.

# ============================================================
# 🧩 SELECCIÓN, HOMOLOGACIÓN Y UNIÓN DE VARIABLES CENSALES
# ============================================================
# Objetivo: dejar un solo dataframe con las variables de 2010 y 2020
# comparables por municipio (cve_mun), incluyendo el nombre del municipio.
# ============================================================

library(dplyr)
library(janitor)
library(stringr)
library(tidyr)

# ------------------------------------------------------------
# 1️⃣ LIMPIAR NOMBRES DE COLUMNAS
# ------------------------------------------------------------
mun_2010 <- mun_2010 %>% clean_names()
mun_2020 <- mun_2020 %>% clean_names()

# ------------------------------------------------------------
# 2️⃣ SELECCIONAR VARIABLES CLAVE PARA 2010
# ------------------------------------------------------------
mun_2010_vars <- mun_2010 %>%
  select(
    cve_mun,
    anio,
    pob_total      = pobtot,      # población total
    pob_12_mas     = p_12ymas,    # población de 12 años y más
    pob_0_14       = pob0_14,     # población de 0 a 14 años
    pob_15_64      = pob15_64,    # población de 15 a 64 años
    pob_65_mas     = pob65_mas,   # población de 65 años y más
    pob_nac_ot     = pnacoe,      # nacidos en otra entidad
    pob_econ_act   = pea          # población económicamente activa
  )

# ------------------------------------------------------------
# 3️⃣ SELECCIONAR VARIABLES CLAVE PARA 2020
# ------------------------------------------------------------
mun_2020_vars <- mun_2020 %>%
  select(
    cve_mun,
    anio,
    nom_ent,
    nom_mun,
    pob_total      = pobtot,      # población total (POBTOT)
    pob_12_mas     = p_12ymas,    # población de 12 años y más
    pob_15_mas     = p_15ymas,    # población de 15 años y más
    pob_0_14       = pob0_14,     # población de 0 a 14 años
    pob_15_64      = pob15_64,    # población de 15 a 64 años
    pob_65_mas     = pob65_mas,   # población de 65 años y más
    pob_nac_ot     = pnacoe,      # nacidos en otra entidad
    pob_econ_act   = pea          # población económicamente activa
  )

# ------------------------------------------------------------
# 4️⃣ RENOMBRAR VARIABLES CON SUFIJO DE AÑO (_10 y _20)
# ------------------------------------------------------------
mun_2010_wide <- mun_2010_vars %>%
  rename_with(~ paste0(., "_10"), .cols = -cve_mun)

mun_2020_wide <- mun_2020_vars %>%
  rename_with(~ paste0(., "_20"), .cols = -cve_mun)

# ------------------------------------------------------------
# 5️⃣ UNIR POR CLAVE MUNICIPAL (cve_mun)
# ------------------------------------------------------------
mun_10_20 <- full_join(mun_2010_wide, mun_2020_wide, by = "cve_mun")

# ------------------------------------------------------------
# 6️⃣ CHEQUEOS RÁPIDOS
# ------------------------------------------------------------
glimpse(mun_10_20)
## Rows: 2,469
## Columns: 20
## $ cve_mun         <chr> "01001", "01002", "01003", "01004", "01005", "01006", …
## $ anio_10         <dbl> 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, …
## $ pob_total_10    <dbl> 797010, 45492, 54136, 15042, 99590, 41862, 49156, 8443…
## $ pob_12_mas_10   <chr> "602719", "32320", "39898", "10801", "69970", "30172",…
## $ pob_0_14_10     <chr> "238193", "16209", "17800", "5255", "35746", "14373", …
## $ pob_15_64_10    <chr> "515262", "26623", "32248", "8930", "59840", "25250", …
## $ pob_65_mas_10   <chr> "40309", "2627", "4034", "844", "3640", "2169", "2520"…
## $ pob_nac_ot_10   <chr> "186972", "5194", "6379", "1378", "16300", "4636", "37…
## $ pob_econ_act_10 <chr> "336974", "14319", "19310", "4819", "39315", "14892", …
## $ anio_20         <dbl> 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, …
## $ nom_ent_20      <chr> "Aguascalientes", "Aguascalientes", "Aguascalientes", …
## $ nom_mun_20      <chr> "Aguascalientes", "Asientos", "Calvillo", "Cosío", "Je…
## $ pob_total_20    <dbl> 948990, 51536, 58250, 17000, 129929, 47646, 57369, 955…
## $ pob_12_mas_20   <chr> "756970", "38399", "44778", "12820", "99250", "36250",…
## $ pob_15_mas_20   <chr> "707473", "35250", "41495", "11817", "91487", "33468",…
## $ pob_0_14_20     <chr> "240583", "16266", "16720", "5183", "38303", "14140", …
## $ pob_15_64_20    <chr> "639532", "31919", "35854", "10699", "84949", "30491",…
## $ pob_65_mas_20   <chr> "67941", "3331", "5641", "1118", "6538", "2977", "3579…
## $ pob_nac_ot_20   <chr> "214908", "6025", "6566", "1385", "23898", "4416", "49…
## $ pob_econ_act_20 <chr> "486675", "21440", "25976", "7010", "65839", "22097", …
# Municipios presentes solo en un año
missing_2010 <- mun_10_20 %>% filter(is.na(pob_total_10)) %>% nrow()
missing_2020 <- mun_10_20 %>% filter(is.na(pob_total_20)) %>% nrow()

cat("🟡 Municipios que aparecen en 2020 pero no en 2010:", missing_2010, "\n")
## 🟡 Municipios que aparecen en 2020 pero no en 2010: 13
cat("🟡 Municipios que aparecen en 2010 pero no en 2020:", missing_2020, "\n")
## 🟡 Municipios que aparecen en 2010 pero no en 2020: 0
# Vista rápida de las columnas principales
mun_10_20 %>%
  select(cve_mun, nom_ent_20, nom_mun_20, 
         starts_with("pob_total"), starts_with("pob_econ_act")) %>%
 head() 
## # A tibble: 6 × 7
##   cve_mun nom_ent_20     nom_mun_20    pob_total_10 pob_total_20 pob_econ_act_10
##   <chr>   <chr>          <chr>                <dbl>        <dbl> <chr>          
## 1 01001   Aguascalientes Aguascalient…       797010       948990 336974         
## 2 01002   Aguascalientes Asientos             45492        51536 14319          
## 3 01003   Aguascalientes Calvillo             54136        58250 19310          
## 4 01004   Aguascalientes Cosío                15042        17000 4819           
## 5 01005   Aguascalientes Jesús María          99590       129929 39315          
## 6 01006   Aguascalientes Pabellón de …        41862        47646 14892          
## # ℹ 1 more variable: pob_econ_act_20 <chr>
# ------------------------------------------------------------
# 📜 Los códices comparados: leyendo el cambio en el territorio
# ------------------------------------------------------------
# Tochtli prepara una vista paralela entre los censos de 2010 y 2020.
# Con esta tabla, puede observar cómo creció cada municipio,
# tanto en población total como en fuerza laboral (PEA).
# Es como mirar dos mapas temporales superpuestos, donde los números
# cuentan la historia de diez años de transformaciones en Geotitlán.

library(DT)

tabla_vista <- mun_10_20 %>%
  select(
    cve_mun,        # clave única del municipio: el hilo del tejido territorial
    nom_ent_20,     # nombre de la entidad (2020)
    nom_mun_20,     # nombre del municipio (2020)
    pob_total_10,   # población total en 2010
    pob_total_20,   # población total en 2020
    pob_econ_act_10,# población económicamente activa en 2010
    pob_econ_act_20 # población económicamente activa en 2020
  )

# 🌾 Tochtli invoca la magia de las tablas interactivas
# Cada fila es una historia municipal, cada columna un eco del tiempo.
DT::datatable(
  tabla_vista,
  options = list(
    pageLength = 10,  # diez historias por página
    scrollX = TRUE,   # permite navegar el códice horizontalmente
    autoWidth = TRUE,
    language = list(url = '//cdn.datatables.net/plug-ins/1.13.1/i18n/es-ES.json')
  ),
  filter = "top",  # filtros que actúan como lupas para explorar patrones
  caption = "🧭 Comparativo municipal 2010–2020: la evolución de la población y la actividad económica en Geotitlán"
)

4.2 🧮 Cálculo de indicadores territoriales

En esta etapa del viaje, Tochtli transforma los números crudos del censo en sabiduría territorial.
Los datos dejan de ser simples tablas y se convierten en instrumentos para leer el pulso de los municipios.
Aquí el código se vuelve alquimia: del texto, surge el número; del número, el indicador; y del indicador, la historia del territorio.


4.2.1 🌾 1️⃣ Conversión a formato numérico

Los códices del INEGI suelen llegar con cifras enmascaradas,
como si los números fueran símbolos antiguos escritos con comas y espacios —“12,345” en vez de 12345—.
R no puede calcular con ellos directamente, así que Tochtli utiliza su primera herramienta mágica:
parse_number() del paquete readr.

Esta función: - 🌿 Elimina comas, signos o espacios. - 🔢 Convierte los textos en números reales. - ⚙️ Prepara el terreno para los cálculos posteriores.

💻 Código:

# 🧮 CONVERSIÓN A NUMÉRICO Y CÁLCULO DE INDICADORES
# ------------------------------------------------------------
library(dplyr)
library(readr)

# 1️⃣ Convertir columnas de población a numéricas
# (quita comas, espacios y convierte a numeric)
mun_10_20_num <- mun_10_20 %>%
  mutate(across(
    matches("^pob_|pobtot|p_"), 
    ~ parse_number(as.character(.))
  ))

# 2️⃣ Calcular indicadores
indicadores_mun <- mun_10_20_num %>%
  mutate(
    # --- Tasa de Crecimiento Medio Anual (TCMA)
    tcma = ((pob_total_20 / pob_total_10)^(1/10) - 1) * 100,

    # --- Índice de Envejecimiento
    ind_envejec_10 = (pob_65_mas_10 / pob_0_14_10) * 100,
    ind_envejec_20 = (pob_65_mas_20 / pob_0_14_20) * 100,

    # --- Índice de Juventud
    ind_juventud_10 = (pob_0_14_10 / (pob_15_64_10 + pob_65_mas_10)) * 100,
    ind_juventud_20 = (pob_0_14_20 / (pob_15_64_20 + pob_65_mas_20)) * 100,

    # --- Índice de Dependencia Económica
    ind_depend_10 = ((pob_0_14_10 + pob_65_mas_10) / pob_15_64_10) * 100,
    ind_depend_20 = ((pob_0_14_20 + pob_65_mas_20) / pob_15_64_20) * 100,

    # --- Atracción migratoria acumulada
    atr_migr_10 = (pob_nac_ot_10 / pob_total_10) * 100,
    atr_migr_20 = (pob_nac_ot_20 / pob_total_20) * 100,

    # --- Tasa de actividad económica
    tasa_act_10 = (pob_econ_act_10 / pob_12_mas_10) * 100,
    tasa_act_20 = (pob_econ_act_20 / pob_12_mas_20) * 100
  )

# 3️⃣ Revisar resultados
indicadores_mun %>%
  select(nom_ent_20, nom_mun_20, tcma, ind_envejec_20, ind_depend_20, atr_migr_20, tasa_act_20) %>%
  head()
## # A tibble: 6 × 7
##   nom_ent_20     nom_mun_20        tcma ind_envejec_20 ind_depend_20 atr_migr_20
##   <chr>          <chr>            <dbl>          <dbl>         <dbl>       <dbl>
## 1 Aguascalientes Aguascalientes   1.76            28.2          48.2       22.6 
## 2 Aguascalientes Asientos         1.26            20.5          61.4       11.7 
## 3 Aguascalientes Calvillo         0.735           33.7          62.4       11.3 
## 4 Aguascalientes Cosío            1.23            21.6          58.9        8.15
## 5 Aguascalientes Jesús María      2.69            17.1          52.8       18.4 
## 6 Aguascalientes Pabellón de Art… 1.30            21.1          56.1        9.27
## # ℹ 1 more variable: tasa_act_20 <dbl>

4.3 🛰️ R como plataforma geoespacial: las herramientas del viajero

En Geotitlán, R es más que un lenguaje de programación:
es una mochila llena de instrumentos para recorrer y representar el territorio.
Cada librería es una herramienta ancestral reimaginada en código,
capaz de leer, transformar y pintar el espacio geográfico.


4.3.1 🌍 Herramientas esenciales de Tochtli

  • 🗺️ sf (simple features)
    Es el pincel cartográfico de R.
    Permite leer y escribir datos espaciales —Shapefile, GeoJSON, GeoPackage
    y trabajar con geometrías (puntos, líneas y polígonos).
    También comprende los sistemas de proyección (CRS),
    para que los mapas conserven su forma y sentido en el mundo.

  • 🎨 tmap
    La paleta visual de Geotitlán.
    Crea mapas temáticos, estáticos o interactivos,
    con una sintaxis clara y expresiva.
    Con tmap, los datos cobran color y las variables encuentran su voz.

  • 🔗 dplyr
    El telar de datos.
    Une, filtra y transforma tablas;
    permite fusionar las estadísticas del censo con la geometría del territorio.
    Sin él, los datos quedarían dispersos, sin historia ni forma.

  • 🧹 janitor (opcional)
    El limpiador del códice.
    Establece nombres claros y uniformes en las columnas,
    evitando errores por mayúsculas, tildes o espacios.
    Tochtli lo usa antes de cualquier ritual analítico.


📝 Tip geotitlense:
En Windows, recuerda escribir las rutas con “/” o doble “\”.
Así evitas que los caminos del código se confundan y el mapa se pierda.


📖 Reflexión:
> “Cada librería es una extensión de nuestra mirada.
> Con ellas, el territorio se revela línea a línea,
> capa a capa, como un códice que respira.” — Tochtli

# 🗺️ Lectura de la capa municipal: el mapa base de Geotitlán
# ------------------------------------------------------------
# Tochtli abre el códice espacial donde descansan los contornos
# de los municipios de México. Cada polígono es una historia,
# una frontera, una memoria grabada en coordenadas.

library(sf)
## Linking to GEOS 3.13.1, GDAL 3.11.0, PROJ 9.6.0; sf_use_s2() is TRUE
library(dplyr)
library(stringr)
library(janitor)
library(tmap)

# 🌎 1) Ruta hacia los archivos espaciales de Geotitlán
# (Ajustada a tu nueva estructura de carpetas)
ruta_shp <- "C:/geodatos/Datos espaciales/00mun.shp"

# 🧭 2) Lectura y limpieza del shapefile
mun_sf <- sf::read_sf(ruta_shp) %>%
  janitor::clean_names() 

4.4 🗺️ Mapeando municipios con R

Con solo unas pocas líneas de código, R puede leer y visualizar información geográfica.

  1. sf::read_sf() lee un archivo espacial (como un .shp), conservando su geometría.
  2. tmap nos permite crear mapas de forma rápida y reproducible.
  3. Con tmap_mode("plot") obtenemos un mapa estático; cambiando a "view" generamos un mapa interactivo con zoom y desplazamiento.

Este primer mapa muestra todos los municipios de México con su delimitación básica, demostrando que R puede comportarse como una plataforma geoespacial completa sin necesidad de interfaces gráficas.

# 3️⃣ Mapa estilo Mondrian con tmap
library(tmap)

tmap_mode("plot") # 'plot' = mapa estático; usa 'view' para interactivo
## ℹ tmap modes "plot" - "view"
## ℹ toggle with `tmap::ttm()`
tm_shape(mun_sf) +
  tm_polygons(
    col = "#FFD100",         # 🟨 Amarillo dominante
    border.col = "#000000",  # Bordes negros gruesos
    lwd = 0.6,               
    title = "Municipios"
  ) +
  tm_layout(
    title = "🟥🟨🟦 Mapa Mondrian de municipios de México",
    title.size = 1.4,
    frame = TRUE,                 # Marco visible
    frame.lwd = 3,                # Borde grueso tipo Mondrian
    bg.color = "#FFFFFF",         # Fondo blanco
    outer.bg.color = "#0033A0",   # Fondo externo azul profundo
    legend.bg.color = "#C8102E",  # Fondo de la leyenda rojo
    legend.text.color = "white",  # Texto de leyenda en blanco
    legend.title.color = "white",
    legend.outside = TRUE,
    legend.outside.position = "right",
    main.title.position = "center",
    main.title.color = "#0033A0",
    main.title.fontface = "bold"
  ) +
  tm_compass(
    type = "4star",
    position = c("left", "bottom"),
    color.light = "#FFD100",
    color.dark = "#C8102E"
  ) +
  tm_scale_bar(
    position = c("left", "bottom"),
    text.color = "#0033A0",
    color.dark = "#000000",
    color.light = "#FFD100"
  )
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_polygons()`: use 'fill' for the fill color of polygons/symbols
## (instead of 'col'), and 'col' for the outlines (instead of 'border.col').[v3->v4] `tm_polygons()`: migrate the argument(s) related to the legend of the
## visual variable `fill` namely 'title' to 'fill.legend = tm_legend(<HERE>)'[v3->v4] `tm_layout()`: use `tm_title()` instead of `tm_layout(title = )`! `tm_scale_bar()` is deprecated. Please use `tm_scalebar()` instead.

# Integrando datos espaciales y estadísticos

Hasta este punto del taller, hemos trabajado con dos tipos de información complementaria:

🗺️ El shapefile municipal (mun_sf): Contiene la geometría (los polígonos de los municipios), sus límites y nombres oficiales.

📊 La tabla de indicadores (indicadores_mun): Contiene los datos estadísticos calculados a partir de los censos (población, índices, tasas, etc.).

El objetivo de este bloque es unir ambos conjuntos de información para obtener una sola capa espacial con toda la información lista para mapear y analizar: geometría + indicadores.

# 🔗 UNIÓN mun_sf (cvegeo) + indicadores_mun (cve_mun)
# ------------------------------------------------------------
library(sf)
library(dplyr)
library(stringr)
library(janitor)

# 1️⃣ Aseguramos nombres limpios
mun_sf <- mun_sf %>% janitor::clean_names()

# 2️⃣ Función para normalizar a 5 dígitos (caracter)
pad5 <- function(x){
  x <- as.character(x)
  x <- stringr::str_replace_all(x, "[^0-9]", "")
  dplyr::if_else(nchar(x) == 0, NA_character_, stringr::str_pad(x, 5, pad = "0"))
}

# 3️⃣ Crear llave común 'cve_mun' en ambos objetos
mun_sf_key <- mun_sf %>%
  mutate(
    cve_mun = pad5(cvegeo)
  ) %>%
  select(cvegeo, cve_mun, nomgeo, everything())  # 👈 forzamos a mantener nomgeo

indicadores_key <- indicadores_mun %>%
  mutate(cve_mun = pad5(cve_mun))

# 4️⃣ Diagnóstico rápido de empates
faltan_en_ind <- mun_sf_key %>%
  st_drop_geometry() %>%
  anti_join(indicadores_key %>% select(cve_mun), by = "cve_mun")

sobran_en_ind <- indicadores_key %>%
  anti_join(mun_sf_key %>% st_drop_geometry() %>% select(cve_mun), by = "cve_mun")

cat("Claves en SHP sin match en indicadores:", nrow(faltan_en_ind), "\n")
## Claves en SHP sin match en indicadores: 0
cat("Claves en indicadores sin match en SHP:", nrow(sobran_en_ind), "\n")
## Claves en indicadores sin match en SHP: 0
# 5️⃣ Unión (manteniendo geometría y nombre del municipio)
mun_indicadores_sf <- mun_sf_key %>%
  left_join(indicadores_key, by = "cve_mun")

# 6️⃣ Comprobación de columnas clave tras el join
mun_indicadores_sf %>%
  select(cvegeo, cve_mun, nomgeo, 
         any_of(c("nom_ent_20", "nom_mun_20")),
         starts_with("pob_total"), starts_with("tcma"), starts_with("ind_")) %>%
  head()
## Simple feature collection with 6 features and 14 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 2410092 ymin: 1067540 xmax: 2514978 ymax: 1159778
## Projected CRS: MEXICO_ITRF_2008_LCC
## # A tibble: 6 × 15
##   cvegeo cve_mun nomgeo    nom_ent_20 nom_mun_20 pob_total_10 pob_total_20  tcma
##   <chr>  <chr>   <chr>     <chr>      <chr>             <dbl>        <dbl> <dbl>
## 1 01001  01001   Aguascal… Aguascali… Aguascali…       797010       948990 1.76 
## 2 01002  01002   Asientos  Aguascali… Asientos          45492        51536 1.26 
## 3 01003  01003   Calvillo  Aguascali… Calvillo          54136        58250 0.735
## 4 01004  01004   Cosío     Aguascali… Cosío             15042        17000 1.23 
## 5 01005  01005   Jesús Ma… Aguascali… Jesús Mar…        99590       129929 2.69 
## 6 01006  01006   Pabellón… Aguascali… Pabellón …        41862        47646 1.30 
## # ℹ 7 more variables: ind_envejec_10 <dbl>, ind_envejec_20 <dbl>,
## #   ind_juventud_10 <dbl>, ind_juventud_20 <dbl>, ind_depend_10 <dbl>,
## #   ind_depend_20 <dbl>, geometry <MULTIPOLYGON [m]>

Con este código, exportamos el objeto espacial mun_indicadores_sf, que ya contiene geometría y variables censales, como un shapefile estándar.

🔹 st_write() es la función del paquete sf para escribir archivos espaciales.
🔹 El parámetro driver = "ESRI Shapefile" indica el formato de salida.
🔹 delete_layer = TRUE permite sobrescribir el archivo si ya existe, evitando errores.

El resultado quedará en la ruta de trabajo o donde tu le des la dirección

# ------------------------------------------------------------
# 💾 EXPORTAR LA CAPA UNIDA COMO SHAPEFILE
# ------------------------------------------------------------
# Objetivo:
# Guardar la capa final 'mun_indicadores_sf' (municipios + indicadores)
# como shapefile para abrirla después en QGIS o ArcGIS.

library(sf)

# 1️⃣ Definir la ruta de salida
ruta_salida_shp <- "C:/SIG_RO/Taller_R/Salidas/indicadores_municipales.shp"

# 2️⃣ Exportar usando st_write()
st_write(
  obj = mun_indicadores_sf,
  dsn = ruta_salida_shp,
  driver = "ESRI Shapefile",
  delete_layer = TRUE  # sobrescribe si ya existe
)
## Warning in abbreviate_shapefile_names(obj): Field names abbreviated for ESRI
## Shapefile driver
## Deleting layer `indicadores_municipales' using driver `ESRI Shapefile'
## Writing layer `indicadores_municipales' to data source 
##   `C:/SIG_RO/Taller_R/Salidas/indicadores_municipales.shp' using driver `ESRI Shapefile'
## Writing 2469 features with 34 fields and geometry type Multi Polygon.
# 3️⃣ Confirmación visual
cat("✅ Shapefile exportado correctamente en:", ruta_salida_shp)
## ✅ Shapefile exportado correctamente en: C:/SIG_RO/Taller_R/Salidas/indicadores_municipales.shp
# 🗺️ FILTRO: MUNICIPIOS DEL ESTADO DE QUERÉTARO
# ------------------------------------------------------------
library(dplyr)
library(sf)

# 1️⃣ Verificar que el campo 'cve_ent' exista
names(mun_indicadores_sf)
##  [1] "cvegeo"          "cve_mun"         "nomgeo"          "cve_ent"        
##  [5] "geometry"        "anio_10"         "pob_total_10"    "pob_12_mas_10"  
##  [9] "pob_0_14_10"     "pob_15_64_10"    "pob_65_mas_10"   "pob_nac_ot_10"  
## [13] "pob_econ_act_10" "anio_20"         "nom_ent_20"      "nom_mun_20"     
## [17] "pob_total_20"    "pob_12_mas_20"   "pob_15_mas_20"   "pob_0_14_20"    
## [21] "pob_15_64_20"    "pob_65_mas_20"   "pob_nac_ot_20"   "pob_econ_act_20"
## [25] "tcma"            "ind_envejec_10"  "ind_envejec_20"  "ind_juventud_10"
## [29] "ind_juventud_20" "ind_depend_10"   "ind_depend_20"   "atr_migr_10"    
## [33] "atr_migr_20"     "tasa_act_10"     "tasa_act_20"
# 2️⃣ Filtrar solo Querétaro (clave 22)
mun_queretaro <- mun_indicadores_sf %>%
  filter(cve_ent == "22")

# 3️⃣ Verificar cuántos municipios tiene
mun_queretaro %>%
  st_drop_geometry() %>%
  count(cve_ent, sort = TRUE)
## # A tibble: 1 × 2
##   cve_ent     n
##   <chr>   <int>
## 1 22         18
# 4️⃣ Vista rápida de nombres de municipios
mun_queretaro %>%
  st_drop_geometry() %>%
  select(cve_ent, nomgeo) %>%
  head()
## # A tibble: 6 × 2
##   cve_ent nomgeo             
##   <chr>   <chr>              
## 1 22      Amealco de Bonfil  
## 2 22      Pinal de Amoles    
## 3 22      Arroyo Seco        
## 4 22      Cadereyta de Montes
## 5 22      Colón              
## 6 22      Corregidora
# 5️⃣ (Opcional) mapa rápido de verificación
library(leaflet)
leaflet(st_transform(mun_queretaro, 4326)) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addPolygons(
    color = "#444444", weight = 0.6,
    fillColor = "#0072B2", fillOpacity = 0.4,
    label = ~nomgeo,
    highlightOptions = highlightOptions(color = "black", weight = 1.2, bringToFront = TRUE)
  ) %>%
  addLegend(
    position = "bottomright",
    colors = "#0072B2",
    labels = "Municipios de Querétaro",
    title = "Estado de Querétaro"
  )
# ------------------------------------------------------------
# 🌐 Leaflet: mapa interactivo con mun_queretaro (usa nomgeo)
# ------------------------------------------------------------
library(dplyr)
library(sf)
library(leaflet)
library(scales)
## 
## Adjuntando el paquete: 'scales'
## The following object is masked from 'package:readr':
## 
##     col_factor
library(htmltools)

# 1) Asegurar CRS WGS84 y definir nombre del municipio
mun_map <- mun_queretaro %>%
  st_transform(4326) %>%
  mutate(
    nombre_mun = nomgeo,                 # 👈 usa nomgeo como nombre del municipio
    nombre_ent = "Querétaro"             # puedes cambiarlo si tienes una columna de entidad
  )

# 2) Paletas de color por indicador (pares 2010–2020)
rng_pair <- function(df, v10, v20) range(c(df[[v10]], df[[v20]]), na.rm = TRUE)
pal_bin  <- function(palette, dom) colorBin(palette, domain = dom, bins = 7, na.color = "#cccccc")

pal_tcma      <- pal_bin("YlOrRd", range(mun_map$tcma, na.rm = TRUE))
pal_envej     <- pal_bin("PuRd",   rng_pair(mun_map, "ind_envejec_10",  "ind_envejec_20"))
pal_juventud  <- pal_bin("Greens", rng_pair(mun_map, "ind_juventud_10", "ind_juventud_20"))
pal_depend    <- pal_bin("YlGnBu", rng_pair(mun_map, "ind_depend_10",   "ind_depend_20"))
pal_migr      <- pal_bin("BuPu",   rng_pair(mun_map, "atr_migr_10",     "atr_migr_20"))
pal_act       <- pal_bin("Oranges",rng_pair(mun_map, "tasa_act_10",     "tasa_act_20"))

lbl_base <- function(nmun, nent) {
  sprintf("<b>%s, %s</b>", nmun %||% "", nent %||% "") %>% lapply(HTML)
}

# 3) Construcción del mapa interactivo
leaflet(mun_map, options = leafletOptions(zoomControl = TRUE)) %>%
  addProviderTiles(providers$CartoDB.Positron, group = "Fondo claro") %>%
  addProviderTiles(providers$CartoDB.DarkMatter, group = "Fondo oscuro") %>%

  # --- TCMA ---
  addPolygons(
    fillColor = ~pal_tcma(tcma),
    color = "#4d4d4d", weight = 0.4, opacity = 1, fillOpacity = 0.85,
    group = "TCMA (2000–2020)",
    popup = ~sprintf("<b>%s</b><br/>TCMA: %s",
                     nombre_mun,
                     ifelse(is.finite(tcma), percent(tcma, 0.1), "s/d"))
  ) %>%
  addLegend(pal = pal_tcma, values = ~tcma, group = "TCMA (2000–2020)",
            title = "TCMA (2000–2020)", opacity = 0.85) %>%

  # --- Envejecimiento ---
  addPolygons(
    fillColor = ~pal_envej(ind_envejec_10), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Envejecimiento 2010",
    popup = ~sprintf("<b>%s</b><br/>Índice 2010: %s",
                     nombre_mun,
                     ifelse(is.finite(ind_envejec_10), paste0(round(ind_envejec_10,1),"%"), "s/d"))
  ) %>%
  addPolygons(
    fillColor = ~pal_envej(ind_envejec_20), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Envejecimiento 2020",
    popup = ~sprintf("<b>%s</b><br/>Índice 2020: %s",
                     nombre_mun,
                     ifelse(is.finite(ind_envejec_20), paste0(round(ind_envejec_20,1),"%"), "s/d"))
  ) %>%
  addLegend(pal = pal_envej, values = ~c(ind_envejec_10, ind_envejec_20),
            group = "Envejecimiento 2010", title = "Índice de envejecimiento (%)",
            opacity = 0.85) %>%

  # --- Juventud ---
  addPolygons(
    fillColor = ~pal_juventud(ind_juventud_10), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Juventud 2010",
    popup = ~sprintf("<b>%s</b><br/>Índice 2010: %s",
                     nombre_mun,
                     ifelse(is.finite(ind_juventud_10), paste0(round(ind_juventud_10,1),"%"), "s/d"))
  ) %>%
  addPolygons(
    fillColor = ~pal_juventud(ind_juventud_20), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Juventud 2020",
    popup = ~sprintf("<b>%s</b><br/>Índice 2020: %s",
                     nombre_mun,
                     ifelse(is.finite(ind_juventud_20), paste0(round(ind_juventud_20,1),"%"), "s/d"))
  ) %>%
  addLegend(pal = pal_juventud, values = ~c(ind_juventud_10, ind_juventud_20),
            group = "Juventud 2010", title = "Índice de juventud (%)",
            opacity = 0.85) %>%

  # --- Dependencia ---
  addPolygons(
    fillColor = ~pal_depend(ind_depend_10), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Dependencia 2010",
    popup = ~sprintf("<b>%s</b><br/>Dependencia 2010: %s",
                     nombre_mun,
                     ifelse(is.finite(ind_depend_10), paste0(round(ind_depend_10,1),"%"), "s/d"))
  ) %>%
  addPolygons(
    fillColor = ~pal_depend(ind_depend_20), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Dependencia 2020",
    popup = ~sprintf("<b>%s</b><br/>Dependencia 2020: %s",
                     nombre_mun,
                     ifelse(is.finite(ind_depend_20), paste0(round(ind_depend_20,1),"%"), "s/d"))
  ) %>%
  addLegend(pal = pal_depend, values = ~c(ind_depend_10, ind_depend_20),
            group = "Dependencia 2010", title = "Dependencia económica (%)",
            opacity = 0.85) %>%

  # --- Migración ---
  addPolygons(
    fillColor = ~pal_migr(atr_migr_10), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Migración 2010",
    popup = ~sprintf("<b>%s</b><br/>Migración 2010: %s",
                     nombre_mun,
                     ifelse(is.finite(atr_migr_10), paste0(round(atr_migr_10,1),"%"), "s/d"))
  ) %>%
  addPolygons(
    fillColor = ~pal_migr(atr_migr_20), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Migración 2020",
    popup = ~sprintf("<b>%s</b><br/>Migración 2020: %s",
                     nombre_mun,
                     ifelse(is.finite(atr_migr_20), paste0(round(atr_migr_20,1),"%"), "s/d"))
  ) %>%
  addLegend(pal = pal_migr, values = ~c(atr_migr_10, atr_migr_20),
            group = "Migración 2010", title = "Atracción migratoria (%)",
            opacity = 0.85) %>%

  # --- Actividad económica ---
  addPolygons(
    fillColor = ~pal_act(tasa_act_10), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Actividad 2010",
    popup = ~sprintf("<b>%s</b><br/>Actividad 2010: %s",
                     nombre_mun,
                     ifelse(is.finite(tasa_act_10), paste0(round(tasa_act_10,1),"%"), "s/d"))
  ) %>%
  addPolygons(
    fillColor = ~pal_act(tasa_act_20), color = "#4d4d4d", weight = 0.4,
    fillOpacity = 0.85, group = "Actividad 2020",
    popup = ~sprintf("<b>%s</b><br/>Actividad 2020: %s",
                     nombre_mun,
                     ifelse(is.finite(tasa_act_20), paste0(round(tasa_act_20,1),"%"), "s/d"))
  ) %>%
  addLegend(pal = pal_act, values = ~c(tasa_act_10, tasa_act_20),
            group = "Actividad 2010", title = "Tasa de actividad (%)",
            opacity = 0.85) %>%

  # --- Control de capas ---
  addLayersControl(
    baseGroups = c("Fondo claro", "Fondo oscuro"),
    overlayGroups = c("TCMA (2000–2020)",
                      "Envejecimiento 2010", "Envejecimiento 2020",
                      "Juventud 2010", "Juventud 2020",
                      "Dependencia 2010", "Dependencia 2020",
                      "Migración 2010", "Migración 2020",
                      "Actividad 2010", "Actividad 2020"),
    options = layersControlOptions(collapsed = FALSE)
  ) %>%
  hideGroup(c("Envejecimiento 2010","Envejecimiento 2020",
              "Juventud 2010","Juventud 2020",
              "Dependencia 2010","Dependencia 2020",
              "Migración 2010","Migración 2020",
              "Actividad 2010","Actividad 2020"))
library(dplyr)
library(sf)
library(DT)

# 1) Quitar geometría para la tabla
base_qro <- mun_queretaro %>% st_drop_geometry()

# 2) Columnas que queremos (si existen)
deseadas <- c(
  # Identificación
  "cve_ent","cve_mun","nomgeo",
  # Área y densidades
  "area_km2","densidad_10","densidad_20",
  # Población base
  "pob_total_10","pob_total_20","pob_12_mas_10","pob_12_mas_20",
  # Indicadores
  "tcma",
  "ind_envejec_10","ind_envejec_20",
  "ind_juventud_10","ind_juventud_20",
  "ind_depend_10","ind_depend_20",
  "atr_migr_10","atr_migr_20",
  "tasa_act_10","tasa_act_20"
)

# 3) Usar solo las que realmente existan
cols_presentes <- intersect(deseadas, names(base_qro))
tabla_qro <- base_qro %>% select(all_of(cols_presentes))

# 4) Tabla interactiva con botones de exportación
datatable(
  tabla_qro,
  rownames = FALSE,
  caption = "Querétaro — Municipios con población, densidad e indicadores (2010–2020)",
  options = list(
    pageLength = 10,
    scrollX = TRUE,
    autoWidth = TRUE,
    dom = 'Bfrtip',
    buttons = c('copy', 'csv', 'excel', 'print'),
    language = list(url = '//cdn.datatables.net/plug-ins/1.13.1/i18n/es-ES.json')
  ),
  extensions = 'Buttons',
  filter = "top"
)