Este notebook tiene como objetivo la creación de una historia a partir del análisis y visualización de un conjunto de datos. El seleccionado ofrece información epidemiológica del Covid - 19: los casos confirmados y tasas de incidencia acumulada (TIA) para población de 60 y más años de edad del municipio de Alcobendas. Para ello, nos serviremos de un Informe semanal en formato CSV con datos para la población de 60 y más años de edad de casos confirmados y tasas de incidencia acumulada de los últimos 14 días y desde el inicio de la pandemia hasta el 29 de marzo. La fuente de los datos es Red de Vigilancia Epidemiológica de la Comunidad de Madrid.
NOTA: el archivo recoge los datos pertinentes hasta su fecha de publicación, a saber, el 29 de marzo de 2022. Todas las categorías de datos son correspondientes hasta esa fecha, por ejemplo incidencia acumulada en los últimos 14 días y similares. Es necesairo tener esto en cuenta a la hora de leer e interpretar los datos ya que no siempre que se haga referencia a la temporalidad podrá ser esto indicado, por lo que téngase en cuenta implícitamente en el resto del documento desde este párrafo.
En primer lugar, necesitamos instalar la librería Pandas, una biblioteca de software escrita como extensión de NumPy para manipulación y análisis de datos para el lenguaje de programación Python. Sus estructuras de datos y operaciones nos permitirán manipular tablas numéricas y series temporales, interesante para trabajar con nuestro conjunto de datos (CSV). Para ello !pip install ()
:
!pip install pandas
En segundo lugar, una vez instalada, procedemos a configurarla. La hemos instalado, pero necesitamos importarla para trabajar con su lenguaje en este documento. Lo hacemos con la abreviación pd
de la siguiente manera:
import pandas as pd
Una vez tenemos preparada la librería, en tercer lugar, debemos decirle a Python cuáles son los datos con los que vamos a trabajar. En este caso se trata de un archivo CSV. El nombre que daremos a esta variable será url
puesto que es el link del archivo CSV, extraído de los conjuntos de datos abiertos facilitados por el gobierno. Lo hacemos con el signo =
para generar la variable y las ""
para indicar que se trata de un link.
url = "https://datos.alcobendas.org/dataset/e841a91e-a7d8-4bd8-977c-f842169cd04e/resource/be4732de-a69a-48c2-849a-be8130a9f64f/download/recurso.csv"
En cuarto lugar, una vez tenemos preparadas la librería y la variable con las que vamos a trabajar necesitamos traer los datos al presente cuaderno para proceder a su análisis y manipulación de presentación. Lo hacemos creando una tabla, denominada dataframe, que nos mostrará los datos en bruto en forma de tabla con los que vamos a trabajar.
Para ello necesitamos que Pandas lea los datos de la variable definida. Utilizamos la siguiente función que nos ofrece la librería: pd.read_csv
(archivo). Creamos una variable denominada Dataframe (df) con los datos del archivo CSV contenidos en la varible url, leídos a través de la función recién mencionada para poder referirnos a ella en el resto del documento. El resultado de esta sintaxis es el siguiente:
df = pd.read_csv(url)
df
Este dataframe supone un primer acercamiento a los datos pero es insuficiente para su comprensión. Apreciamos que contiene 1090 filas, a saber, zonas básicas de salud del Ayuntamiento de Alcobendas, de las que nos muestra las 5 primeras y las 5 últimas. De cada una de ellas nos presenta en las 10 columnas una serie de datos. De su visualización podemos decidir qué categorías nos resultan pertinentes para nuestra historia: casos confirmados, tasa de incidencia acumulada en los últimos 14 días, los casos confirmados totales y la tasa de incidencia acumulada total de las personas de 60 años de edad en adelante desde el inicio de la pandemia hasta el 29 de marzo de este año.
Al Dataframe (df) le ponemos el .
para aplicarle una función. Comenzamos por lo elemental. La función .info
nos explica qué hay en el dataframe (df) por categorías.
df.info()
Si queremos conocer de manera exclusiva las columnas que tiene nuestra tabla ponemos df.columns
.
df.columns
Al visualizar el contenido de esta manera resulta más fácil la selección anteriormente realizada de las categorías que nos interesan.
Si queremos centrarnos en los valores numéricos utilizamos la función .describe()
, que nos ofrece el recuento de los datos que queramos, la media, la mínima la desviación típica...etc.
df.describe()
Así, podemos saber que en el municipio de Alcobendas hubo 766 casos de Covid-19 confirmados de personas iguales o mayores de 60 años en los últimos 14 días de marzo y un total de 1.005.000 desde el inicio de la pandemia.
NOTA: es necesario puntualizar que, dado que los datos son acumulados, el recuento de los mismos no es fidedigno. Como se mostrará posteriormente al sumar individualmente las etiquetas que seleccionemos, el total de contagios en los dos años en Alcobendas para las personas iguales o mayores de 60 años es de 29.695 y en los últimos 14 días de 277 casos.
Para conocer las primeras zonas sanitariarias de Alcobendas que presenta la tabla, utilizamos la función .head
. Para conocer las últimas, nos servimos de la función .tail
. A continuación especificamos entreparéntesis () el número de zonas que queremos visualizar. En este caso indicamos 10 para tener más información que la que mostraba la visualización del dataframe y tener una mayor amplitud de visión sobre los datos.
df.head (10)
df.tail (10)
Para poder preguntar a Python por alguna zona sanitara en concreto primero necesito poder conocerlas todas. Para ello es interesante esta función porque permite introducir intervalos, como se muestra a continuación.
df.head(0-545)
df.tail(546-1090)
A continuación resulta de interés centrarnos en una categoría para ver los demás datos a partir de ella. Para lo cual necesimaos establecerla como íncide. Lo hacemos así: set_index('columna que queramos')
.
df.set_index('Casos confirmados en los ultimos 14 días')
Para visualizar el conjunto de datos de esta categoría de manera exclusiva y sin reiteraciones utilizamos la función .unique()
tras especificar entre corchetes y comillas simples ['']
tras df
el nombre de la columna que queremos. Así:
df['Casos confirmados en los ultimos 14 días'].unique()
Para el caso que nos ocupa esta función resulta especialmente útil para conocer el listado completo de zonas sanitarias para poder identificar cada una de ellas con una fila y número de la tabla y ampliar las posibilidades de manejar y extraer los datos.
df['Zona básica de salud']
df['Zona básica de salud'].unique()
Vemos así que solo hay 5 zonas sanitarias. Aunque para el caso no es muy relevante, podemos conocer el dato para una categoría de una zona sanitaria concreta de la siguiente manera:['nombredelacolumna'] [númerodelafila]
. Nos proponemos conocer el número de casos totales confirmados en la zona sanitaria que ocupe la posición de la mitad en la tabla.
df['Casos confirmados totales'] [545]
df['Zona básica de salud'] [545]
Sabríamos así que la zona sanitaria Chopera de Alcobendas ha tenido 178 casos de Covid-19 confirmados en la segunda quincena de marzo, además de que esta zona ocupa entre otras la fila número 545 de la tabla. De esta forma, con las funciones presentadas podemos ir extrayendo del dataframe los datos que queramos.
A continuación resulta interesante combinar las columnas en las que nos fijamos en un principio para profundizar en estos datos y poder alterar su visualización. Para ello retomamos la función set_index()
con las categorías escogidas. En otras palabras, combinaremos las funciones recién utilizadas para poder agrupar la información y trabajar con las variables de manera conjunta. Para diferenciar la cronología trabajaremos por un lado con los datos relativos a los últimos 14 días hasta el 29 de marzo, y por otro con los números totales desde el inicio de la pandemia. Todo ello hasta el 29 de marzo y sobre las personas de 60 o más años en Alcobendas.
df.set_index('Zona básica de salud')['Casos confirmados en los ultimos 14 días']
Para poder pintar estos datos y representarlos en un gráfico simplemente añadimos .plot()
al final de la función anterior.
df.set_index('Zona básica de salud')['Casos confirmados en los ultimos 14 días'].plot()
Con la función .plot(title="títulográfica")
titulamos el gráfico y los que realicemos a continuación.
df.set_index('Zona básica de salud')['Casos confirmados en los ultimos 14 días'].plot(title="Casos de Covid-19 confirmados en los últimos 14 días")
df.set_index('Zona básica de salud')['Casos confirmados totales']
df.set_index('Zona básica de salud')['Casos confirmados totales'].plot(title="Casos confirmados totales")
Realizamos la misma operación con la tasa de incidencia. Primero de los últimos 14 días (hasta la fecha de publicación del informe) y luego total desde el inicio de la pandemia.
df.set_index('Zona básica de salud')['Tasa de incidencia acumulada en los últimos 14 días']
df.set_index('Zona básica de salud')['Tasa de incidencia acumulada en los últimos 14 días'].plot(title="Tasa de incidencia acumulada en los últimos 14 días")
df.set_index('Zona básica de salud')['Tasa de incidencia acumulada total']
df.set_index('Zona básica de salud')['Tasa de incidencia acumulada total'].plot(title="Tasa total de incidencia acumulada")
df['fecha informe']
df.set_index('fecha informe')['Casos confirmados totales']
df.set_index('fecha informe')['Casos confirmados totales'].plot()
Para poder solventar el problema de las etiquetas y que el resultado sea mucho más limpio para construir una historia, podemos prescindir del dataframe e introducir, puesto que son pocos, manualmente en la sintaxis correspondiente los datos a representar. Para el caso puede ser interesante un gráfico de barras horizonal con los siguientes datos:
df.set_index('Zona básica de salud')['Casos confirmados totales']
Para ello necesitamos importar la librería matplotlib.pyplot
.
import matplotlib.pyplot as plt
Declaramos valores para el eje x
, en este caso categorias.
eje_x = ['La Chopera', 'La Moraleja', 'Marqués de la Valdavia', 'Miraflores', 'Valdelasfuentes']
Definimos los valores para el eje y
, es decir, los valores.
eje_y = [7.715,5.911,4.181,5.940,5.948]
Por último, creamos la gráfica y ponemos las barras del color que queramos, el naranja en este caso.
plt.barh(eje_x, eje_y, color="orange")
plt.ylabel('Zonas sanitarias')
plt.xlabel('Casos confirmados totales')
plt.title('Casos de Covid-19 en personas de 60 o más años de edad en Alcobendas')
plt.show()
Repetimos el proceso con los casos confirmados en los últimos 14 días.
eje_x = ['La Chopera', 'La Moraleja', 'Marqués de la Valdavia', 'Miraflores', 'Valdelasfuentes']
eje_y = [50,66,55,41,65]
plt.barh(eje_x, eje_y, color="pink")
plt.ylabel('Zonas sanitarias')
plt.xlabel('Casos confirmados totales')
plt.title('Casos de Covid-19 en personas de 60 o más años de edad en Alcobendas')
plt.show()
Por último es interesante conocer los totales de estos gráficos. Para salvar el problema de recuento acumulado que supone una elevación multiplicada de los casos introducimos las cifras para que Python los sume. En primer lugar recontaremos los casos desde el inicio de la pandemia y en segundo lugar los relativos a los últimos 14 días.
7.715+5.911+4.181+5.940+5.948
50+66+55+41+65
A continuación nos proponemmos representar geográficamente las 5 zonas sanitarias de Alcobendas para poder visualizarlas. Para ello necesitamos la librería folium
, útil para la creación de mapas web interactivos con Python. Para ello repetimos el proceso anterior: instalación e importación de librería, definición de variables e introducción de funciones.
Empezamos preparando la librería folium con la sintaxis utilizada anteriormente para Pandas: !pip install folium
y import folium
.
!pip install folium
import folium
Como en el proceso anterior con la librería Pandas, una vez preparada la librería necesitamos definir la variable con la que vamos a trabajar. Podría ser oportuno también crear la variable url
para introducir en la librería Folium la base de datos que manejamos, pero en este caso no es necesario. Por lo que definimos la variable geo
con las coordenadas del lugar a representar.
geo = [40.5475,-3.64209]
Una vez definida la variable es el momento de introducir funciones. La librería Folium cuenta con la función .Map()
, para la representación de un mapa. Le decimos que la localización de las coordenadas a representar son las definidas en la variable geo
, y esta sintaxis la asociamos a la variable mapa
para establecer que cada vez que pongamos en este notebook dicha palabra, Python dibuje el mapa de Alcobendas.
mapa = folium.Map(location=geo)
mapa
Pero realmente este mapa es demasiado amplio para aportar información. Necesitamos bajar a las calles. Para ello es interesante el estilo de mapa Stamen Toner, que en blanco y negro nos muestra las calles de las coordenadas introducidas. Para ello necesitamos añadir a la sintaxis anterior tiles='Stamen Toner', zoom_start=x
. Así nos permite mostrar el mapa con el zoom que determiemos. Para el caso he escogido 16.
folium.Map(
location=[40.5475,-3.64209],
tiles='Stamen Toner',
zoom_start=16
)
Pero este mapa sigue sin enseñarnos un punto concreto. Nos interesa poder marcar puntos en él para reconocer las diferentes zonas sanitarias de Alcobendas. Para ello utilizamos la función de folium .Marquer
que cuenta con el atributo popup
que nos permirte ver el nombre de la calle al posicionarnos en un punto. Para ver mejor esto nos interesa otro estilo de mapa diferente al anterior, uno que no distinga las calles en el terreno, así que introducimos el tipo Stamen Terrain en la definición de tiles
. Folium.Marker
además nos permite elegir un texto para cada punto señalado al deslizar el cursor. Así, tras el comando tooltip
ponemos el nombre de la zona sanitaria.
m = folium.Map(location=[40.5475,-3.64209],
zoom_start=13,
tiles='Stamen Terrain')
tooltip ='La Chopera'
folium.Marker([ 40.5358796 , -3.7016036], popup='La Chopera', tooltip=tooltip).add_to(m)
tooltip = 'La Moraleja'
folium.Marker([40.531936 , -3.635167], popup='La Moraleja', tooltip=tooltip).add_to(m)
tooltip = 'Marqués de la Valdavia'
folium.Marker([40.541 , -3.6374], popup='Marqués de la Valdavia', tooltip=tooltip).add_to(m)
tooltip = 'Miraflores'
folium.Marker([40.5358796, -3.7016036], popup='Miraflores', tooltip=tooltip).add_to(m)
tooltip = 'Valdelasfuentes'
folium.Marker([40.547425 , -3.654149], popup='Valdelasfuentes', tooltip=tooltip).add_to(m)
m
El resultado es este. No entiendo por qué La Chopera no sale representada. Puede ser interesante de nuevo recuperar el estilo de mapa sobre las calles y que en la zona zanitaria aparezca también el número de contagios totales.
m = folium.Map(location=[40.5475,-3.64209],
zoom_start=13,
tiles='Stamen Toner')
tooltip ='La Chopera, 7.715'
folium.Marker([ 40.5358796 , -3.7016036], popup='La Chopera', tooltip=tooltip).add_to(m)
tooltip = 'La Moraleja, 5.911'
folium.Marker([40.531936 , -3.635167], popup='La Moraleja', tooltip=tooltip).add_to(m)
tooltip = 'Marqués de la Valdavia, 4.181'
folium.Marker([40.541 , -3.6374], popup='Marqués de la Valdavia', tooltip=tooltip).add_to(m)
tooltip = 'Miraflores, 5.940'
folium.Marker([40.5358796, -3.7016036], popup='Miraflores', tooltip=tooltip).add_to(m)
tooltip = 'Valdelasfuentes, 5.948'
folium.Marker([40.547425 , -3.654149], popup='Valdelasfuentes', tooltip=tooltip).add_to(m)
m
Este estilo no me convence así que vuelvo al que genera folium por defecto, eliminando la sistaxis de tiles
.
m = folium.Map(location=[40.5475,-3.64209],
zoom_start=13,)
tooltip ='La Chopera, 7.715'
folium.Marker([ 40.5358796 , -3.7016036], popup='La Chopera', tooltip=tooltip).add_to(m)
tooltip = 'La Moraleja, 5.911'
folium.Marker([40.531936 , -3.635167], popup='La Moraleja', tooltip=tooltip).add_to(m)
tooltip = 'Marqués de la Valdavia, 4.181'
folium.Marker([40.541 , -3.6374], popup='Marqués de la Valdavia', tooltip=tooltip).add_to(m)
tooltip = 'Miraflores, 5.940'
folium.Marker([40.5358796, -3.7016036], popup='Miraflores', tooltip=tooltip).add_to(m)
tooltip = 'Valdelasfuentes, 5.948'
folium.Marker([40.547425 , -3.654149], popup='Valdelasfuentes', tooltip=tooltip).add_to(m)
m
Para que los marcadores destaquen más interesa cambiarlos de color. Para ello introducimos al final de la sintaxis utilizada icon=folium.Icon(color="elquequeramos")
. Voy a escoger morado ya que creo que es el que más va a resaltar.
m = folium.Map(location=[40.5475,-3.64209],
zoom_start=13,)
tooltip ='La Chopera, 7.715'
folium.Marker([ 40.5358796 , -3.7016036], popup='La Chopera', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
tooltip = 'La Moraleja, 5.911'
folium.Marker([40.531936 , -3.635167], popup='La Moraleja', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
tooltip = 'Marqués de la Valdavia, 4.181'
folium.Marker([40.541 , -3.6374], popup='Marqués de la Valdavia', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
tooltip = 'Miraflores, 5.940'
folium.Marker([40.5358796, -3.7016036], popup='Miraflores', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
tooltip = 'Valdelasfuentes, 5.948'
folium.Marker([40.547425 , -3.654149], popup='Valdelasfuentes', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
m
Por último, puede ser interesante cambiar el icono del marcador. Escojo una imagen del Covid-19 y creando una variable para el icono, introduzdo icon=folium.Icon
en la sintaxis de esta manera:
m = folium.Map(location=[40.5475,-3.64209],
zoom_start=13,)
icon_url = "https://www.who.int/images/default-source/health-topics/health-financing/novel-coronavirus-ru.jpg?sfvrsn=755458c4_12"
tooltip ='La Chopera, 7.715'
icon = folium.features.CustomIcon(icon_url,icon_size=(28, 30))
folium.Marker([ 40.5358796 , -3.7016036], popup='La Chopera', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
tooltip = 'La Moraleja, 5.911'
icon = folium.features.CustomIcon(icon_url,icon_size=(28, 30))
folium.Marker([40.531936 , -3.635167], popup='La Moraleja', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
tooltip = 'Marqués de la Valdavia, 4.181'
icon = folium.features.CustomIcon(icon_url,icon_size=(28, 30))
folium.Marker([40.541 , -3.6374], popup='Marqués de la Valdavia', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
tooltip = 'Miraflores, 5.940'
icon = folium.features.CustomIcon(icon_url,icon_size=(28, 30))
folium.Marker([40.5358796, -3.7016036], popup='Miraflores', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
tooltip = 'Valdelasfuentes, 5.948'
icon = folium.features.CustomIcon(icon_url,icon_size=(28, 30))
folium.Marker([40.547425 , -3.654149], popup='Valdelasfuentes', tooltip=tooltip, icon=folium.Icon(color="purple")).add_to(m)
m
Tras haber comprendido, analizado y jugado con la visualización de los datos construimos una historia para poner en práctica la utilidad de las herramientas utilizadas.
HISTORIA (suponer que es 30 de marzo)
El municipio de Alcobendas cuenta 29.695 casos de Covid-19 en personas mayores de 60 años desde el 25 de marzo de 2020 hasta el pasado 29 de marzo. Dos años y cuatro días después del inicio de la pandemia la tasa de incidencia ha bajado un 104%, pero aún hay contagios. La Moraleja encabeza la lista con un total de 66 en los últimos 14 días, seguida solo con un caso menos por Valdelasfuentes. El tercer lugar lo ocupa Marqués de la Valdavia, con 55 nuevos contagios, seguido de La Chopera con 50 y de Miraflores con 41 casos confirmados en los últimos 14 días en personas mayores de 60 años.
df.set_index('fecha informe')['Tasa de incidencia acumulada total'].plot(title="Tasa total de incidencia acumulada en personas mayores de 60 años en Alcobendas")
La tasa de incidencia acumulada ha disminuido un 104% desde el inicio de la pandemia en Alcobendas en las personas mayores de 60 años
eje_x = ['La Chopera', 'La Moraleja', 'Marqués de la Valdavia', 'Miraflores', 'Valdelasfuentes']
eje_y = [50,66,55,41,65]
plt.barh(eje_x, eje_y, color="pink")
plt.ylabel('Zonas sanitarias')
plt.xlabel('Casos confirmados totales')
plt.title('Casos de Covid-19 en personas de 60 o más años de edad en Alcobendas')
Con 66 nuevos casos La Moraleja es la zona sanitaria de Alcobendas que encabeza la lista de contagios en los últimos 14 días.
En total se han registrado 277 nuevos casos en los últimos 14 días. Pero las cifras de los últimos dos años cambian el ránking. La Chopera es la zona sanitaria con más casos confirmados en este segmento de la población con un total de 7.715 en dos años, seguida de Valdelasfuentes con 5.948 contagios, a quien pisa los talones Miraflores, con 5.940 registros, sólo 8 menos. No muy lejos le sigue La Moraleja, con 5.911 casos confirmados seguida por, en quinto y último lugar, Marqués de la Valdavia con 4.181 personas de 60 años en adelante contagiadas en los últimos dos años.
eje_x = ['La Chopera', 'La Moraleja', 'Marqués de la Valdavia', 'Miraflores', 'Valdelasfuentes']
eje_y = [7.715,5.911,4.181,5.940,5.948]
plt.barh(eje_x, eje_y, color="orange")
plt.ylabel('Zonas sanitarias')
plt.xlabel('Casos confirmados totales')
plt.title('Casos de Covid-19 en personas de 60 o más años de edad en Alcobendas')
plt.show()
A pesar de que los contagios no han desaparecido, son insuficientes para frenar la pendiente negativa de la curva, que dos años después de aquel alarmante marzo alcanza puntos por debajo de cero en Alcobendas para este segmento de la población.
df.set_index('Zona básica de salud')['Casos confirmados totales'].plot(title="Casos confirmados totales")
Disminuyen los contagios en los últimos 14 días pero aún no llegan a desaparecer.
df.set_index('Zona básica de salud')['Casos confirmados en los ultimos 14 días'].plot(title="Casos de Covid-19 confirmados en los últimos 14 días")
m
El Ayuntamiento de Alcobendas continúa actualizando semanalmente los datos de la incidencia de casos Covid-19 en la población de 60 años en adelante de acuerdo a la implantación de la nueva Estrategia de vigilancia y control frente a Covid-19 tras la fase aguda de la pandemia de la Comunidad de Madrid.
Vamos a guardar los datos (csv) y un gráfico (png con la librería matplolib.pyplot). La función para lo primero es .to_csv
. La función para lo segundo es plt.savefing
.
df.to_csv("practica-4")
import matplotlib.pyplot as plt
df.set_index('Zona básica de salud')['Casos confirmados totales'].plot(title="Casos confirmados totales")
plt.savefig('practica-4')
Lo comprobamos:
!ls