Introducción

Las personas usuarias de información estadística territorial frecuentemente se enfrentan al problema de disponer de datos confiables y actualizados, en formatos apropiados para una diversidad de aplicaciones y análisis. En México, el INEGI es la institución que se encarga de recolectar, sistematizar y difundir información de todos los sectores. A pesar de que la disponibilidad y calidad de información ha aumentado considerablemente en las últimas dos décadas, es evidente que resulta imposible satisfacer todas las necesidades particulares con productos terminados y listos para utilizarse.

Un ejemplo de esto pueden ser los indicadores básicos del territorio, desagregados no por municipios ni localidades, sino por ciudades, conurbaciones, o áreas metropolitanas. La jerarquía territorial que estructura la información del INEGI, no necesariamente tiene una relación directa con la organización metropolitana y las conurbaciones que definen el Sistema Urbano Nacional (SUN).En este documento se realiza una búsqueda, limpieza y análisis de información para conformar una base de datos a nivel ciudad para la se presentan de manera inicial las variable de población y extensión territorial.

Este trabajo se realiza partiendo del producto “Principales resultados por localidad (ITER) del Censo de Población y Vivienda 2020” que como su nombre lo indica contiene los resultados para las variables censales hasta el nivel de localidades. Para calcular la superficie territorial que ocupa cada localidad se ha recurrido a los achivos tipo shapefiles (.shp) que comprenden el Marco Geoestadístico Nacional, mismos que fueron procesados utlizando un software de sistemas de información geográfica (QGIS 3.16).

En el presente documento se expone el procesamiento y tratamiento de los datos. Y se presentan algunas gráficas generales que nos permiten tener una perspectiva general de los indicadores básicos analizados. Finalente se genera una tabla que contiene los datos de población y extensión territorial para las ciudades del SUN para su utilización como insumo en otros análisis.

Análisis

Librerías y preparación de directorios de trabajo

Se requiere la instalación de los paquetes dplyr, readr, foreign y ggplot2. Se creará una carpeta y subcarpeta dentro del directorio de “Mis Documentos” del usuario.

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(readr)
library(foreign)
library(ggplot2)

setwd("~/")
if (!dir.exists("R_Data")) {
      dir.create("R_Data")
}
setwd("~/R_Data")
if (!dir.exists("ciudades")) {
      dir.create("ciudades")
}
setwd("ciudades")

Descarga de información

En este paso se descargarán los arhivos necesarios para realizar el análisis. Se descargarán los principales resultados por localidad (ITER) del Censo INEGI 2020, la base de datos conteniendo la superficie en hectáreas de las localidades de acuerdo al Marco Geoestadístico Nacional 2020 de INEGI, y el listado de ciudades del Sistema Urbano Nacoional (SUN 2018) que contiene las conirbaciones y áreas o zonas metropolitanas del país.

# INEGI - ITER 2020
url_iter00 <- "https://www.inegi.org.mx/contenidos/programas/ccpv/2020/datosabiertos/iter/iter_00_cpv2020_csv.zip"
iter00 <- "iter_00_cpv2020_csv.zip"
if (!file.exists(iter00)) {
      download.file(url_iter00, iter00, mode = "wb")
}
if (!dir.exists("iter_00_cpv2020")) {
      unzip(iter00)
}
# Urban surface by Locality
url_loc_areas <- "https://github.com/santanaluis/inegidata/raw/main/00l_areascalc.dbf"
loc_areas <- "00l_areascalc.dbf"
if (!file.exists(loc_areas)) {
      download.file(url_loc_areas, loc_areas, mode = "wb")
}
#Metropolitan Areas List
url_zmetro <- "http://www.conapo.gob.mx/work/models/CONAPO/Marginacion/Datos_Abiertos/SUN/Base_SUN_2018.csv"
if (!file.exists("Base_SUN_2018.csv")) {
      download.file(url_zmetro, "Base_SUN_2018.csv")
}
base_sun_2018 <- read.csv("Base_SUN_2018.csv", as.is = T)

Lectura y exploración preliminar de datos

Se leen los tres data-frames y se exploran sus encabezados para dar una idea de su estructura.

iter_2020 <- read_csv("conjunto_de_datos/conjunto_de_datos_iter_00CSV20.csv", na = "*")
## Warning: One or more parsing issues, see `problems()` for details
## Rows: 195662 Columns: 232
## -- Column specification --------------------------------------------------------
## Delimiter: ","
## chr   (9): ENTIDAD, NOM_ENT, MUN, NOM_MUN, LOC, NOM_LOC, LONGITUD, LATITUD, ...
## dbl (223): POBTOT, POBFEM, POBMAS, P_0A2, P_0A2_F, P_0A2_M, P_3YMAS, P_3YMAS...
## 
## i Use `spec()` to retrieve the full column specification for this data.
## i Specify the column types or set `show_col_types = FALSE` to quiet this message.
loc_areas <- read.dbf(loc_areas, as.is = FALSE)
base_sun_2018 <- read.csv("Base_SUN_2018.csv", as.is = T)
head(iter_2020)
## # A tibble: 6 x 232
##   ENTIDAD NOM_ENT  MUN   NOM_MUN  LOC   NOM_LOC  LONGITUD LATITUD ALTITUD POBTOT
##   <chr>   <chr>    <chr> <chr>    <chr> <chr>    <chr>    <chr>   <chr>    <dbl>
## 1 00      Total n~ 000   Total n~ 0000  Total n~ ""       ""      ""      1.26e8
## 2 00      Total n~ 000   Total n~ 9998  Localid~ ""       ""      ""      2.50e5
## 3 00      Total n~ 000   Total n~ 9999  Localid~ ""       ""      ""      1.47e5
## 4 01      Aguasca~ 000   Total d~ 0000  Total d~ ""       ""      ""      1.43e6
## 5 01      Aguasca~ 000   Total d~ 9998  Localid~ ""       ""      ""      3.70e3
## 6 01      Aguasca~ 000   Total d~ 9999  Localid~ ""       ""      ""      3.02e3
## # ... with 222 more variables: POBFEM <dbl>, POBMAS <dbl>, P_0A2 <dbl>,
## #   P_0A2_F <dbl>, P_0A2_M <dbl>, P_3YMAS <dbl>, P_3YMAS_F <dbl>,
## #   P_3YMAS_M <dbl>, P_5YMAS <dbl>, P_5YMAS_F <dbl>, P_5YMAS_M <dbl>,
## #   P_12YMAS <dbl>, P_12YMAS_F <dbl>, P_12YMAS_M <dbl>, P_15YMAS <dbl>,
## #   P_15YMAS_F <dbl>, P_15YMAS_M <dbl>, P_18YMAS <dbl>, P_18YMAS_F <dbl>,
## #   P_18YMAS_M <dbl>, P_3A5 <dbl>, P_3A5_F <dbl>, P_3A5_M <dbl>, P_6A11 <dbl>,
## #   P_6A11_F <dbl>, P_6A11_M <dbl>, P_8A14 <dbl>, P_8A14_F <dbl>, ...
head(loc_areas)
##      CVEGEO CVE_ENT CVE_MUN CVE_LOC                                 NOMGEO
## 1 010060024      01     006    0024                    Ojo Zarco [Colonia]
## 2 010060045      01     006    0045                               Santiago
## 3 010060233      01     006    0233 San Carlos [Fraccionamiento Campestre]
## 4 010060258      01     006    0258                               El Canal
## 5 010060287      01     006    0287                             Las Flores
## 6 010060302      01     006    0302         Santa Isabel [Fraccionamiento]
##   AMBITO  SUP_HAS
## 1  Rural  18.9909
## 2  Rural  26.3988
## 3  Rural 124.8151
## 4  Rural   6.2208
## 5  Rural   2.3346
## 6  Rural   7.7799
head(base_sun_2018)
##   CVE_ENT         NOM_ENT CVE_MUN                   NOM_MUN CVE_LOC NOM_LOC
## 1       1  Aguascalientes    1011 San Francisco de los Romo      NA        
## 2       1  Aguascalientes    1005               Jesús María      NA        
## 3       1  Aguascalientes    1001            Aguascalientes      NA        
## 4       2 Baja California    2005        Playas de Rosarito      NA        
## 5       2 Baja California    2003                    Tecate      NA        
## 6       2 Baja California    2004                   Tijuana      NA        
##   CVE_SUN        NOM_SUN POB_2018
## 1  M01.01 Aguascalientes    42531
## 2  M01.01 Aguascalientes   116700
## 3  M01.01 Aguascalientes   897331
## 4  M02.03        Tijuana   110683
## 5  M02.03        Tijuana   115570
## 6  M02.03        Tijuana  1798741

Limpieza y procesamiento de datos

Datos censales a nivel localidad urbana.

Esta base de datos contiene aproximadamente 193 mil registros. En esta se mezclan observaciones de diferentes escalas (nacional, estatal, municipal y a nivel localidad). La tabla original descargada de INEGI requiere ser procesada para separarla en data sets utiles para el análisis estadístico.

## Separar filas que expresan totales por nacional, estatal o municipal.
iter_2020_ent <- filter(iter_2020, startsWith(iter_2020$NOM_MUN, "Total de la entidad"))
iter_2020_nal <- filter(iter_2020, iter_2020$NOM_MUN == "Total nacional")
iter_2020_mun <- filter(iter_2020, iter_2020$NOM_LOC == "Total del Municipio")
## Crar un segundo dataframe de localidades omitiendo filas de totales y 
## subtotales para lograr tener siempre solo una observación por cada fila
iter_2020_loc <- filter(iter_2020, !startsWith(iter_2020$NOM_MUN, "Total"))
iter_2020_loc <- filter(iter_2020_loc, !startsWith(iter_2020_loc$NOM_LOC, "Total"))
## Crear campo de clave geografica
iter_2020_loc <- mutate(iter_2020_loc, CVEGEOL = paste(ENTIDAD, MUN, LOC, sep = ""))
## Crear campo de clave entidad+municipio
iter_2020_loc <- mutate(iter_2020_loc, CVEEMUN = paste(ENTIDAD, MUN, sep = ""))
head(iter_2020_loc)
## # A tibble: 6 x 234
##   ENTIDAD NOM_ENT  MUN   NOM_MUN  LOC   NOM_LOC  LONGITUD LATITUD ALTITUD POBTOT
##   <chr>   <chr>    <chr> <chr>    <chr> <chr>    <chr>    <chr>   <chr>    <dbl>
## 1 01      Aguasca~ 001   Aguasca~ 0001  Aguasca~ "102°17~ "21°52~ 1878    863893
## 2 01      Aguasca~ 001   Aguasca~ 0094  Granja ~ "102°22~ "21°52~ 1902         5
## 3 01      Aguasca~ 001   Aguasca~ 0096  Agua Az~ "102°21~ "21°53~ 1861        41
## 4 01      Aguasca~ 001   Aguasca~ 0102  Los Arb~ "102°21~ "21°46~ 1861         8
## 5 01      Aguasca~ 001   Aguasca~ 0104  Ardilla~ "102°11~ "21°56~ 1989         1
## 6 01      Aguasca~ 001   Aguasca~ 0106  Arellano "102°16~ "21°48~ 1892      1169
## # ... with 224 more variables: POBFEM <dbl>, POBMAS <dbl>, P_0A2 <dbl>,
## #   P_0A2_F <dbl>, P_0A2_M <dbl>, P_3YMAS <dbl>, P_3YMAS_F <dbl>,
## #   P_3YMAS_M <dbl>, P_5YMAS <dbl>, P_5YMAS_F <dbl>, P_5YMAS_M <dbl>,
## #   P_12YMAS <dbl>, P_12YMAS_F <dbl>, P_12YMAS_M <dbl>, P_15YMAS <dbl>,
## #   P_15YMAS_F <dbl>, P_15YMAS_M <dbl>, P_18YMAS <dbl>, P_18YMAS_F <dbl>,
## #   P_18YMAS_M <dbl>, P_3A5 <dbl>, P_3A5_F <dbl>, P_3A5_M <dbl>, P_6A11 <dbl>,
## #   P_6A11_F <dbl>, P_6A11_M <dbl>, P_8A14 <dbl>, P_8A14_F <dbl>, ...

Datos de superficie urbanizada a nivel de localidades

Este paso se efectua la unión datos calculados de superficie con el data set de localidades del MGN. Adicionalmente creamos un nuevo dataframe con un listado corto de variables.

loc_datau <- inner_join(iter_2020_loc, loc_areas, by = c("CVEGEOL" = "CVEGEO"))
## Subset incluyendo población y grupos de edad y calculo densidad
loc_subs1 <- select(loc_datau, c(1:57, 231:240))
loc_poblysup  <- select(loc_subs1, c(1:10, 58:61, 66, 67))
loc_poblysup <- mutate(loc_poblysup, DEN_LOC = loc_poblysup$POBTOT/loc_poblysup$SUP_HAS)
loc_poblysup <- mutate(loc_poblysup, CVE_MUN = CVEEMUN)
loc_poblysup <- select(loc_poblysup, !CVEEMUN)

Algo que podemos observar, es que al unir la tabla de localidades con superficies procedente del MGN, con la de las localidades del ITER, se pierden una gran cantidad de registros, pasando de 193 mil a poco menos de 50 mil en el dataframe unido. Podemos verificar las implicaciones de esto a nivel de volumen de población que representa:

paste("Población total en base ITER 2020:", sum(iter_2020_loc$POBTOT))
## [1] "Población total en base ITER 2020: 126411503"
paste("Población total Dataframe unido:", sum(loc_subs1$POBTOT))
## [1] "Población total Dataframe unido: 121716575"
loc.lostdata <- 100*(1-(sum(loc_subs1$POBTOT)/sum(iter_2020_loc$POBTOT)))
paste("Perdida en volúmen de población:", round(loc.lostdata, 2) , "%")
## [1] "Perdida en volúmen de población: 3.71 %"

La pérdida de este volumen de población al unir las tablas puede deberse a que no todas las localidades reportadas en los resultados del ITER están registradas en el MGN. Aunque esto podría no tener un impacto significativo en el análisis, es importante no perderlo de vista, ya que puede implicar la invisibilización de las localidades más marginadas en posteriores análisis.

Agrupación de acuerdo con los datos del Sistema Urbano Nacional (SUN)

En este apartado vamos a integrar la información de población y superficie de las Localidades del MGN a partir de la estructura del SUN. El primer paso consiste en la agrupación de los datos por municipio en el que se encuentran las localidades, y posterioremente por conurbación o zona metropolitana al que pertenece el municipio.

# Corregir clases de variables para poder indexar
base_sun_2018$CVE_MUN <- as.character(base_sun_2018$CVE_MUN)
sun_2018_clave <- base_sun_2018[, c(3,7,8)]
# length(unique(sun_2018_clave$CVE_SUN))
# Agrupar localidades por municipios
loc_poblysup <- group_by(loc_poblysup, CVE_MUN)
mun.supurb.pob <- summarise(loc_poblysup, POB_TOT = sum(POBTOT), SUP_TOT = sum(SUP_HAS))
mun.supurb.pob$CVE_MUN <- as.numeric(mun.supurb.pob$CVE_MUN)
mun.supurb.pob$CVE_MUN <- as.character(mun.supurb.pob$CVE_MUN)
df.ciudades <- inner_join(sun_2018_clave, mun.supurb.pob)
## Joining, by = "CVE_MUN"
# Aagrupar municipios por ciudades
df.ciudades <- group_by(df.ciudades, CVE_SUN, NOM_SUN)
df.ciudades.list <- summarise(df.ciudades, PTOT_CD = sum(POB_TOT), SUPT_CD = sum(SUP_TOT))
## `summarise()` has grouped output by 'CVE_SUN'. You can override using the `.groups` argument.
df.ciudades.list <- mutate(df.ciudades.list, DENS_HAS = PTOT_CD/SUPT_CD) #Crea campo de densidad

Como resultado obtenemos un data frame de 401 registros que contiene las ciudades del SUN, con los datos calculados de población y extensión territorial. A continuación se presentan los primeros y últimos 10 registros del data frame.

head(df.ciudades.list, 10)
## # A tibble: 10 x 5
## # Groups:   CVE_SUN [10]
##    CVE_SUN NOM_SUN                    PTOT_CD SUPT_CD DENS_HAS
##    <chr>   <chr>                        <dbl>   <dbl>    <dbl>
##  1 C01.01  Rincón de Romos             163368   3239.     50.4
##  2 C05.01  Nueva Rosita-Cloete         106626   5410.     19.7
##  3 C06.01  Manzanillo                  379284  12459.     30.4
##  4 C07.01  Cacahoatán                   85260   8182.     10.4
##  5 C07.02  Frontera Comalapa           297492   8853.     33.6
##  6 C07.03  Huehuetán                    64000   3831.     16.7
##  7 C07.04  Huixtla                     229707   9709.     23.7
##  8 C07.05  Pichucalco                   52392   2473.     21.2
##  9 C07.06  San Cristóbal de las Casas 1038490  28569.     36.4
## 10 C07.07  Teopisca                     94240   3387.     27.8
tail(df.ciudades.list, 10)
## # A tibble: 10 x 5
## # Groups:   CVE_SUN [10]
##    CVE_SUN NOM_SUN                      PTOT_CD SUPT_CD DENS_HAS
##    <chr>   <chr>                          <dbl>   <dbl>    <dbl>
##  1 P31.08  Valladolid                     84291   3214.    26.2 
##  2 P32.01  Víctor Rosales                 45137   1114.    40.5 
##  3 P32.02  Jerez de García Salinas        58339   3453.    16.9 
##  4 P32.03  Juan Aldama                    19634   1510.    13.0 
##  5 P32.04  Loreto_ZS                      52448   1378.    38.1 
##  6 P32.05  Miguel Auza                    22692   2365.     9.59
##  7 P32.06  Nochistlán de Mejía            23873    977.    24.4 
##  8 P32.07  Ojocaliente                    43503   1803.    24.1 
##  9 P32.08  Sombrerete                     62247   4315.    14.4 
## 10 P32.09  Tlaltenango de Sánchez Román   24811    987.    25.1

Plots

Finalmente, presentamos algunas gráficas resultado del análisis realizado en este trabajo.

Localidades

A manera de ejemplo se presentan dos histogramas a partir de las variables de población total y grado promedio de escolaridad, ambas a nivel de localidad urbana.

ggplot(data = iter_2020_loc, aes(POBTOT/1000)) + geom_histogram(fill="#FD7C69") +
      labs(x="Population (Thousands)", y="Frequency", 
           title="Population histogram, Localities, Data year:2020") 
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

ggplot(data = iter_2020_loc, aes(GRAPROES)) + geom_histogram(fill="#66A65F") +
      labs(x="Númber of Years", y="Frequency", 
           title="Average years of education histogram, Localities, Data year:2020") 
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## Warning: Removed 82163 rows containing non-finite values (stat_bin).

Ciudades SUN

Histogramas con datos de población, superficie y densidad.

ggplot(data = df.ciudades.list, aes(PTOT_CD/1000000)) + geom_histogram(fill="#665C51") +
      labs(x="Population in millions", y="Frequency", 
           title="Total Population of Mexican Cities, Data year:2020") 
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

ggplot(data = df.ciudades.list, aes(SUPT_CD/1000)) + geom_histogram(fill="#C26B51") +
      labs(x="Thousands of hectares", y="Frequency", 
           title="Ocupied surface of Mexican Cities, Data year:2020") 
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

ggplot(data = df.ciudades.list, aes(DENS_HAS)) + geom_histogram(fill="#41B7C4") +
      labs(x="Density (inhabitants per hectare)", y="Frequency", 
           title="Density histogram of Mexican Cities, Data year:2020") 
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Relación entre Población y Superficie ocupada

ggplot(data = df.ciudades.list, aes(PTOT_CD/1000000, SUPT_CD/1000)) + geom_point(alpha = .6, size = 2) +
      labs(x="Population (Millions)", y="Surface in hectares(Thousands)", 
           title = "Cities in Mexico by Population and Surface")+
      geom_smooth(method = lm)
## `geom_smooth()` using formula 'y ~ x'