{
"cells": [
{
"cell_type": "markdown",
"id": "8f0cf25d",
"metadata": {},
"source": [
"# Bases para la visualización de datos\n",
"\n",
"Como bien subrayan Dougherty e Ilyankou {cite}`dougherty_hands-data_2021` la clave de nuestras visualizaciones consiste en comparar dos o más variables. Por ejemplo, cantidad de contagios y tiempo; o defunciones y sexo. Decidir qué variables comparamos es relevante porque nos da la pauta para elegir el tipo de visualización que mejor se adapta a nuestro objetivo.\n",
"\n",
"Aunque ya tengamos nuestros datos limpios, tendremos que realizar algunas operaciones para poderlos comparar. Esto es, requeriremos sumar, promediar, contar, hacer porcentajes, entre otras operaciones.\n",
"\n",
"Afortunadamente, al ser acciones tan comunes, la mayoría de programas que trabajan con datos incluyen procesos para hacer esos cálculos. Te mostraremos algunos ejemplos de operaciones que podemos realizar con los datos de la pandemia que hemos limpiado anteriormente.\n",
"\n",
"Notarás que no son los únicos cálculos posibles y que tal vez podríamos realizar otros si no hubiésemos descartados algunas columnas previamente. Esto es algo común en el análisis de datos. Tendrás que segmentar, ampliar o reducir tus datos, en el camino, tendrás que tomar decisiones que te ayudarán a enfocar tu análisis y no será extraño que regreses al conjunto de datos original para realizar nuevas operaciones.\n",
"\n",
"## Sumar\n",
"\n",
"Esta es una operación aritmética sumamente común. Por ejemplo, podemos querer establecer la cantidad de defunciones por día. Para ello, vamos a necesitar modificar nuestros datos para incluir un valor de 1 en cada fila donde se haya registrado un deceso (fecha_def):"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "a9179ba0",
"metadata": {
"tags": [
"remove-cell"
]
},
"outputs": [],
"source": [
"ruta_datos = '../data/covid_clean.csv'"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "bb1dd844",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"datos_covid = pd.read_csv(ruta_datos)\n",
"datos_covid['decesos'] = datos_covid['fecha_def'].apply(lambda x: 1 if pd.notnull(x) else 0)"
]
},
{
"cell_type": "markdown",
"id": "0e3bef43",
"metadata": {},
"source": [
"Ahora, podremos agrupar por fecha y sumar las muertes:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "96692374",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" fecha_def | \n",
" fallecidos_diarios | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" 2022-01-03 | \n",
" 2 | \n",
"
\n",
" \n",
" 1 | \n",
" 2022-01-04 | \n",
" 1 | \n",
"
\n",
" \n",
" 2 | \n",
" 2022-01-05 | \n",
" 2 | \n",
"
\n",
" \n",
" 3 | \n",
" 2022-01-06 | \n",
" 3 | \n",
"
\n",
" \n",
" 4 | \n",
" 2022-01-07 | \n",
" 7 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" fecha_def fallecidos_diarios\n",
"0 2022-01-03 2\n",
"1 2022-01-04 1\n",
"2 2022-01-05 2\n",
"3 2022-01-06 3\n",
"4 2022-01-07 7"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"muertes_diarias = datos_covid.groupby('fecha_def')['decesos'].sum().reset_index(name='fallecidos_diarios')\n",
"muertes_diarias.head()"
]
},
{
"cell_type": "markdown",
"id": "6f51df1f",
"metadata": {},
"source": [
"## Promedio\n",
"\n",
"Por ejemplo, un dato interesante que podríamos querer reconocer es el promedio de edad de las personas contagiadas por Covid-19 en el primer semestre de 2022. Aunque técnicamente podemos hacer este cálculo por nuestra cuenta (sumar todas las edades y dividir por el número de personas), es más fácil que `pandas` lo haga por nosotros."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "e3ae81b6",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"36.94687035455609"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"datos_covid['edad'].mean()"
]
},
{
"cell_type": "markdown",
"id": "2b04814d",
"metadata": {},
"source": [
"Aquí estamos realizando un cálculo de promedio bastante simple (la cantidad por el total de elementos). Ahora, supongamos que queremos saber el promedio de edad por sexo:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "c71c950d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"sexo\n",
"HOMBRE 36.796708\n",
"MUJER 37.094279\n",
"Name: edad, dtype: float64"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"promedio_es = datos_covid.groupby('sexo')['edad'].mean()\n",
"promedio_es"
]
},
{
"cell_type": "markdown",
"id": "df55056b",
"metadata": {},
"source": [
"Como vemos es prácticamente indistinta la edad de mujeres y hombres con relación a sus contagios, esto podría indicar que no existe una correlación entre edad, sexo y contagio."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "2a1550b4",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"HOMBRE -0.008921\n",
"MUJER 0.008921\n",
"dtype: float64"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"c_corr = datos_covid.sexo.str.get_dummies().corrwith(datos_covid.edad)\n",
"c_corr"
]
},
{
"cell_type": "markdown",
"id": "29439a7f",
"metadata": {},
"source": [
"El resultado de la correlación entre edad y sexo es prácticamente cero, muy alejada de cualquier valor que indique una correlación fuerte.\n",
"\n",
"## Porcentaje\n",
"\n",
"También podríamos calcular el porcentaje de infectados por país de origen (excluyendo México, obviamente):"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "1bcd53b8",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" pais | \n",
" porcentaje | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" estados unidos de américa | \n",
" 39.560440 | \n",
"
\n",
" \n",
" 1 | \n",
" venezuela | \n",
" 8.131868 | \n",
"
\n",
" \n",
" 2 | \n",
" colombia | \n",
" 5.714286 | \n",
"
\n",
" \n",
" 3 | \n",
" argentina | \n",
" 5.274725 | \n",
"
\n",
" \n",
" 4 | \n",
" cuba | \n",
" 5.274725 | \n",
"
\n",
" \n",
" 5 | \n",
" otro | \n",
" 3.956044 | \n",
"
\n",
" \n",
" 6 | \n",
" españa | \n",
" 3.956044 | \n",
"
\n",
" \n",
" 7 | \n",
" república de honduras | \n",
" 2.857143 | \n",
"
\n",
" \n",
" 8 | \n",
" chile | \n",
" 2.417582 | \n",
"
\n",
" \n",
" 9 | \n",
" brasil | \n",
" 2.197802 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" pais porcentaje\n",
"0 estados unidos de américa 39.560440\n",
"1 venezuela 8.131868\n",
"2 colombia 5.714286\n",
"3 argentina 5.274725\n",
"4 cuba 5.274725\n",
"5 otro 3.956044\n",
"6 españa 3.956044\n",
"7 república de honduras 2.857143\n",
"8 chile 2.417582\n",
"9 brasil 2.197802"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"datos_covid['pais_nacionalidad'] = datos_covid['pais_nacionalidad'].str.lower()\n",
"porcentaje_pais = datos_covid[datos_covid.pais_nacionalidad != 'méxico'].groupby('pais_nacionalidad').size() / datos_covid[datos_covid.pais_nacionalidad != 'méxico'].shape[0] * 100\n",
"# nombrar las columnas\n",
"porcentaje_pais.name = 'porcentaje'\n",
"porcentaje_pais.index.name = 'pais'\n",
"# ordenar por porcentaje\n",
"porcentaje_pais = porcentaje_pais.reset_index()\n",
"porcentaje_pais.sort_values(by='porcentaje', ascending=False, inplace=True)\n",
"porcentaje_pais.reset_index(drop=True, inplace=True)\n",
"porcentaje_pais[:10]"
]
},
{
"cell_type": "markdown",
"id": "961bd8a8",
"metadata": {},
"source": [
"Ahora, hagamos el cálculo del porcentaje de contagios por país de origen teniendo en cuenta el tipo de migrante."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "1c7fa119",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" pais_nacionalidad | \n",
" SI | \n",
" NO | \n",
" NO ESPECIFICADO | \n",
"
\n",
" \n",
" \n",
" \n",
" 0 | \n",
" estados unidos de américa | \n",
" 31.2500 | \n",
" 41.208791 | \n",
" 37.037037 | \n",
"
\n",
" \n",
" 1 | \n",
" cuba | \n",
" 12.5000 | \n",
" 4.120879 | \n",
" 3.703704 | \n",
"
\n",
" \n",
" 2 | \n",
" venezuela | \n",
" 10.9375 | \n",
" 7.967033 | \n",
" 3.703704 | \n",
"
\n",
" \n",
" 3 | \n",
" república de honduras | \n",
" 7.8125 | \n",
" 1.648352 | \n",
" 7.407407 | \n",
"
\n",
" \n",
" 4 | \n",
" colombia | \n",
" 7.8125 | \n",
" 4.670330 | \n",
" 14.814815 | \n",
"
\n",
" \n",
" 5 | \n",
" argentina | \n",
" 3.1250 | \n",
" 6.043956 | \n",
" 0.000000 | \n",
"
\n",
" \n",
" 6 | \n",
" haití | \n",
" 3.1250 | \n",
" 0.549451 | \n",
" 0.000000 | \n",
"
\n",
" \n",
" 7 | \n",
" guatemala | \n",
" 3.1250 | \n",
" 1.098901 | \n",
" 0.000000 | \n",
"
\n",
" \n",
" 8 | \n",
" españa | \n",
" 3.1250 | \n",
" 4.120879 | \n",
" 3.703704 | \n",
"
\n",
" \n",
" 9 | \n",
" canadá | \n",
" 3.1250 | \n",
" 1.373626 | \n",
" 3.703704 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" pais_nacionalidad SI NO NO ESPECIFICADO\n",
"0 estados unidos de américa 31.2500 41.208791 37.037037\n",
"1 cuba 12.5000 4.120879 3.703704\n",
"2 venezuela 10.9375 7.967033 3.703704\n",
"3 república de honduras 7.8125 1.648352 7.407407\n",
"4 colombia 7.8125 4.670330 14.814815\n",
"5 argentina 3.1250 6.043956 0.000000\n",
"6 haití 3.1250 0.549451 0.000000\n",
"7 guatemala 3.1250 1.098901 0.000000\n",
"8 españa 3.1250 4.120879 3.703704\n",
"9 canadá 3.1250 1.373626 3.703704"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from functools import reduce # vamos a aprovechar la función reduce para hacer un merge de los dataframes\n",
"\n",
"tipos_migracion = ['SI', 'NO', 'NO ESPECIFICADO']\n",
"\n",
"# Esta es una larga lista de acciones que están escritas de una manera sintética\n",
"\n",
"# 1. Filtrar por tipo de migración\n",
"dfs = [datos_covid[(datos_covid.migrante == tipo) & (datos_covid.pais_nacionalidad != 'méxico')].groupby('pais_nacionalidad').size() / datos_covid[(datos_covid.migrante == tipo) & (datos_covid.pais_nacionalidad != 'méxico')].shape[0] * 100 for tipo in tipos_migracion]\n",
"\n",
"# 2. Renombrar las columnas\n",
"dfsname = []\n",
"\n",
"for df, tipo in zip(dfs, tipos_migracion):\n",
" df.name = tipo\n",
" df.index.name = 'pais_nacionalidad'\n",
" df = df.reset_index()\n",
" df.sort_values(by=tipo, ascending=False, inplace=True)\n",
" df.reset_index(drop=True, inplace=True)\n",
" dfsname.append(df)\n",
"\n",
"# 3. Unir los dataframes\n",
"porcentaje_pais = reduce(lambda left, right: pd.merge(left, right, on='pais_nacionalidad', how='outer'), dfsname)\n",
"porcentaje_pais.fillna(0, inplace=True)\n",
"porcentaje_pais.sort_values(by='SI', ascending=False, inplace=True)\n",
"porcentaje_pais.reset_index(drop=True, inplace=True)\n",
"porcentaje_pais[:10]"
]
},
{
"cell_type": "markdown",
"id": "d4ac0f74",
"metadata": {},
"source": [
"Ahora tenemos un escenario más preciso. Ya no sabemos solamente cuántos contagios tenemos por país de origen, sino tenemos un valor que representa cuál es el porcentaje de cada uno de estas nacionalidad en el conjunto general de extranjeros. Además, podemos contrastar entre aquellos que son migrantes y aquellos que simplemente están de visita, o que no lo especificaron.\n",
"\n",
"En esta tabla tenemos el dato ordenado por migrantes y solamente incluye el top 10 de países de origen. Pero hay sutilezas que podríamos explorar con mayor detalle, por ejemplo, de cuáles países se contagiaron mayor cantidad de visitantes que de migrantes, cuál es el orden de nacionalidad no especificada, etc. Es aquí donde la visualización de datos puede ayudarnos a entender mejor estas relaciones.\n",
"\n",
"## En síntesis\n",
"\n",
"Como verás, estas operaciones pueden ser más o menos complejas, dependiendo de los datos que tenemos disponibles y de lo que queremos hacer con ellos. Aunque estas líneas de código pueden ser ilegibles por momentos, es importante tener en cuenta que `pandas` es una herramienta muy poderosa que nos permite hacer análisis de datos de una manera muy sencilla.\n",
"\n",
"Te recomiendo que intentes replicar algunos de los ejemplos que hemos visto aquí y que te desafíes a hacer tus propios análisis de datos.\n",
"\n",
"¡Adelante!"
]
}
],
"metadata": {
"jupytext": {
"cell_metadata_filter": "-all",
"formats": "md:myst",
"text_representation": {
"extension": ".md",
"format_name": "myst",
"format_version": 0.13,
"jupytext_version": "1.14.0"
}
},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.7"
},
"source_map": [
14,
30,
35,
39,
43,
46,
52,
54,
58,
61,
65,
68,
76,
87,
91,
118
]
},
"nbformat": 4,
"nbformat_minor": 5
}