Integración de los Datos del Censo 2020 usando Python

México

El 25 de enero del 2020 se publicaron los datos del Censo de Población y Vivienda 2020 de México correspondientes al Cuestionario Básico con 221 variables e indicadores a nivel manzana, en el siguiente sitio: (INEGI). Sin duda representa una gran oportunidad para analistas y practicantes de la Ciencia de Datos, pues el nivel de detalle permite generar múltiples análisis y descubrimientos relativos a la población y su distribución a lo largo de todo México.

Sin embargo el INEGI distribuye los datos estadísticos y los geográficos de forma separada, por lo que en este artículo te mostrare como bajar y organizar todos los datos con Python.

Instalar Python (Distribución Anaconda)

El primer paso consiste en tener instalado Python en tu equipo, una de las formas mas robustas para contar con este entorno de trabajo es mediante la distribución llamada Anaconda, basta con entrar a la página de https://www.anaconda.com/products/individual y descargar el instalador correspondiente a tu sistema operativo:

Descarga aquí: https://www.anaconda.com/products/individual

Una vez instalado debes poder abrir una Terminal de tu sistema operativo y presionar el comando:

conda --version

Lo que da como resultado algo similar a la siguiente ventana:

Ahora podemos crear un ambiente virtual de trabajo, lo cual nos permitirá tener todas las librerias necesarias para trabajar con los datos del Censo sin necesidad de romper alguna dependencia en futuros proyectos de Python.

conda create --name cpv2020 python=3.8 -c conda-forge

Con el comando anterior estámos solicitando a anaconda que construya un ambiante de trabajo independiente para trabajar libremente con los paquetes especificos de nuestro proyecto. Nos solicitará aceptar la instalación como se muestra en la siguiente imagen, basta con escribir la letra Y para que proceda a la instalación:

presiona la letra [y] para continuar…

Ya que se instaló el ambiente lo puedes a empezar a usar con el comando:

conda activate cpv2020
Puedes observar que se activo el ambiente porque aparece al principio de la linea de comandos de la terminal entre paréntesis.

Ahora instalaremos la herramienta de programación llamada Jupyter Lab, lo cual se logra con el siguiente comando:

conda install -c conda-forge jupyterlab

Recuerda indicar con la letra [y] que estas de acuerdo en la lista de paquetes a instalar.

Observa que el comando se ejecutó dentro del ambiente cpv2020

Antes de iniciar la herramienta de trabajo es buen momento para crear el directorio de trabajo, es decir el lugar donde vamos a descargar los datos, en mi caso le llame Censo2020 como se muestra en la siguiente imagen:

Crear el directorio Censo2020

a continuación instalamos los siguientes paquetes de Python:

pip install geopandas==0.8.1
conda install -c conda-forge tqdm

Ahora es posible iniciar Jupyter Lab, la herramienta que usaremos a los largo de este artículo.

jupyter lab
Abrir la herramienta Jupyter Lab

Automáticamente el comando anterior nos abre una ventana del navegador con la siguiente:

Herramienta de desarrollo desde el navegador web (Jupyter Lab)

Jupyter Lab es una herramienta versátil en la que podemos trabajar la mayor parte de nuestro trabajo de Ciencia de Datos. Presionemos el botón Python 3 bajo la sección Notebook:

Presionar éste botón para crear un nuevo cuaderno de Jupyter

Es posible renombrar el cuaderno presionando botón derecho sobre la pestaña del cuaderno recientemente creado:

Quedando de la siguiente manera:

Cuaderno del Censo 2020

Carga de paquetes de trabajo

Lo primero que vamos a hacer es instruir a nuestro entorno de trabajo que cargue los paquetes de trabajo. Con los cuales podremos realizar el resto de nuestro trabajo. Podemos observar que el botón Play ejecuta cada celda de código y gracias a la magia de Jupyter veremos el resultado de la ejecución:

Cada celda se ejecuta haciendo clic en el botón de Play

Funciones de Python

Para organizar mejor el trabajo en Python es posible crear funciones. Fragmentos de código que vamos a ejecutar varias veces y que es mejor tener organizados mediante un nombre y una funcionalidad delimitada. Usaremos 2 funciones específicamente:

  • download: Es una funcion dedicada a descargar archivos de internet, con la característica de que mostrará una barra de avance, gracias a la biblioteca TQDM. Con la cual podremos ver el avance de la descarga de cada archivo
  • extract_shapefile: Esta función extrae los archivos para que las capas de información geográfica que vamos a trabajar, cuenten con los archivos necesarios y los deposita en una carpeta específica.
Funciones de apoyo

Generación de la estructura de directorios de trabajo

La siguiente celda construye las carpetas necesarias para organizar la información que se va a descargar.

La estructura de archivos resultante es:

Estructura de archivos resultante

El código que genera la estructura es el siguiente:

Descarga de datos

El siguiente código se encarga de descargar todos los archivos del sitio del INEGI y almacenarlos en el directorio correspondiente.

Con la primera celda se descargan en el directorio ./inegi/ccpvagebmza los archivos .zip de todos los estados de México con las variables e indicadores a nivel manzana.

La segunda celda descarga los archivos cartograficos, dentro de cada archivo zip se encuentran multiples capas de información. En la siguiente imagen se pueden ver los diferentes tipos de información geográfica que se encuentran en los archivos estatales descargados. En este tutorial utilizaremos los 3 tipos marcados en amarillo.

Extracción de datos de trabajo

El siguiente código extrae los datos necesarios para llevar a cabo la union de las variables e indicadores con los rasgos geográficos.

Extracción de toda la información

las celdas de código de arriba extraen los datos de cada archivo y concentran en un solo directorio los datos estadísticos:

  • ./inegi/ccpvagebmza/csv/conjunto_de_datos
Archivos estadísticos

y otro directorio con los datos geográficos:

  • ./inegi/mgccpv/shp/m/conjunto_de_datos
Archivos geográficos

Integración de datos estadísticos y geográficos

El siguiente código realiza la integración de los datos para cada estado independientemente (1–32) cargando los archivos Shapefile de las capas de: Manzana (m), Caserío disperso (cd) y Polígonos externos de manzana (pem). Tambien se cargan los datos estadísticos.

La secuencia de pasos realizados para la integración segun el código de arriva es:

  • Construir la CVEGEO concatenando las claves geoestadisticas ver el artículo anterior donde explico el detalle de la construcción de dicha clave: https://abxda.medium.com/un-evento-decenal-de-datos-abiertos-68c6d232c70b
  • Se realiza la union de tablas pd.merge(df, gpdf, how = ‘left’) de los datos estadísticos df y las manzanas urbanas gpdf, con la condición de que si no se encuentra la CVEGEO en las manzanas urbanas, entonces se dejen con valores nulos los campos provenientes del conjunto de datos geográfico. Con lo que evitamos perder algun dato estadístico que se pueda encontrar en alguna de las otras capas.
  • Despues de dicha union eliminamos todos los registros con el valor 0 en el campo de manzana (MZA), esto debido a que en la tabla estadística se encuentran los subtotales acumulados de Ageb, Municipio, Localidad y Estado, los cuales no nos interesan en este momento, debido a que estamos construyendo una capa geográfica a nivel manzana.
Observe los valores de el campo MZA cuando se refieren a totales o sub-totales
  • Ahora creamos la variable df1 con los registros que no identificaron una geometría en el cruce con las manzanas urbanas.
  • Procedemos a unir df1 con los caseríos dispersos df_geo_dif = pd.merge(df1, cddf, how = ‘left’). Lo cual une los campos de atributos de la manzana estadística y las coordenadas del punto dónde se capturó la información.
  • Posteriormente decidimos reemplazar los puntos de los caseríos dispersos con poligonos externos de manzana cuando fue posible.
  • Finalmente se genera una capa de información nacional en el formato GeoPackage: https://www.geopackage.org. Con la finalidad de tener todas la información en una base de datos geoestadística. La cual puede abriese en Sistemas de Información Geográfica como https://www.qgis.org/es/site/ o http://www.openjump.org

Gracias por Leerme :) Abel Coronado

Aquí abajo todo el código: https://github.com/abxda/Mexico-Population-Census-2020

import geopandas as gpd
import pandas as pd
from tqdm import tqdm
import requests
from zipfile import ZipFile
import time
import os
import shutil
#Funciones de apoyodef download(url,dir):
time.sleep(5)
chunk_size = 1024
r = requests.get(url, stream = True)
total_size = int(r.headers['content-length'])
filename = url.split('/')[-1]
with open(dir+filename, 'wb') as f:
for data in tqdm(iterable = r.iter_content(chunk_size = chunk_size), total = total_size/chunk_size, unit = 'KB'):
f.write(data)

def extract_shapefile(states,directory,shp_dir,shape_type):
for i in range(32):
estado = states[i]
file = str(i+1).zfill(2)
zip_file = directory+estado
shp_file = f'conjunto_de_datos/{file}{shape_type}.shp'
cpg_file = f'conjunto_de_datos/{file}{shape_type}.cpg'
dbf_file = f'conjunto_de_datos/{file}{shape_type}.dbf'
prj_file = f'conjunto_de_datos/{file}{shape_type}.prj'
shx_file = f'conjunto_de_datos/{file}{shape_type}.shx'
with ZipFile(zip_file, 'r') as zip:
zip.extract(shp_file,shp_dir)
zip.extract(dbf_file,shp_dir)
zip.extract(prj_file,shp_dir)
zip.extract(shx_file,shp_dir)
try:
zip.extract(cpg_file,shp_dir)
except:
with open(shp_dir+cpg_file, 'w') as out_file:
out_file.write("ISO 88591")
# Estructura de Directoriosos.makedirs("./inegi/ccpvagebmza/csv/conjunto_de_datos")
os.makedirs("./inegi/mgccpv/shp/m/conjunto_de_datos")
os.makedirs("./inegi/mgccpv/gpkg/")
#Descarga de Datos
directory= "./inegi/ccpvagebmza/"
for i in range(32):
estado = str(i+1).zfill(2)
ageb_mza = f'https://www.inegi.org.mx/contenidos/programas/ccpv/2020/datosabiertos/ageb_manzana/ageb_mza_urbana_{estado}_cpv2020_csv.zip'
download(ageb_mza,directory)
directory= "./inegi/mgccpv/"
url_mgccpv = "https://www.inegi.org.mx/contenidos/productos/prod_serv/contenidos/espanol/bvinegi/productos/geografia/marcogeo/889463807469/"
states = ["01_aguascalientes.zip","02_bajacalifornia.zip","03_bajacaliforniasur.zip","04_campeche.zip","05_coahuiladezaragoza.zip","06_colima.zip","07_chiapas.zip","08_chihuahua.zip","09_ciudaddemexico.zip","10_durango.zip","11_guanajuato.zip","12_guerrero.zip","13_hidalgo.zip","14_jalisco.zip","15_mexico.zip","16_michoacandeocampo.zip","17_morelos.zip","18_nayarit.zip","19_nuevoleon.zip","20_oaxaca.zip","21_puebla.zip","22_queretaro.zip","23_quintanaroo.zip","24_sanluispotosi.zip","25_sinaloa.zip","26_sonora.zip","27_tabasco.zip","28_tamaulipas.zip","29_tlaxcala.zip","30_veracruzignaciodelallave.zip","31_yucatan.zip","32_zacatecas.zip"]
for state in states:
print(state)
state_file = url_mgccpv+state
download(state_file,directory)
#Extracción de Datos# Variables e indicadores del Censo de Población 2020
directory= "./inegi/ccpvagebmza/"
csv_dir = directory+"csv/"
for i in range(32):
estado = str(i+1).zfill(2)
zip_file = directory+f'ageb_mza_urbana_{estado}_cpv2020_csv.zip'
csv_file = f'conjunto_de_datos/conjunto_de_datos_ageb_urbana_{estado}_cpv2020.csv'
with ZipFile(zip_file, 'r') as zip:
zip.extract(csv_file,csv_dir)
# Manzanas
shape_type = "m"
directory= "./inegi/mgccpv/"
shp_dir = directory+"shp/m/"
extract_shapefile(states,directory,shp_dir,shape_type)
# Caserío disperso
shape_type = "cd"
directory= "./inegi/mgccpv/"
shp_dir = directory+"shp/m/"
extract_shapefile(states,directory,shp_dir,shape_type)
# Polígono externo de manzana
shape_type = "pem"
directory= "./inegi/mgccpv/"
shp_dir = directory+"shp/m/"
extract_shapefile(states,directory,shp_dir,shape_type)
#Union de Datosfor i in range(32):
estado = str(i+1).zfill(2)
print("procesando estado: "+str(estado))
gpdf = gpd.read_file(f"./inegi/mgccpv/shp/m/conjunto_de_datos/{estado}m.shp")
cddf = gpd.read_file(f"./inegi/mgccpv/shp/m/conjunto_de_datos/{estado}cd.shp")
pemdf = gpd.read_file(f"./inegi/mgccpv/shp/m/conjunto_de_datos/{estado}pem.shp")
df = pd.read_csv(f"./inegi/ccpvagebmza/csv/conjunto_de_datos/conjunto_de_datos_ageb_urbana_{estado}_cpv2020.csv",na_values=['N/A','N/D','*'])
df['CVEGEO'] = df.apply(lambda row: str(row['ENTIDAD']).zfill(2) + str(row['MUN']).zfill(3)+ str(row['LOC']).zfill(4)+ str(row['AGEB']).zfill(4)+ str(row['MZA']).zfill(3), axis=1)
df_geo_censo = pd.merge(df, gpdf, how = 'left').drop(["CVE_ENT", "CVE_MUN", "CVE_LOC", "CVE_AGEB", "CVE_MZA"], axis = 1)
df_geo_censo = df_geo_censo.drop(df[df.MZA == 0].index)
df_geo_censo = gpd.GeoDataFrame(df_geo_censo, geometry="geometry")
#df_geo_censo = df_geo_censo.to_crs("EPSG:4326")
df_full = df_geo_censo[df_geo_censo['geometry'].notnull()]
df1 = df_geo_censo[df_geo_censo['geometry'].isnull()]
df1 = df1.drop(["TIPOMZA","AMBITO","geometry"], axis = 1)
df_geo_dif = pd.merge(df1, cddf, how = 'left').drop(["CVE_ENT", "CVE_MUN", "CVE_LOC", "CVE_AGEB", "CVE_MZA"], axis = 1)
pemdf = pemdf.rename(columns={'geometry': 'geometry_pem'})
pemdf = pemdf.drop(["CVE_ENT", "CVE_MUN", "CVE_LOC", "CVE_AGEB", "CVE_MZA"], axis = 1)
df_geo_dif = pd.merge(df_geo_dif, pemdf, how = 'left')
df_geo_dif['geometry'] = df_geo_dif.apply(lambda row : row['geometry_pem'] if row['geometry_pem'] != None else row['geometry'], axis = 1)
df_geo_dif = df_geo_dif.drop(["geometry_pem"], axis = 1)
final_shape = pd.concat([df_full,df_geo_dif],ignore_index=True)
final_shape["AGEB"] = final_shape.AGEB.apply(str)
print("guardando datos del estado: "+str(estado))
final_shape.to_file(f"./inegi/mgccpv/gpkg/cpv2020_{estado}.gpkg", layer='cpv2020', driver="GPKG")

Father-Husband-Data Scientist-Philosopher-Entrepreneur-Professor PhD c. in Data Science-MSc Stats #R #Scala #Spark #SatelliteImagery #Python #BigData #Nerd