ANALISIS PRELIMINAR: MIER Y NORIEGA

El siguiente trabajo buscara hacer un análisis preliminar sobre carencias y marginación en localidades del municipio Mier y Noriega del Estado de Nuevo León para poder tener una primera aproximación a los fenómenos presentes en la localidad, con tal de comprender la situación.

CARGAR PAQUETES Y BASE

Preparamos el entorno de trabajo, se cargan las bibliotecas necesarias para manipular datos, convertir variables a formato numérico y graficar. Luego se importa la base ITER_19CSV20.csv, que contiene indicadores por localidad.

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)
library(readr)
library(stringr)
library(ggplot2)

df <- read.csv("ITER_19CSV20.csv") 

HACER LIMPIEZA

En esta sección se construye el subconjunto de interés: se filtra el municipio 36 y se verifica rápidamente que el filtro se aplicó. Como se establece en el diccionario “*” son datos suprimidos por disccreción, así que se convertiran a NAs para evitar errores; lo restante se convierte a número para poder calcular sumas, promedios y porcentajes. Asimismo se eliminara LOC == 0 ya que corresponde al agregado municipal y no a una localidad específica, ya que el objetivo es comparar localidades reales entre sí.

df_36 <- df %>% 
  filter(MUN == 36)

unique(df_36$MUN)
## [1] 36
nrow(df_36)
## [1] 28
df_36 <- df_36 %>%
  mutate(across(
    c(P15YM_AN, P_15YMAS, GRAPROES, VPH_NODREN, VPH_AGUAFV, VPH_INTER),
    ~ parse_number(na_if(as.character(.), "*"))
  ))

df_36 <- df_36 %>%
  filter(LOC != 0)

VARIABLES

Este bloque calcula la población total del municipio (sumando POBTOT). No es un adorno: sirve como referencia general para dimensionar el análisis

pob_total_mun <- sum(df_36$POBTOT, na.rm = TRUE)
pob_total_mun
## [1] 7671

DATOS INSUFICIENTES

Aquí construiremos una tabla base por localidad (tabla_rezago_base) con tres piezas educativas mínimas: población de 15+ (P_15YMAS), analfabetismo 15+ (P15YM_AN) y escolaridad promedio (GRAPROES). Con eso se calcula el porcentaje de analfabetismo y se crea un diagnóstico (estado_edu) para clasificar cada localidad según si tiene información suficiente o no, con tal de que antes de comparar localidades, identifiquemos cuáles tienen denominadores inválidos o variables faltantes.

tabla_rezago_base <- df_36 %>%
  group_by(NOM_LOC) %>%
  summarise(
    p_15ymas     = sum(P_15YMAS, na.rm = TRUE),
    analf_15ymas = sum(P15YM_AN, na.rm = TRUE),
    graproes     = mean(GRAPROES, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(
    pct_analf = 100 * analf_15ymas / p_15ymas,
    estado_edu = case_when(
      is.na(p_15ymas) | p_15ymas <= 0 ~ "Sin población 15+",
      is.na(pct_analf) | !is.finite(pct_analf) ~ "Sin % analfabetismo",
      is.na(graproes) | !is.finite(graproes) ~ "Sin escolaridad",
      TRUE ~ "OK"
    )
  )

# Ver solo las problemáticas (las 6 deberían salir aquí)
tabla_rezago_base %>%
  filter(estado_edu != "OK") %>%
  select(NOM_LOC, p_15ymas, analf_15ymas, pct_analf, graproes, estado_edu) %>%
  arrange(NOM_LOC)
## # A tibble: 6 × 6
##   NOM_LOC                    p_15ymas analf_15ymas pct_analf graproes estado_edu
##   <chr>                         <dbl>        <dbl>     <dbl>    <dbl> <chr>     
## 1 Falfurrias (San Carlos)           0            0       NaN      NaN Sin pobla…
## 2 La Puerta de Guadalupe (L…        0            0       NaN      NaN Sin pobla…
## 3 La Tortuga                        0            0       NaN      NaN Sin pobla…
## 4 Los García                        0            0       NaN      NaN Sin pobla…
## 5 San Diego                         0            0       NaN      NaN Sin pobla…
## 6 Tanque Roto                       0            0       NaN      NaN Sin pobla…

Descubimos que estas 6 localidades no tienen datos suficientes, así que por motivos de simplicidad decidimos omitirlas.

REZAGO

Hemos construido un índice simple de rezago educativo por localidad usando solo dos señales básicas: analfabetismo (15+) y escolaridad promedio.

Primero se agregan los datos por localidad (sumas y promedios) y se calcula el porcentaje de analfabetismo. Después se filtran casos donde el cálculo no es válido (por ejemplo, cuando la población 15+ es cero o hay valores faltantes), para evitar divisiones sin sentido o indicadores artificiales.

La decisión metodológica central es priorizar simplicidad e interpretabilidad: en lugar de usar transformaciones menos intuitivas, se normaliza cada componente dentro del municipio con una escala 0–1, lo que me permite compararlos aunque estén en unidades distintas.

La escolaridad se invierte (esc_inv) para que ambos componentes apunten en la misma dirección: valores altos siempre significan peor condición. Finalmente, el índice se expresa como un promedio en escala 0–100, donde 0 representa la mejor situación relativa observada en el municipio y 100 la peor.

tabla_rezago <- df_36 %>%
  group_by(NOM_LOC) %>%
  summarise(
    p_15ymas     = sum(P_15YMAS, na.rm = TRUE),
    analf_15ymas = sum(P15YM_AN, na.rm = TRUE),
    graproes     = mean(GRAPROES, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(
    pct_analf = 100 * analf_15ymas / p_15ymas
  ) %>%
  filter(
    !is.na(p_15ymas), p_15ymas > 0,
    !is.na(pct_analf), is.finite(pct_analf),
    !is.na(graproes), is.finite(graproes)
  ) %>%
  mutate(
    # Normalización simple (0–1) dentro del municipio
    analf_norm = (pct_analf - min(pct_analf, na.rm = TRUE)) /
                 (max(pct_analf, na.rm = TRUE) - min(pct_analf, na.rm = TRUE)),

    esc_inv = max(graproes, na.rm = TRUE) - graproes,
    esc_norm = (esc_inv - min(esc_inv, na.rm = TRUE)) /
               (max(esc_inv, na.rm = TRUE) - min(esc_inv, na.rm = TRUE)),

    # Índice final simple (0–100): mayor = peor
    indice_rezago = 100 * (analf_norm + esc_norm) / 2
  ) %>%
  select(NOM_LOC, p_15ymas, pct_analf, graproes, indice_rezago) %>%
  arrange(desc(indice_rezago))

tabla_rezago
## # A tibble: 21 × 5
##    NOM_LOC                             p_15ymas pct_analf graproes indice_rezago
##    <chr>                                  <dbl>     <dbl>    <dbl>         <dbl>
##  1 La Cardona                               323     23.8      5.3           85.6
##  2 Localidades de dos viviendas              12     16.7      4.42          85.0
##  3 San Isidro                               294     22.4      5.69          76.3
##  4 La Presita de Cerros Blancos (La P…      352     20.5      5.83          69.8
##  5 El Gallito                               149     12.1      5.44          58.6
##  6 San José de Cuatro Caminos                66     13.6      5.98          53.0
##  7 Tapona Moreña                            350     14.6      6.27          50.2
##  8 San José de Medina (Rancho de Abaj…        8     12.5      6.13          48.2
##  9 San Elías                                 18     11.1      6.11          45.6
## 10 Lagunita de Taberna                      135      8.89     5.87          44.9
## # ℹ 11 more rows

A partir de aquí ya nos podemos dar una idea, pero gráficamente no es muy sugerente, por lo mismo sería buena idea hacer gráficas que nos ilustren estas carencias de mejor manera

ANALFABETISMO

tabla_rezago %>%
  filter(!is.na(pct_analf), is.finite(pct_analf), p_15ymas > 0) %>%
  ggplot(aes(x = fct_reorder(NOM_LOC, pct_analf, .desc = TRUE),
             y = pct_analf,
             fill = pct_analf)) +
  geom_col() +
  coord_flip() +
  scale_fill_gradient(low = "#FDE0E0", high = "#B30000") +
  labs(
    title = "Analfabetismo (15+) por localidad",
    x = "Localidad",
    y = "% analfabetismo (15+)",
    fill = "% analf."
  ) +
  theme(axis.text.y = element_text(size = 9))

Hay un bloque claramente más rezagado: La Cardona aparece como el valor más alto (cerca de 24%), seguida por San Isidro (alrededor de 22%) y La Presita de Cerros Blancos (La Presita) (aprox. 20%). Del otro lado en el extremo opuesto, las localidades de una vivienda y La Joya del Zacate están muy abajo (cerca de 0–3%). En otras palabras podemos decir el rezago no está “uniformemente repartido”; está concentrado. Un análisis geográfico cualitativo sería interesante para saber si el nivel de rezago se puede asimilar a la geografía.

ESCOLARIDAD

tabla_rezago %>%
  filter(!is.na(graproes), is.finite(graproes)) %>%
  ggplot(aes(x = fct_reorder(NOM_LOC, graproes, .desc = FALSE),
             y = graproes,
             fill = graproes)) +
  geom_col() +
  coord_flip() +
  scale_fill_gradient(low = "#B30000", high = "#FDE0E0") +
  labs(
    title = "Escolaridad promedio (GRAPROES) por localidad",
    x = "Localidad",
    y = "Años promedio de escolaridad",
    fill = "Escolaridad"
  ) +
  theme(axis.text.y = element_text(size = 9))

Sorprendentemente las localidades con mayor escolaridad promedio son San Rafael de los Martínez y Dolores (con aproximadamente 7.1–7.3 años), seguidas por Mier y Noriega con unos 7 años el cuál esperarías brillará en este rubro por ser la cabecera.

En el extremo inferior, las localidades de dos viviendas caen alrededor de 4.5 años, muy por debajo del resto, y luego aparecen Localidades de una vivienda y La Cardona en la zona baja (aprox. 5.5–5.7 años).

tabla_rezago %>%
  filter(!is.na(indice_rezago), is.finite(indice_rezago)) %>%
  ggplot(aes(
    x = fct_reorder(NOM_LOC, indice_rezago, .desc = TRUE),
    y = indice_rezago,
    fill = indice_rezago
  )) +
  geom_col() +
  coord_flip() +
  scale_fill_gradient(low = "#FDE0E0", high = "#B30000") +
  labs(
    title = "Índice de rezago educativo por localidad",
    x = "Localidad",
    y = "Índice de rezago (adimensional)",
    fill = "Rezago"
  ) +
  theme(axis.text.y = element_text(size = 9))

El índice empuja arriba a las localidades donde coinciden ambas cosas: analfabetismo relativamente alto y escolaridad relativamente baja. Por eso aparecen en la parte más alta La Cardona y localidades de dos viviendas, seguidas por San Isidro y La Presita. En la parte baja del índice (mejor situación relativa) quedan Dolores y San Rafael de los Martínez (alrededor de 15–20). Es decir: el índice no contradice a las dos gráficas anteriores; las sintetiza. Nuestra localidad, Cerros Blancos, no parece estar en una situación comparativamente tan precaria como otras localidades.

VIVIENDA Y SERVICIOS

INDICE DE CARENCIAS

Este bloque estima un índice de carencias en vivienda por localidad dentro del municipio 36. Primero filtramos las observaciones relevantes y limpiamos las variables de vivienda y servicios, reemplazando marcas como “*” por valores faltantes y convirtiendo todo a numérico para evitar errores de cálculo.

Después, se agregan los datos por localidad: Obtenemos el total de viviendas habitadas y los conteos asociados a disponibilidad de agua e internet, así como el conteo de viviendas sin drenaje y de estos conteos derivamos tres proporciones clave:

  1. % sin agua entubada
  2. % sin drenaje
  3. % sin internet

Finalmente decidí operar a través de un índice sintético (0–100) calculado como el promedio de los tres porcentajes, con el objetivo de obtener una medida simple y comparable de tal suerte valores más altos indican mayor carencia.En lugar de ponderaciones o modelos, se usa una combinación transparente de tres componentes directamente interpretables. El índice no pretende capturar todas las condiciones de vivienda, sino ofrecer un resumen consistente para ordenar localidades y ubicar focos de rezago.

carencias_loc <- df %>%
  filter(MUN == 36, LOC != 0) %>%
  mutate(across(
    c(TVIVHAB, VPH_AGUADV, VPH_NODREN, VPH_INTER),
    ~ {
      x <- str_trim(as.character(.))
      x <- na_if(x, "*")
      x <- na_if(x, "")
      parse_double(x)
    }
  )) %>%
  group_by(LOC, NOM_LOC) %>%
  summarise(
    viv_hab   = sum(TVIVHAB,    na.rm = TRUE),
    con_agua  = sum(VPH_AGUADV, na.rm = TRUE),
    no_dren   = sum(VPH_NODREN, na.rm = TRUE),
    con_inter = sum(VPH_INTER,  na.rm = TRUE),
    .groups = "drop"
  ) %>%
  filter(!is.na(viv_hab), viv_hab > 0) %>%
  mutate(
    no_agua  = pmin(pmax(viv_hab - con_agua,  0), viv_hab),
    no_inter = pmin(pmax(viv_hab - con_inter, 0), viv_hab),

    pct_no_agua  = 100 * no_agua  / viv_hab,
    pct_no_dren  = 100 * no_dren  / viv_hab,
    pct_no_inter = 100 * no_inter / viv_hab,

    indice_carencia = (pct_no_agua + pct_no_dren + pct_no_inter) / 3
  ) %>%
  arrange(desc(indice_carencia))

carencias_loc
## # A tibble: 27 × 12
##      LOC NOM_LOC viv_hab con_agua no_dren con_inter no_agua no_inter pct_no_agua
##    <int> <chr>     <dbl>    <dbl>   <dbl>     <dbl>   <dbl>    <dbl>       <dbl>
##  1    12 Las Me…      22        0      22         0      22       22      100   
##  2    22 San Jo…       3        2       3         0       1        3       33.3 
##  3  9999 Locali…       6        2       4         0       4        6       66.7 
##  4    10 Laguni…      43       34      43         0       9       43       20.9 
##  5    15 La Pre…     129       92     112         1      37      128       28.7 
##  6    19 San El…       7        1       2         0       6        7       85.7 
##  7    25 Tapona…     118       57      65         0      61      118       51.7 
##  8    20 San Is…     102       25      34         4      77       98       75.5 
##  9     9 La Joy…      12        0       1         1      12       11      100   
## 10    17 El Ref…     129      120     123         3       9      126        6.98
## # ℹ 17 more rows
## # ℹ 3 more variables: pct_no_dren <dbl>, pct_no_inter <dbl>,
## #   indice_carencia <dbl>
carencias_loc %>%
  filter(is.finite(indice_carencia)) %>%
  ggplot(aes(
    x = fct_reorder(NOM_LOC, indice_carencia, .desc = TRUE),
    y = indice_carencia,
    fill = indice_carencia
  )) +
  geom_col() +
  coord_flip() +
  scale_fill_gradient(low = "#FDE0E0", high = "#B30000") +
  scale_y_continuous(
    limits = c(0, NA),
    breaks = c(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100),
    labels = function(x) paste0(x, "%")
  ) +
  labs(
    title = "Índice de carencias por localidad (0–100)",
    subtitle = "Indice sintético (0–100) construido a partir de tres carencias en vivienda",
    x = "Localidad",
    y = "Carencia promedio (%)",
    fill = "Carencia"
  ) +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 9))

CABECERA

Este bloque prepara el terreno para una comparación directa entre cabecera municipal y resto de localidades. Construimos loc_ind para crear una tabla por localidad que resume:

Si existe una localidad con LOC == 1, se asume que esa es la cabecera (convención frecuente en tabulados administrativos), de lo contrario tomamos como cabecera la localidad con mayor población (pob_tot).

Finalmente agrupamos en 2 grupos: “Cabecera Municipal” y “Resto”. A partir de aquí podemos comparar dos grupos.

df_36 <- df %>%
  filter(MUN == 36, LOC != 0) %>%
  mutate(across(
    c(POBTOT, P_15YMAS, P15YM_AN, GRAPROES, TVIVHAB, VPH_AGUADV, VPH_NODREN, VPH_INTER),
    ~ {
      x <- str_trim(as.character(.))
      x <- na_if(x, "*")
      x <- na_if(x, "")
      parse_double(x)
    }
  ))

loc_ind <- df_36 %>%
  group_by(LOC, NOM_LOC) %>%
  summarise(
    pob_tot   = sum(POBTOT,   na.rm = TRUE),
    p_15ymas  = sum(P_15YMAS, na.rm = TRUE),

    analf_15ymas = sum(P15YM_AN, na.rm = TRUE),
    graproes     = mean(GRAPROES, na.rm = TRUE),

    viv_hab   = sum(TVIVHAB,   na.rm = TRUE),
    con_agua  = sum(VPH_AGUADV, na.rm = TRUE),
    no_dren   = sum(VPH_NODREN, na.rm = TRUE),
    con_inter = sum(VPH_INTER,  na.rm = TRUE),

    .groups = "drop"
  ) %>%
  filter(!is.na(viv_hab), viv_hab > 0) %>%
  mutate(
    pct_analf = 100 * analf_15ymas / p_15ymas,

    no_agua  = pmin(pmax(viv_hab - con_agua,  0), viv_hab),
    no_inter = pmin(pmax(viv_hab - con_inter, 0), viv_hab),

    pct_no_agua  = 100 * no_agua  / viv_hab,
    pct_no_dren  = 100 * no_dren  / viv_hab,
    pct_no_inter = 100 * no_inter / viv_hab,

    indice_carencia = pct_no_agua + pct_no_dren + pct_no_inter
  ) %>%
  select(LOC, NOM_LOC, pob_tot, p_15ymas, pct_analf, graproes,
         viv_hab, pct_no_agua, pct_no_dren, pct_no_inter, indice_carencia)

cab_loc <- if (any(loc_ind$LOC == 1, na.rm = TRUE)) 1 else loc_ind$LOC[which.max(loc_ind$pob_tot)]

loc_ind <- loc_ind %>%
  mutate(tipo_localidad = if_else(LOC == cab_loc, "Cabecera Municipal", "Resto"))

RESUMEN SIMPLE

Agrupamos las localidades por tipo de localidad (cabecera vs resto) y calculamos el promedio de los indicadores principales:

  1. % de analfabetismo (media)
  2. escolaridad promedio (media)
  3. índice de carencia (media)

Además reportamos cuántas localidades hay en cada grupo y cuánta población acumulan.

El resultado (comp) funciona como una lectura rápida de brechas: si la cabecera sale sistemáticamente mejor en educación y servicios, podemos comprender de manera bastante directa que tan grande es la brecha entre la cabecera y el resto.

comp <- loc_ind %>%
  group_by(tipo_localidad) %>%
  summarise(
    n_loc = n(),
    pob_tot = sum(pob_tot, na.rm=TRUE),
    pct_analf_mean = mean(pct_analf, na.rm=TRUE),
    graproes_mean = mean(graproes, na.rm=TRUE),
    carencia_mean = mean(indice_carencia, na.rm=TRUE),
    .groups="drop"
  )

comp
## # A tibble: 2 × 6
##   tipo_localidad     n_loc pob_tot pct_analf_mean graproes_mean carencia_mean
##   <chr>              <int>   <dbl>          <dbl>         <dbl>         <dbl>
## 1 Cabecera Municipal     1    1180           9.88          7.27          81.8
## 2 Resto                 26    6491          11.1           6.16         195.

COMPARACIÓN DE MEDIAS

# Indicadores por localidad (para TODOS los municipios)
loc_all <- df_36 %>%
  group_by(MUN, LOC, NOM_LOC) %>%
  summarise(
    pob_tot   = sum(POBTOT,   na.rm = TRUE),
    p_15ymas  = sum(P_15YMAS, na.rm = TRUE),
    analf_15ymas = sum(P15YM_AN, na.rm = TRUE),
    graproes     = mean(GRAPROES, na.rm = TRUE),

    viv_hab   = sum(TVIVHAB,   na.rm = TRUE),
    con_agua  = sum(VPH_AGUADV, na.rm = TRUE),
    no_dren   = sum(VPH_NODREN, na.rm = TRUE),
    con_inter = sum(VPH_INTER,  na.rm = TRUE),
    .groups = "drop"
  ) %>%
  filter(!is.na(viv_hab), viv_hab > 0) %>%
  mutate(
    pct_analf = 100 * analf_15ymas / p_15ymas,

    no_agua  = pmin(pmax(viv_hab - con_agua,  0), viv_hab),
    no_inter = pmin(pmax(viv_hab - con_inter, 0), viv_hab),

    pct_no_agua  = 100 * no_agua  / viv_hab,
    pct_no_dren  = 100 * no_dren  / viv_hab,
    pct_no_inter = 100 * no_inter / viv_hab,

    # índice 0–100 como promedio, más interpretable
    indice_carencia = (pct_no_agua + pct_no_dren + pct_no_inter) / 3
  ) %>%
  # Identificar cabecera por municipio: LOC==1 si existe; si no, la de mayor población
  group_by(MUN) %>%
  mutate(
    cab_loc = if (any(LOC == 1, na.rm = TRUE)) 1 else LOC[which.max(pob_tot)],
    tipo_localidad = if_else(LOC == cab_loc, "Cabecera Municipal", "Resto")
  ) %>%
  ungroup()

# Comparación de medias por municipio (Cabecera vs Resto)
mun_comp <- loc_all %>%
  filter(is.finite(pct_analf), is.finite(graproes), is.finite(indice_carencia)) %>%
  group_by(MUN, tipo_localidad) %>%
  summarise(
    pct_analf = mean(pct_analf, na.rm = TRUE),
    graproes  = mean(graproes,  na.rm = TRUE),
    carencia  = mean(indice_carencia, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  pivot_longer(cols = c(pct_analf, graproes, carencia),
               names_to = "indicador", values_to = "media") %>%
  mutate(
    indicador = recode(indicador,
      pct_analf = "Analfabetismo (15+), %",
      graproes  = "Escolaridad promedio (años)",
      carencia  = "Carencia promedio (0–100)"
    )
  ) %>%
  pivot_wider(names_from = tipo_localidad, values_from = media) %>%
  drop_na(`Cabecera Municipal`, Resto)
cab_name <- loc_ind %>%
  filter(tipo_localidad == "Cabecera Municipal") %>%
  slice(1) %>%
  pull(NOM_LOC)

cab_val_analf <- loc_ind %>%
  filter(tipo_localidad == "Cabecera Municipal") %>%
  slice(1) %>%
  pull(pct_analf)

loc_ind %>%
  filter(is.finite(pct_analf)) %>%
  ggplot(aes(x = pct_analf, y = reorder(NOM_LOC, pct_analf), shape = tipo_localidad)) +
  geom_vline(xintercept = cab_val_analf, linetype = 2, linewidth = 0.7) +
  geom_point(aes(color = tipo_localidad), size = 2.6) +
  labs(
    title = "Analfabetismo (15+) por localidad",
    subtitle = paste0("Línea punteada = Cabecera Municipal (", cab_name, ")"),
    x = "% analfabetismo (15+)",
    y = "Localidad",
    color = NULL,
    shape = NULL
  ) +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 9))

La lectura es interesante, descubrimos una suerte de “abanico” de puntos nos indica que el problema de analfabetismo esta mas bien distribuido de manera mas o menos regular entre el municipio, Mier y Noriega no destaca en particular sobre el resto en este aspecto.

cab_val_esc <- loc_ind %>%
  filter(tipo_localidad == "Cabecera Municipal") %>%
  slice(1) %>%
  pull(graproes)

loc_ind %>%
  filter(is.finite(graproes)) %>%
  ggplot(aes(x = graproes, y = reorder(NOM_LOC, graproes), shape = tipo_localidad)) +
  geom_vline(xintercept = cab_val_esc, linetype = 2, linewidth = 0.7) +
  geom_point(aes(color = tipo_localidad), size = 2.6) +
  labs(
    title = "Escolaridad promedio (GRAPROES) por localidad",
    subtitle = paste0("Línea punteada = Cabecera Municipal (", cab_name, ")"),
    x = "Años promedio de escolaridad",
    y = "Localidad",
    color = NULL,
    shape = NULL
  ) +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 9))

Aquí el resultado es mas esperable, Mier y Noriega presenta niveles mucho mayores de escolaridad en su condición de cabecera con otros dos municipios estableciendose ligeramente por encima del mismo. Pero en general, en el municipio existe un nivel de rezago comparativo muy grande respecto al resto.

cab_val_car <- loc_ind %>%
  mutate(carencia_0_100 = indice_carencia / 3) %>%
  filter(tipo_localidad == "Cabecera Municipal") %>%
  slice(1) %>%
  pull(carencia_0_100)

loc_ind %>%
  mutate(carencia_0_100 = indice_carencia / 3) %>%
  filter(is.finite(carencia_0_100)) %>%
  ggplot(aes(
    x = carencia_0_100,
    y = reorder(NOM_LOC, carencia_0_100),
    shape = tipo_localidad
  )) +
  geom_vline(xintercept = cab_val_car, linetype = 2, linewidth = 0.7) +
  geom_point(aes(color = tipo_localidad), size = 2.6) +
  scale_x_continuous(
    limits = c(0, NA),                 
    breaks = c(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100), 
    labels = function(x) paste0(x, "%")
  ) +
  labs(
    title = "Carencia promedio (0–100) por localidad",
    subtitle = paste0("Línea punteada = Cabecera Municipal (", cab_name, ")"),
    x = "Carencia promedio (%)",
    y = "Localidad",
    color = NULL,
    shape = NULL
  ) +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 9))

Aquí se puede apreciar perfectamente el nivel de rezago frente al resto de localidades: Mier y Noriega presenta el menor nivel de carencia respecto al resto de comunidades, lo que efectivamente destaca su posición de cabecera. Podemos concluir que si existe una suerte de diferenciación marcada.

CONCLUSIÓN

En el municipio de Mier y Noriega se observa una desigualdad territorial interna: la cabecera funciona como punto de referencia y, frente a ella, varias localidades muestran rezagos más marcados en analfabetismo, escolaridad y carencias de vivienda. Podemos preliminarmente hablar de una concentración del rezago en un subconjunto de localidades, lo que es útil para priorizar intervención y focalizar recursos, aunque requeririamos un análisis geográfico mas profundo para poder llegar a conclusiones mas elaboradas.