Ejemplo de cuaderno para el proyecto final
Contents
Ejemplo de cuaderno para el proyecto final#
Para la entrega final podrás entregar un cuaderno como el siguiente. Este cuaderno te puede servir de guía, e incluso puedes intentar replicarlo para obtener resultados similares :)
⚠️ Para ver las visualizaciones es necesario que hagas clic en el botón “Open in Colab” que aparece en la parte superior de la página.
Importar datos#
Con “importar datos” nos referimos a la manera en la que preparamos la fuente de datos para ser leída por nuestro programa.
Existen múltiples maneras de importar la información. Por ejemplo, podemos sencillamente utilizar el mismo método que usamos con nuestro archivo ejemplo-1.txt
.
Descarga el archivo que quieras utilizar en el directorio de Drive en el que vayas a almacenar tus datos.
Como ejemplo, voy a utilizar los casos nacionales de COVID-19 registrados diariamente durante el primer semestre de 2022: https://datos.cdmx.gob.mx/dataset/casos-asociados-a-covid-19/resource/e5f65f40-5904-492a-ae33-1ea98fb73d78?inner_span=True
Descargo el archivo CSV en un directorio de mi computadora. Posteriormente lo subo a mi directorio de datos de Google Drive:
Volvemos a nuestro cuaderno de Google Colab. Me aseguro de haber activado Google Drive en mi Google Colab y busco el directorio en el cual está mi archivo. En mi caso: '/content/drive/MyDrive/Colab Notebooks/curso_datos/casos_nacionales_covid-19_2022_semestre1.csv'
Con esos pasos, podemos hacer la importación:
datos = '/content/drive/MyDrive/Colab Notebooks/curso_datos/casos_nacionales_covid-19_2022_semestre1.csv'
with open(datos, 'r') as f:
data = f.readlines(10) # agrego este argumento porque el archivo es muy extenso.
data
['"","fecha_actualizacion","id_registro","origen","sector","entidad_um","sexo","entidad_nac","entidad_res","municipio_res","tipo_paciente","fecha_ingreso","fecha_sintomas","fecha_def","intubado","neumonia","edad","nacionalidad","embarazo","habla_lengua_indig","indigena","diabetes","epoc","asma","inmusupr","hipertension","otra_com","cardiovascular","obesidad","renal_cronica","tabaquismo","otro_caso","toma_muestra_lab","resultado_lab","toma_muestra_antigeno","resultado_antigeno","clasificacion_final","migrante","pais_nacionalidad","pais_origen","uci"\n']
De esta manera hemos logrado incluir el archivo en nuestro cuaderno, pero será muy complejo manipularlo. Por esta razón, es preferible utilizar una librería que nos ayude a procesar estos datos. En nuestro caso, usaremos ‘Pandas’
Para hacer que nuestro programa funcione, solamente debemos importar la librería:
import pandas as pd
Y posteriormente podremos abrir nuestro archivo desde Python:
import pandas as pd
covid_nacional = pd.read_csv(datos)
covid_nacional.head()
/usr/local/lib/python3.7/dist-packages/IPython/core/interactiveshell.py:3326: DtypeWarning: Columns (13) have mixed types.Specify dtype option on import or set low_memory=False.
exec(code_obj, self.user_global_ns, self.user_ns)
Unnamed: 0 | fecha_actualizacion | id_registro | origen | sector | entidad_um | sexo | entidad_nac | entidad_res | municipio_res | ... | otro_caso | toma_muestra_lab | resultado_lab | toma_muestra_antigeno | resultado_antigeno | clasificacion_final | migrante | pais_nacionalidad | pais_origen | uci | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2022-06-26 | 0793b8 | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | HOMBRE | CIUDAD DE MÉXICO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | NO ESPECIFICADO | MÉXICO | NO APLICA | NO APLICA |
1 | 2 | 2022-06-26 | 0fef08 | USMER | SSA | CIUDAD DE MÉXICO | HOMBRE | CIUDAD DE MÉXICO | NaN | NaN | ... | NO | SI | POSITIVO A SARS-COV-2 | NO | NO APLICA (CASO SIN MUESTRA) | CASO DE SARS-COV-2 CONFIRMADO | NO ESPECIFICADO | MÉXICO | NO APLICA | NO APLICA |
2 | 3 | 2022-06-26 | 11e31a | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | HOMBRE | CIUDAD DE MÉXICO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | NO ESPECIFICADO | MÉXICO | NO APLICA | NO APLICA |
3 | 4 | 2022-06-26 | 0741e4 | FUERA DE USMER | ISSSTE | CIUDAD DE MÉXICO | HOMBRE | CIUDAD DE MÉXICO | NaN | NaN | ... | NO | SI | RESULTADO NO ADECUADO | NO | NO APLICA (CASO SIN MUESTRA) | NO REALIZADO POR LABORATORIO | NO ESPECIFICADO | MÉXICO | NO APLICA | NO |
4 | 5 | 2022-06-26 | 13c92b | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | CIUDAD DE MÉXICO | NaN | NaN | ... | SI | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | NO ESPECIFICADO | MÉXICO | NO APLICA | NO APLICA |
5 rows × 41 columns
De esta manera, nuestro archivo estará listo para ser procesado :)
Análisis de estructuras de datos y preparación#
Describe la fuente de datos#
Una descripción simple de la forma de la fuente de datos es la siguiente:
# número de filas
filas = covid_nacional.shape[0]
filas
1323501
Esta es una fuente de datos con suficientes campos como para justificar una lectura distante de la información. Difícilmente una persona podría comprender la información que hay en ella solamente “leyendo” los datos de esas tablas.
# número de columnas
columnas = covid_nacional.shape[1]
columnas
41
Además, vemos que es un conjunto de datos con una cantidad significativa de categorías. Esto permite que con una sola fuente de información se puedan realizar operaciones de comparación entre columnas para analizar la información.
# nombre de las columnas
covid_nacional.columns
Index(['Unnamed: 0', 'fecha_actualizacion', 'id_registro', 'origen', 'sector',
'entidad_um', 'sexo', 'entidad_nac', 'entidad_res', 'municipio_res',
'tipo_paciente', 'fecha_ingreso', 'fecha_sintomas', 'fecha_def',
'intubado', 'neumonia', 'edad', 'nacionalidad', 'embarazo',
'habla_lengua_indig', 'indigena', 'diabetes', 'epoc', 'asma',
'inmusupr', 'hipertension', 'otra_com', 'cardiovascular', 'obesidad',
'renal_cronica', 'tabaquismo', 'otro_caso', 'toma_muestra_lab',
'resultado_lab', 'toma_muestra_antigeno', 'resultado_antigeno',
'clasificacion_final', 'migrante', 'pais_nacionalidad', 'pais_origen',
'uci'],
dtype='object')
El nombre de las columnas nos ayuda a identificar las categorías y posibles datos que contienen nuestra fuente de datos.
No todas las fuentes de datos nombran sus columnas de manera significativa. En el caso de nuestro ejemplo, es bastante sencillo identificar qué tipo de información contiene cada categoría o columna, incluso qué tipo de dato sería deseable que tuviese cada una.
Tipos de datos con dtypes()
#
covid_nacional.dtypes
Unnamed: 0 int64
fecha_actualizacion object
id_registro object
origen object
sector object
entidad_um object
sexo object
entidad_nac object
entidad_res object
municipio_res object
tipo_paciente object
fecha_ingreso object
fecha_sintomas object
fecha_def object
intubado object
neumonia object
edad int64
nacionalidad object
embarazo object
habla_lengua_indig object
indigena object
diabetes object
epoc object
asma object
inmusupr object
hipertension object
otra_com object
cardiovascular object
obesidad object
renal_cronica object
tabaquismo object
otro_caso object
toma_muestra_lab object
resultado_lab object
toma_muestra_antigeno object
resultado_antigeno object
clasificacion_final object
migrante object
pais_nacionalidad object
pais_origen object
uci object
dtype: object
La mayoría de los datos se encuentran representados como tipo object
, es decir, que son de tipo texto, numérico-textual o mixto.
Aunque hay columnas que podrían tener un tipo de dato datetime
, están representadas en tipo object
. Esas columnas deberán ser transformadas para poder hacer operaciones y visualizaciones.
Descripción de los datos con describe()
#
covid_nacional.describe()
Unnamed: 0 | edad | |
---|---|---|
count | 1.323501e+06 | 1.323501e+06 |
mean | 6.617510e+05 | 3.774596e+01 |
std | 3.820620e+05 | 1.728453e+01 |
min | 1.000000e+00 | 0.000000e+00 |
25% | 3.308760e+05 | 2.500000e+01 |
50% | 6.617510e+05 | 3.600000e+01 |
75% | 9.926260e+05 | 5.000000e+01 |
max | 1.323501e+06 | 1.220000e+02 |
De modo predeterminado, pandas
describe los datos numéricos int64
. De estos solamente nos sería útil edad
, pues Unnamed: 0
es un índice (valor nominal).
covid_nacional.describe(include='all')
Unnamed: 0 | fecha_actualizacion | id_registro | origen | sector | entidad_um | sexo | entidad_nac | entidad_res | municipio_res | ... | otro_caso | toma_muestra_lab | resultado_lab | toma_muestra_antigeno | resultado_antigeno | clasificacion_final | migrante | pais_nacionalidad | pais_origen | uci | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 1.323501e+06 | 1323501 | 1323501 | 1323501 | 1323501 | 1323501 | 1323501 | 1323501 | 149707 | 149707 | ... | 1323501 | 1323501 | 1323501 | 1323501 | 1323501 | 1323501 | 1323501 | 1323501 | 1320040 | 1323501 |
unique | NaN | 1 | 1323501 | 2 | 12 | 32 | 2 | 33 | 23 | 1190 | ... | 3 | 2 | 5 | 2 | 3 | 7 | 3 | 122 | 1 | 4 |
top | NaN | 2022-06-26 | 0793b8 | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | CIUDAD DE MÉXICO | MÉXICO | NEZAHUALCÓYOTL | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | NO ESPECIFICADO | MÉXICO | NO APLICA | NO APLICA |
freq | NaN | 1323501 | 1 | 1170267 | 793606 | 1314661 | 733991 | 1052272 | 133374 | 26282 | ... | 848434 | 1152385 | 1152385 | 1204565 | 771647 | 792364 | 1305180 | 1304673 | 1320040 | 1297093 |
mean | 6.617510e+05 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
std | 3.820620e+05 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
min | 1.000000e+00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
25% | 3.308760e+05 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
50% | 6.617510e+05 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
75% | 9.926260e+05 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
max | 1.323501e+06 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
11 rows × 41 columns
El parámetro include='all'
obliga a realizar la operación en todas las columnas.
Esto permite identificar algunas columnas con ciertas frecuencias que podrían ser sujeto de análisis. Por ejemplo, correlaciones entre enfermedades crónicas y resultados (positivos o negativos), o frecuencias de casos de migrantes, mujeres o indígenas relacionadas con un área geográfica.
Debido a que esta fuente de datos no cuenta con información georeferenciada (contamos con los nombres de los municipios, pero no la información de latitud y longitud) será necesario utilizar una fuente de datos que permita agregar esa información.
Procesamiento de datos#
Manipulación de datos#
Aplicación del método .iloc
para localizar filas y columnas por índice:
covid_nacional.iloc[2:200, 1:3]
fecha_actualizacion | id_registro | |
---|---|---|
2 | 2022-06-26 | 11e31a |
3 | 2022-06-26 | 0741e4 |
4 | 2022-06-26 | 13c92b |
5 | 2022-06-26 | 04f190 |
6 | 2022-06-26 | 0a1655 |
... | ... | ... |
195 | 2022-06-26 | 485cdb |
196 | 2022-06-26 | 984dc6 |
197 | 2022-06-26 | 4b5708 |
198 | 2022-06-26 | bb8b5b |
199 | 2022-06-26 | cc68e2 |
198 rows × 2 columns
Aplicación del método .loc
para hallar celdas por coincidencias:
seleccion = covid_nacional.loc[(covid_nacional['sexo'] == 'MUJER') & (covid_nacional['migrante'] == 'SI')]
seleccion
Unnamed: 0 | fecha_actualizacion | id_registro | origen | sector | entidad_um | sexo | entidad_nac | entidad_res | municipio_res | ... | otro_caso | toma_muestra_lab | resultado_lab | toma_muestra_antigeno | resultado_antigeno | clasificacion_final | migrante | pais_nacionalidad | pais_origen | uci | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
252 | 253 | 2022-06-26 | b94888 | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | SI | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | VENEZUELA | NaN | NO APLICA |
971 | 972 | 2022-06-26 | d22ed2 | USMER | SSA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | SI | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | ESTADOS UNIDOS DE AMÉRICA | NaN | NO APLICA |
979 | 980 | 2022-06-26 | 6a5061 | USMER | SSA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | SI | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | ESTADOS UNIDOS DE AMÉRICA | NaN | NO APLICA |
5877 | 5878 | 2022-06-26 | ac1990 | FUERA DE USMER | PRIVADA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | ESTADOS UNIDOS DE AMÉRICA | NaN | NO APLICA |
6666 | 6667 | 2022-06-26 | 8d5273 | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | CUBA | NaN | NO APLICA |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
1298223 | 1298224 | 2022-06-26 | g16c3a9 | FUERA DE USMER | PRIVADA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | ITALIA | NaN | NO APLICA |
1305240 | 1305241 | 2022-06-26 | g154063 | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | EL SALVADOR | NaN | NO APLICA |
1305279 | 1305280 | 2022-06-26 | g1683fe | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | GUATEMALA | NaN | NO APLICA |
1316685 | 1316686 | 2022-06-26 | g0ebf9f | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | REPÚBLICA DE HONDURAS | NaN | NO APLICA |
1319864 | 1319865 | 2022-06-26 | g093480 | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | NO ESPECIFICADO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | SI | CHILE | NaN | NO APLICA |
1611 rows × 41 columns
Renombramos las columnas para poder realizar correctamente la unión entre dos dataframes:
covid_nacional.rename(columns={
"entidad_nac": "entidad_nacimiento",
"entidad_res": "entidad_residencia",
"municipio_res": "municipio_residencia"
}, inplace=True)
covid_nacional[7:10]
Unnamed: 0 | fecha_actualizacion | id_registro | origen | sector | entidad_um | sexo | entidad_nacimiento | entidad_residencia | municipio_residencia | ... | otro_caso | toma_muestra_lab | resultado_lab | toma_muestra_antigeno | resultado_antigeno | clasificacion_final | migrante | pais_nacionalidad | pais_origen | uci | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
7 | 8 | 2022-06-26 | 0ba73d | FUERA DE USMER | ISSSTE | CIUDAD DE MÉXICO | MUJER | QUERÉTARO | MÉXICO | NAUCALPAN DE JUÁREZ | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | NO | NO APLICA (CASO SIN MUESTRA) | CASO SOSPECHOSO | NO ESPECIFICADO | MÉXICO | NO APLICA | NO APLICA |
8 | 9 | 2022-06-26 | 0681f2 | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | HOMBRE | CIUDAD DE MÉXICO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | NEGATIVO A SARS-COV-2 | NEGATIVO A SARS-COV-2 | NO ESPECIFICADO | MÉXICO | NO APLICA | NO APLICA |
9 | 10 | 2022-06-26 | 0a98b4 | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | MICHOACÁN DE OCAMPO | NaN | NaN | ... | NO | NO | NO APLICA (CASO SIN MUESTRA) | SI | POSITIVO A SARS-COV-2 | CASO DE SARS-COV-2 CONFIRMADO | NO ESPECIFICADO | MÉXICO | NO APLICA | NO APLICA |
3 rows × 41 columns
Merge#
Nuevo conjunto de datos para realizar la combinación:
ruta_areas_inegi = '/content/drive/MyDrive/Colab Notebooks/curso_datos/AGEEML_2022842026272.csv'
areas_inegi = pd.read_csv(ruta_areas_inegi)
areas_inegi.head()
Mapa | Cve_Ent | Nom_Ent | Nom_Abr | Cve_Mun | Nom_Mun | Cve_Loc | Nom_Loc | Ámbito | Latitud | Longitud | Lat_Decimal | Lon_Decimal | Altitud | Cve_Carta | Pob_Total | Pob_Masculina | Pob_Femenina | Total De Viviendas Habitadas | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 10010001 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 1 | Aguascalientes | U | 21°52´47.362N" | 102°17´45.768W" | 21.879823 | -102.296047 | 1878 | F13D19 | 863893 | 419168 | 444725 | 246259 |
1 | 10010094 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 94 | Granja Adelita | R | 21°52´18.749N" | 102°22´24.710W" | 21.871875 | -102.373531 | 1901 | F13D18 | 5 | * | * | 2 |
2 | 10010096 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 96 | Agua Azul | R | 21°53´01.522N" | 102°21´25.639W" | 21.883756 | -102.357122 | 1861 | F13D18 | 41 | 24 | 17 | 12 |
3 | 10010100 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 100 | Rancho Alegre | R | 21°51´16.556N" | 102°22´21.884W" | 21.854599 | -102.372746 | 1879 | F13D18 | 0 | 0 | 0 | 0 |
4 | 10010102 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 102 | Los Arbolitos [Rancho] | R | 21°46´48.650N" | 102°21´26.261W" | 21.780181 | -102.357295 | 1861 | F13D18 | 8 | * | * | 2 |
Pasos previos para el inner merge#
Para nuestros conjuntos de datos requiere un inner merge
para geolocalizar los datos. Pero para ello requeriremos realizar algunas tareas previas:
1. Renombrar columna para unión en el segundo dataframe#
areas_inegi.rename(
columns={'Nom_Mun':'municipio_residencia'}, # recordemos que cambiamos el nombre de la columna en el ejercicio anterior
inplace=True)
areas_inegi.head()
Mapa | Cve_Ent | Nom_Ent | Nom_Abr | Cve_Mun | municipio_residencia | Cve_Loc | Nom_Loc | Ámbito | Latitud | Longitud | Lat_Decimal | Lon_Decimal | Altitud | Cve_Carta | Pob_Total | Pob_Masculina | Pob_Femenina | Total De Viviendas Habitadas | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 10010001 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 1 | Aguascalientes | U | 21°52´47.362N" | 102°17´45.768W" | 21.879823 | -102.296047 | 1878 | F13D19 | 863893 | 419168 | 444725 | 246259 |
1 | 10010094 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 94 | Granja Adelita | R | 21°52´18.749N" | 102°22´24.710W" | 21.871875 | -102.373531 | 1901 | F13D18 | 5 | * | * | 2 |
2 | 10010096 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 96 | Agua Azul | R | 21°53´01.522N" | 102°21´25.639W" | 21.883756 | -102.357122 | 1861 | F13D18 | 41 | 24 | 17 | 12 |
3 | 10010100 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 100 | Rancho Alegre | R | 21°51´16.556N" | 102°22´21.884W" | 21.854599 | -102.372746 | 1879 | F13D18 | 0 | 0 | 0 | 0 |
4 | 10010102 | 1 | Aguascalientes | Ags. | 1 | Aguascalientes | 102 | Los Arbolitos [Rancho] | R | 21°46´48.650N" | 102°21´26.261W" | 21.780181 | -102.357295 | 1861 | F13D18 | 8 | * | * | 2 |
2. Normalizar la columna común#
covid_nacional['municipio_residencia'] = covid_nacional['municipio_residencia'].str.lower()
areas_inegi['municipio_residencia'] = areas_inegi['municipio_residencia'].str.lower()
3. Segmentación de la información#
areas_inegi_tm = areas_inegi.loc[areas_inegi['Cve_Loc'] == 1]
Realización del inner merge#
conjunto_datos = pd.merge(covid_nacional, areas_inegi_tm, how='inner', on='municipio_residencia')
print(conjunto_datos.shape)
conjunto_datos.head()
(158085, 59)
Unnamed: 0 | fecha_actualizacion | id_registro | origen | sector | entidad_um | sexo | entidad_nacimiento | entidad_residencia | municipio_residencia | ... | Latitud | Longitud | Lat_Decimal | Lon_Decimal | Altitud | Cve_Carta | Pob_Total | Pob_Masculina | Pob_Femenina | Total De Viviendas Habitadas | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 8 | 2022-06-26 | 0ba73d | FUERA DE USMER | ISSSTE | CIUDAD DE MÉXICO | MUJER | QUERÉTARO | MÉXICO | naucalpan de juárez | ... | 19°28´43.690N" | 099°13´59.585W" | 19.478803 | -99.233218 | 2280 | E14A39 | 776220 | 373698 | 402522 | 225509 |
1 | 143 | 2022-06-26 | 588e9b | FUERA DE USMER | SSA | CIUDAD DE MÉXICO | MUJER | CIUDAD DE MÉXICO | MÉXICO | naucalpan de juárez | ... | 19°28´43.690N" | 099°13´59.585W" | 19.478803 | -99.233218 | 2280 | E14A39 | 776220 | 373698 | 402522 | 225509 |
2 | 154 | 2022-06-26 | 51860a | USMER | SSA | CIUDAD DE MÉXICO | HOMBRE | CIUDAD DE MÉXICO | MÉXICO | naucalpan de juárez | ... | 19°28´43.690N" | 099°13´59.585W" | 19.478803 | -99.233218 | 2280 | E14A39 | 776220 | 373698 | 402522 | 225509 |
3 | 912 | 2022-06-26 | de16a0 | USMER | SSA | CIUDAD DE MÉXICO | MUJER | CIUDAD DE MÉXICO | MÉXICO | naucalpan de juárez | ... | 19°28´43.690N" | 099°13´59.585W" | 19.478803 | -99.233218 | 2280 | E14A39 | 776220 | 373698 | 402522 | 225509 |
4 | 1032 | 2022-06-26 | 5f39e3 | USMER | SSA | CIUDAD DE MÉXICO | HOMBRE | GUANAJUATO | MÉXICO | naucalpan de juárez | ... | 19°28´43.690N" | 099°13´59.585W" | 19.478803 | -99.233218 | 2280 | E14A39 | 776220 | 373698 | 402522 | 225509 |
5 rows × 59 columns
Limpieza de datos#
Segmentación por columnas útiles#
muestra_covid = conjunto_datos[['sexo', 'edad', 'entidad_nacimiento', 'municipio_residencia', 'indigena', 'nacionalidad', 'migrante', 'pais_nacionalidad', 'fecha_ingreso', 'fecha_sintomas', 'fecha_def', 'municipio_residencia', 'Lat_Decimal', 'Lon_Decimal']]
muestra_covid.head()
sexo | edad | entidad_nacimiento | municipio_residencia | indigena | nacionalidad | migrante | pais_nacionalidad | fecha_ingreso | fecha_sintomas | fecha_def | municipio_residencia | Lat_Decimal | Lon_Decimal | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | MUJER | 75 | QUERÉTARO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-21 | 2022-02-16 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
1 | MUJER | 32 | CIUDAD DE MÉXICO | naucalpan de juárez | NO ESPECIFICADO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-07 | 2022-01-02 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
2 | HOMBRE | 30 | CIUDAD DE MÉXICO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-04 | 2022-02-03 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
3 | MUJER | 51 | CIUDAD DE MÉXICO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-28 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
4 | HOMBRE | 83 | GUANAJUATO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-30 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
Lidiar con datos nulos#
muestra_covid.fillna({'municipio_residencia': 'NO APLICA', 'pais_nacionalidad': 'NO APLICA'}, inplace=True)
muestra_covid
/usr/local/lib/python3.7/dist-packages/pandas/core/frame.py:5182: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
downcast=downcast,
/usr/local/lib/python3.7/dist-packages/pandas/core/generic.py:6392: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
return self._update_inplace(result)
sexo | edad | entidad_nacimiento | municipio_residencia | indigena | nacionalidad | migrante | pais_nacionalidad | fecha_ingreso | fecha_sintomas | fecha_def | municipio_residencia | Lat_Decimal | Lon_Decimal | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | MUJER | 75 | QUERÉTARO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-21 | 2022-02-16 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
1 | MUJER | 32 | CIUDAD DE MÉXICO | naucalpan de juárez | NO ESPECIFICADO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-07 | 2022-01-02 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
2 | HOMBRE | 30 | CIUDAD DE MÉXICO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-04 | 2022-02-03 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
3 | MUJER | 51 | CIUDAD DE MÉXICO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-28 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
4 | HOMBRE | 83 | GUANAJUATO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-30 | NaN | naucalpan de juárez | 19.478803 | -99.233218 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
158080 | HOMBRE | 12 | VERACRUZ DE IGNACIO DE LA LLAVE | amatlán de los reyes | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-23 | 2022-06-23 | NaN | amatlán de los reyes | 18.847578 | -96.915484 |
158081 | MUJER | 46 | CIUDAD DE MÉXICO | amatlán de los reyes | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-22 | 2022-06-19 | NaN | amatlán de los reyes | 18.847578 | -96.915484 |
158082 | MUJER | 59 | CIUDAD DE MÉXICO | general simón bolívar | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-23 | 2022-06-22 | NaN | general simón bolívar | 24.689074 | -103.225975 |
158083 | MUJER | 27 | MÉXICO | temozón | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-24 | 2022-06-22 | NaN | temozón | 20.803680 | -88.201158 |
158084 | MUJER | 32 | MÉXICO | izamal | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-24 | 2022-06-20 | NaN | izamal | 20.932998 | -89.019715 |
158085 rows × 14 columns
Transformar datos#
columnas = ['fecha_ingreso', 'fecha_sintomas', 'fecha_def']
for columna in columnas:
muestra_covid[columna] = pd.to_datetime(muestra_covid.loc[:, columna])
muestra_covid.dtypes
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:3: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
This is separate from the ipykernel package so we can avoid doing imports until
sexo object
edad int64
entidad_nacimiento object
municipio_residencia object
indigena object
nacionalidad object
migrante object
pais_nacionalidad object
fecha_ingreso datetime64[ns]
fecha_sintomas datetime64[ns]
fecha_def datetime64[ns]
municipio_residencia object
Lat_Decimal float64
Lon_Decimal float64
dtype: object
Georeferenciar los datos de pais_nacionalidad
#
# obtener librería pycountry
!pip install pycountry
import pycountry
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
Requirement already satisfied: pycountry in /usr/local/lib/python3.7/dist-packages (22.3.5)
Requirement already satisfied: setuptools in /usr/local/lib/python3.7/dist-packages (from pycountry) (57.4.0)
# Función para convertir los datos a iso en español
import gettext
# Esta corrección es necesaria para incluir una serie de países que de otra manera quedarían excluidos
# Se excluyeron las siguientes claves por ser ambiguas o no localizables: 'OTRO', 'SE DESCONOCE', 'REPÚBLICA CHECA Y REPÚBLICA ESLOVACA', 'PAÍSES DE LA EX-U.R.S.S., EXCEPTO UCRANIA Y BIELORUSIA', 'AZERBAIYÁN - ISLAS AZORES'
correccion_paises = {
'nombre_original': ['ESTADOS UNIDOS DE AMÉRICA', 'VENEZUELA', 'TAIWÁN', 'HOLANDA', 'REPÚBLICA DE HONDURAS', 'BOLIVIA',
'REPÚBLICA DE COREA', 'GRAN BRETAÑA (REINO UNIDO)', 'RUSIA',
'REPÚBLICA DE COSTA RICA', 'REPÚBLICA DE PANAMÁ',
'REPÚBLICA ORIENTAL DEL URUGUAY',
'RUMANIA', 'IRÁN', 'ESTADO LIBRE ASOCIADO DE PUERTO RICO',
'ESTADO DE KUWAIT', 'ANTIGUA Y BERMUDA',
'CAMPIONE DITALIA',
'EMIRATOS ARABES UNIDOS',
'ZONA ESPECIAL CANARIA', 'COMMONWEALTH DE DOMINICA',
'THAILANDIA', 'ESTADO DE BAHREIN', 'MALÍ',
'ISLAS MENORES ALEJADAS DE LOS ESTADOS UNIDOS', 'GUYANA FRANCESA',
'IRAQ'],
'nombre_corregido': ['ESTADOS UNIDOS', 'VENEZUELA, REPÚBLICA BOLIVARIANA DE', 'TAIWÁN, PROVINCIA DE CHINA', 'PAÍSES BAJOS', 'HONDURAS', 'BOLIVIA, ESTADO PLURINACIONAL de',
'COREA, REPÚBLICA DE', 'Reino Unido', 'FEDERACIÓN RUSA',
'COSTA RICA', 'PANAMÁ', 'URUGUAY', 'rumanía', 'irán, república islámica de', 'Puerto rico', 'KUWAIT', 'ANTIGUA Y BARBUDA', 'ITALIA', 'EMIRATOS ÁRABES UNIDOS', 'ESPAÑA', 'DOMINICA', 'TAILANDIA', 'BAHREIN', 'MALI', 'ESTADOS UNIDOS', 'GUYANA', 'IRAK']
}
none_countries = {'nombre': ['ZONA NEUTRAL', 'COSTA DE MARFIL', 'REPÚBLICA DEMOCRÁTICA DE COREA', 'ARGELIA', 'NUEVA ZELANDIA', 'ARABIA SAUDITA', 'REPÚBLICA CENTRO AFRICANA', 'SUDÁFRICA'],
'alpha2': ['NT', 'CI', 'KP', 'DZ', 'NZ', 'SA', 'CF', 'ZA'],
'alpha3': ['NTZ', 'CIV', 'PRK', 'DZA', 'NZL', 'SAU', 'CAF', 'ZAF']}
def map_country_code(country_name, language, iso):
'''
country_name: str. El nombre del país en español.
language: str. El idioma en el que se desea obtener el código (p. ej: 'es').
iso: str. Opciones posibles: 'alpha_2' o 'alpha_3'.
'''
try:
if country_name is None:
return None
# esta condición sintetiza el caso de México (reduce de 5 minutos a 6 segundos el tiempo de ejecución)
elif country_name == 'MÉXICO':
if iso == 'alpha_2':
return 'MX'
elif iso == 'alpha_3':
return 'MEX'
spanish = gettext.translation(
'iso3166', pycountry.LOCALES_DIR, languages=[language])
spanish.install()
_ = spanish.gettext
# check if country_name is in correccion_paises['nombre_original'] and correct it with correccion_paises['nombre_corregido']
if country_name in correccion_paises['nombre_original']:
country_name = correccion_paises['nombre_corregido'][correccion_paises['nombre_original'].index(country_name)]
if country_name in none_countries['nombre']:
if iso == 'alpha_2':
return none_countries['alpha2'][none_countries['nombre'].index(country_name)]
elif iso == 'alpha_3':
return none_countries['alpha3'][none_countries['nombre'].index(country_name)]
else:
for english_country in pycountry.countries:
country_name = country_name.lower()
spanish_country = _(english_country.name).lower()
if spanish_country == country_name:
if iso == 'alpha_3':
return english_country.alpha_3
elif iso == 'alpha_2':
return english_country.alpha_2
except Exception as e:
raise
Conversión de los nombres a códigos alpha
muestra_covid['alpha3'] = muestra_covid['pais_nacionalidad'].apply(lambda x: map_country_code(x, 'es', 'alpha_3'))
muestra_covid['alpha2'] = muestra_covid['pais_nacionalidad'].apply(lambda x: map_country_code(x, 'es', 'alpha_2'))
muestra_covid.head()
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
"""Entry point for launching an IPython kernel.
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:2: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
sexo | edad | entidad_nacimiento | municipio_residencia | indigena | nacionalidad | migrante | pais_nacionalidad | fecha_ingreso | fecha_sintomas | fecha_def | municipio_residencia | Lat_Decimal | Lon_Decimal | alpha3 | alpha2 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | MUJER | 75 | QUERÉTARO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-21 | 2022-02-16 | NaT | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
1 | MUJER | 32 | CIUDAD DE MÉXICO | naucalpan de juárez | NO ESPECIFICADO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-07 | 2022-01-02 | NaT | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
2 | HOMBRE | 30 | CIUDAD DE MÉXICO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-04 | 2022-02-03 | NaT | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
3 | MUJER | 51 | CIUDAD DE MÉXICO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-28 | NaT | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
4 | HOMBRE | 83 | GUANAJUATO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-30 | NaT | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
Guardar a CSV#
ruta = '/content/drive/MyDrive/Colab Notebooks/curso_datos/covid_clean.csv'
muestra_covid.to_csv(ruta, index=False)
comprobación
pd.read_csv(ruta)
sexo | edad | entidad_nacimiento | municipio_residencia | indigena | nacionalidad | migrante | pais_nacionalidad | fecha_ingreso | fecha_sintomas | fecha_def | municipio_residencia.1 | Lat_Decimal | Lon_Decimal | alpha3 | alpha2 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | MUJER | 75 | QUERÉTARO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-21 | 2022-02-16 | NaN | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
1 | MUJER | 32 | CIUDAD DE MÉXICO | naucalpan de juárez | NO ESPECIFICADO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-07 | 2022-01-02 | NaN | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
2 | HOMBRE | 30 | CIUDAD DE MÉXICO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-02-04 | 2022-02-03 | NaN | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
3 | MUJER | 51 | CIUDAD DE MÉXICO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-28 | NaN | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
4 | HOMBRE | 83 | GUANAJUATO | naucalpan de juárez | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-01-01 | 2021-12-30 | NaN | naucalpan de juárez | 19.478803 | -99.233218 | MEX | MX |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
158080 | HOMBRE | 12 | VERACRUZ DE IGNACIO DE LA LLAVE | amatlán de los reyes | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-23 | 2022-06-23 | NaN | amatlán de los reyes | 18.847578 | -96.915484 | MEX | MX |
158081 | MUJER | 46 | CIUDAD DE MÉXICO | amatlán de los reyes | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-22 | 2022-06-19 | NaN | amatlán de los reyes | 18.847578 | -96.915484 | MEX | MX |
158082 | MUJER | 59 | CIUDAD DE MÉXICO | general simón bolívar | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-23 | 2022-06-22 | NaN | general simón bolívar | 24.689074 | -103.225975 | MEX | MX |
158083 | MUJER | 27 | MÉXICO | temozón | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-24 | 2022-06-22 | NaN | temozón | 20.803680 | -88.201158 | MEX | MX |
158084 | MUJER | 32 | MÉXICO | izamal | NO | MEXICANA | NO ESPECIFICADO | MÉXICO | 2022-06-24 | 2022-06-20 | NaN | izamal | 20.932998 | -89.019715 | MEX | MX |
158085 rows × 16 columns
Visualización de datos#
Importar las librerías necesarias:
!pip install plotly
import plotly.express as px
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
Requirement already satisfied: plotly in /usr/local/lib/python3.7/dist-packages (5.5.0)
Requirement already satisfied: tenacity>=6.2.0 in /usr/local/lib/python3.7/dist-packages (from plotly) (8.0.1)
Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from plotly) (1.15.0)
Visualización de líneas#
Gráfico con los fallecimientos diarios totales en México durante el primer semestre de 2022:
Preparación de los datos
ruta_datos = '/content/drive/MyDrive/Colab Notebooks/curso_datos/covid_clean.csv'
datos_covid = pd.read_csv(ruta_datos)
datos_covid['decesos'] = datos_covid['fecha_def'].apply(lambda x: 1 if pd.notnull(x) else 0)
muertes_diarias = datos_covid.groupby('fecha_def')['decesos'].sum().reset_index(name='fallecidos_diarios')
muertes_diarias.head()
fecha_def | fallecidos_diarios | |
---|---|---|
0 | 2022-01-03 | 2 |
1 | 2022-01-04 | 1 |
2 | 2022-01-05 | 2 |
3 | 2022-01-06 | 3 |
4 | 2022-01-07 | 7 |
“Dibujar” el gráfico
fig = px.line(muertes_diarias, x='fecha_def', y='fallecidos_diarios')
fig.update_layout(
title="Muertes diarias por COVID-19 en México",
xaxis_title="Fecha",
yaxis_title="Muertes diarias",
font=dict(
family="Roboto, monospace",
size=18,
color="#7f7f7f" # <-- el color de la fuente se puede definir con un código hexadecimal. Para conocer más sobre los códigos de colores, puedes consultar https://htmlcolorcodes.com/es/
)
)
# color de línea y ancho
fig.update_traces(line_color='#ff7f0e', line_width=2)
fig.show()
Visualización de dispersión apilada (multigráfico)#
Preparar la información. Un dataframe para cada gráfico:
hipertension = covid_nacional.loc[(covid_nacional['hipertension'] == 'SI') & (covid_nacional['fecha_def'].notnull())]
cardiovascular = covid_nacional.loc[(covid_nacional['cardiovascular'] == 'SI') & (covid_nacional['fecha_def'].notnull())]
renal_cronica = covid_nacional.loc[(covid_nacional['renal_cronica'] == 'SI') & (covid_nacional['fecha_def'].notnull())]
tabaquismo = covid_nacional.loc[(covid_nacional['tabaquismo'] == 'SI') & (covid_nacional['fecha_def'].notnull())]
Agrupar cada dataframe:
# agrupar por edad y fecha de defunción
hipertension = hipertension.groupby(['edad', 'hipertension']).size().reset_index(name='count')
cardiovascular = cardiovascular.groupby(['edad', 'cardiovascular']).size().reset_index(name='count')
renal_cronica = renal_cronica.groupby(['edad', 'renal_cronica']).size().reset_index(name='count')
tabaquismo = tabaquismo.groupby(['edad', 'tabaquismo']).size().reset_index(name='count')
Crear un gráfico de dispersión para cada grupo:
from plotly.subplots import make_subplots
import plotly.graph_objects as go
fig = make_subplots(rows=2, cols=2, subplot_titles=("Hipertensión", "Enfermedad cardiovascular", "Enfermedad renal crónica", "Tabaquismo"))
fig.add_trace(go.Scatter(x=hipertension['edad'], y=hipertension['count'], mode='markers'), row=1, col=1)
fig.add_trace(go.Scatter(x=cardiovascular['edad'], y=cardiovascular['count'], mode='markers'), row=1, col=2)
fig.add_trace(go.Scatter(x=renal_cronica['edad'], y=renal_cronica['count'], mode='markers'), row=2, col=1)
fig.add_trace(go.Scatter(x=tabaquismo['edad'], y=tabaquismo['count'], mode='markers'), row=2, col=2)
fig.update_layout(height=600, width=800, title_text="Relación entre edad, número de decesos y enfermedades preexistentes")
# actualizar los ejes
for i in range(1, 3):
fig.update_yaxes(title_text="Número de decesos", row=1, col=i)
fig.update_yaxes(title_text="Número de decesos", row=2, col=i)
fig.update_xaxes(title_text="Edad", row=1, col=i)
fig.update_xaxes(title_text="Edad", row=2, col=i)
fig.show()
Mapa#
Mapa de índices de incidencia (casos por cada 100,000 habitantes) en México durante el segundo semestre de 2022:
Preparar los datos:
# recuperar los datos originales para evitar errores
casos_nacionales = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/curso_datos/casos_nacionales_covid-19_2022_semestre1.csv')
geolocalizacion = pd.read_csv("/content/drive/MyDrive/Colab Notebooks/curso_datos/geolocalizacion.csv", encoding='utf-8')
# determinar casos por municipio de residencia
casos_nacionales = casos_nacionales['municipio_res'].value_counts().reset_index()
casos_nacionales.columns = ['municipio_res', 'casos']
casos_nacionales.rename(columns={'municipio_res': 'municipio_residencia'}, inplace=True)
casos_nacionales['municipio_residencia'] = casos_nacionales['municipio_residencia'].str.lower()
casos_nacionales = casos_nacionales.merge(geolocalizacion, on='municipio_residencia', how='left')
# limpieza de datos
casos_nacionales.drop(columns=['Unnamed: 0'], inplace=True)
casos_nacionales = casos_nacionales.dropna()
# agregar población total
areas = areas_inegi[['municipio_residencia', 'Lat_Decimal', 'Lon_Decimal', 'Pob_Total']]
areas['municipio_residencia'] = areas['municipio_residencia'].str.lower()
nuevodata = pd.merge(casos_nacionales, areas, on=['municipio_residencia', 'Lat_Decimal', 'Lon_Decimal'], how='inner')
# convertir Pob_Total a integral
nuevodata['Pob_Total'] = nuevodata['Pob_Total'].astype(int)
# calcular tasa de incidencia
nuevodata['tasa_incidencia'] = nuevodata['casos'] / nuevodata['Pob_Total'] * 100000
nuevodata.head()
/usr/local/lib/python3.7/dist-packages/IPython/core/interactiveshell.py:3326: DtypeWarning:
Columns (13) have mixed types.Specify dtype option on import or set low_memory=False.
/usr/local/lib/python3.7/dist-packages/ipykernel_launcher.py:21: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
municipio_residencia | casos | Lat_Decimal | Lon_Decimal | Pob_Total | tasa_incidencia | |
---|---|---|---|---|---|---|
0 | nezahualcóyotl | 26282 | 19.408763 | -99.018200 | 1072676 | 2450.134057 |
1 | ecatepec de morelos | 24107 | 19.599069 | -99.049159 | 1643623 | 1466.698872 |
2 | tlalnepantla de baz | 17929 | 19.538523 | -99.195198 | 658907 | 2721.021328 |
3 | naucalpan de juárez | 10020 | 19.478803 | -99.233218 | 776220 | 1290.871145 |
4 | chalco | 6997 | 19.261132 | -98.895655 | 174704 | 4005.059987 |
Dibujar el mapa:
fig = px.scatter_mapbox(
nuevodata,
lat="Lat_Decimal",
lon="Lon_Decimal",
color='tasa_incidencia',
size='tasa_incidencia',
hover_name="municipio_residencia",
hover_data=["casos", "Pob_Total", "tasa_incidencia"],
color_continuous_scale=px.colors.cyclical.IceFire,
size_max=50,
zoom=4
)
fig.update_layout(mapbox_style="open-street-map")
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
Mapa animado#
Mapa animado del país de origen de los casos diarios de extranjeros:
Preparar los datos:
# segmentar información para excluir casos mexicanos
mapa_extranjeros = muestra_covid.loc[muestra_covid['alpha3'] != 'MEX']
# limpiar datos que no se pudieron convertir
extranjeros = mapa_extranjeros.dropna(subset=['alpha3'])
# agrupar por pais_nacionalidad, alpha3 y alpha2
diario = extranjeros.groupby(['fecha_ingreso', 'pais_nacionalidad', 'alpha3', 'alpha2']).count().reset_index()
# renombrar columna sexo como casos
diario.rename(columns={'sexo': 'casos'}, inplace=True)
# eliminar columnas no necesarias
diario.drop(columns=['edad','entidad_nacimiento','municipio_residencia','indigena','nacionalidad','migrante', 'fecha_sintomas','fecha_def', 'Lat_Decimal', 'Lon_Decimal'], inplace=True)
# garantizar que fecha_ingreso sea datetime
diario['fecha_ingreso'] = diario['fecha_ingreso'].dt.strftime('%d/%m/%Y')
diario.head()
fecha_ingreso | pais_nacionalidad | alpha3 | alpha2 | casos | |
---|---|---|---|---|---|
0 | 02/01/2022 | REPÚBLICA DE COREA | KOR | KR | 1 |
1 | 03/01/2022 | ALEMANIA | DEU | DE | 1 |
2 | 03/01/2022 | COLOMBIA | COL | CO | 1 |
3 | 03/01/2022 | ECUADOR | ECU | EC | 1 |
4 | 03/01/2022 | ESTADOS UNIDOS DE AMÉRICA | USA | US | 2 |
Dibujar mapa
fig = px.choropleth(diario, locations="alpha3", color="casos", hover_name="pais_nacionalidad", projection="natural earth", animation_frame="fecha_ingreso", color_continuous_scale=px.colors.sequential.Plasma)
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
¿Qué aprendimos del Covid-19 con estos datos?#
Después del ejercicio de “machacar” los datos proporcionados por el gobierno de México, notamos que estamos llegando a una etapa de la pandemia mucho más controlada. Aunque los fallecimientos derivados de la enfermedad se incrementaron durante el mes de febrero, es claro que no alcanzó el nivel de meses críticos del año 2021 o 2020.
Los contagios fueron bastante altos en casi todas las poblaciones, mostrando que hay una concentración natural de contagios en el área del centro de México, donde se agrupa la mayor población del país. Aunque también es evidente una cantidad importante de casos en el norte del país, especialmente en los estados de Zacatecas, Nuevo León y Tamaulipas.
La cantidad de extranjeros que reportaron su contagio en México (esto no indica que se hayan infectado en el país o en el exterior) es significativa, con más de 10,000 casos, aunque la gran mayoría de estos se presentó con viajeros provenientes de Estados Unidos. No es por tanto factible en ningún caso considerar que la migración hacia o a través del país tenga correlación alguna con la distribución del virus.
Los datos no nos permiten corroborar la incidencia de las campañas de vacunación global en el apaciguamiento de la pandemia, pero no es descabellado adelantar tal hipótesis.
Sin duda una comparación de mayor calado (tomando los datos de 2019 hasta la fecha, por ejemplo) brindará mayores luces respecto al comportamiento de la pandemia en México.
Sigámonos cuidando 🙌