Uso de la API del Covid 19 con Pandas

Para realizar esta práctica utilizamos Python, un lenguaje de programación de alto nivel para el desarrollo de software. A diferencia de otros lenguajes como Java, se trata de un lenguaje interpretado, es decir, cuyo código ya es legible y no requiere traducción.

En este cuaderno Python trabajaremos la representación de los datos de la API del Covid-19 por países con la librería Pandas. Como sus siglas indican, Pandas es la librería de Python para el anális de datos (Python Data Analysis Library) que nos es muy útil para la manipulación y análisis de datos en el lenguaje de progrmación de Python. Es una biblioteca de software escrita como extensión de NumPy que ofrece estructuras de datos y funcicones para manipular tablas numéricas y series temporales.

La Url con la que vampos a trabajar es la siguiente: https://api.covid19api.com/countries

Antes de poder empezar a trabajar con los datos necesitamos realizar tres pasos previos:

  1. Preparar librerías 1.1 Instalar 1.2 Importar
  2. Definir las variables con las que vamos a trabajar, en este caso la API del Covid-19
  3. Crear del dataframe para que Python muestre los datos

Preparación de librería

Requiere de dos pasos:

Instalación

Necesitamos instalar la librería para que Python pueda trabajar a partir de ella para la leer los datos y trabajar con ellos. Una vez instalada permanecerá en la consola. Lo hacemos con la sintaxis !pip install ()

In [2]:
!pip install pandas
Requirement already satisfied: pandas in /usr/local/lib/python3.8/dist-packages (1.3.1)
Requirement already satisfied: python-dateutil>=2.7.3 in /usr/local/lib/python3.8/dist-packages (from pandas) (2.8.1)
Requirement already satisfied: numpy>=1.17.3 in /usr/local/lib/python3.8/dist-packages (from pandas) (1.21.1)
Requirement already satisfied: pytz>=2017.3 in /usr/local/lib/python3.8/dist-packages (from pandas) (2020.4)
Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.7.3->pandas) (1.14.0)

El f nos indica que no estamos ejecutando Python, sino Bash. Pandas es una librería de Python especializada en manejar análisis y estructuras de datos. En clases anteriores efectivamente estuvimos viendo el tipo de estructura de datos en temas, donde los tipos de datos que podemos encontrar son: cadenas de datos, numbers o datos binarios v(erdadero / falso). Hoy veremos la estructura de datos.

Configuración de Pandas

Que hayamos instalado la librería no significa que podamos trabajar con ella. Tenemos que configurarla, importarla al presente notebook para hacer uso de ella. Puede compararse a cuando nos compramos un libro: necesitamos abrirlo para poder leerlo. Lo hacemos con el comando import() y con su abreviación típica:

In [12]:
import pandas as pd

Así abreviamos la importación de pandas como pd. Ya tenemos el libro comprado y abierto. Ahora falta leerlo. Para ello tenemos que crear un dataframe, la forma en la que Python a través de Pandas leerá los datos de la API. Pero para ello primero debemos decirle qué datos queremos que lea. Para ello creamos una variable que lo indique. lo hacemos con =

Crear Variable

In [11]:
url = "https://api.covid19api.com/countries"

Así definimos la variable url que pusimos antes y que Python vea lo que es. Para ello le explicamos a Python que url es = a una cadena de de caracreres, motivo por el que van "entre comillas". La referencia nos sirve para el resto de las cajas del cuaderno.

Crear Dataframe

Por último, ahora que Pyton ya tiene la librería (Pandas) y los datos de la API con la variable url definida es el momento de que lea los datos. De Pandas hay una función que se llama read_json; esto es, una función para leer JSON (Java Script Object Notation o notación de objetos en java script. Dentro de la función read_json ponemos : para poner lo que queremos que lea, La url con los datos está es JSON: son los datos en este lenguaje.

In [13]:
df = pd.read_json(url)

La función read_jason lee un JSON y entre paréntesis () la función de lo que queremos que lea, en este caso una url. Es decir, si ponemos en el navegador esta función, me devuelve un JSON, una lista de diccionarios. Al crear un Dataframe creamos una tabla que nos lee esto en JSON. Una vez creada la variable de dataframe la ejecutamos.

In [14]:
df
Out[14]:
Country Slug ISO2
0 Gambia gambia GM
1 Paraguay paraguay PY
2 Trinidad and Tobago trinidad-and-tobago TT
3 Austria austria AT
4 Sao Tome and Principe sao-tome-and-principe ST
... ... ... ...
243 Cape Verde cape-verde CV
244 Israel israel IL
245 Bolivia bolivia BO
246 Latvia latvia LV
247 Papua New Guinea papua-new-guinea PG

248 rows × 3 columns

Exploración de la tabla

Ahora que ya Python ha abierto los datos es el momendo de explorarlos. A la variable definida como df podemos añadirle funciones. En este caso la función .head sirve para mostrarnos los datos a la cabeza del conjunto. Para ver los últimos valores (que se corresponden en este caso con los países con menos certeza de casos covid), la función es .tail.

Para determinar el número de países que queremos que nos muestre en ambas funciones, lo especificamos dentro del paréntseis.

In [17]:
df.head (6)
Out[17]:
Country Slug ISO2
0 Gambia gambia GM
1 Paraguay paraguay PY
2 Trinidad and Tobago trinidad-and-tobago TT
3 Austria austria AT
4 Sao Tome and Principe sao-tome-and-principe ST
5 Timor-Leste timor-leste TL
In [19]:
df.tail (3)
Out[19]:
Country Slug ISO2
245 Bolivia bolivia BO
246 Latvia latvia LV
247 Papua New Guinea papua-new-guinea PG

La función .info nos explica qué hay en el dataframe (df).

In [20]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 248 entries, 0 to 247
Data columns (total 3 columns):
 #   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
 0   Country  248 non-null    object
 1   Slug     248 non-null    object
 2   ISO2     248 non-null    object
dtypes: object(3)
memory usage: 5.9+ KB
In [23]:
df['Country'] [66]
Out[23]:
'Honduras'

Para centrarnos en una columna concreta ponemos los corechetes y dentro de comillas simples [''] el nombre de la columna que nos interese explorar. Para seleccionar un número concreto de la lista abrimos a continuación, tras un espacio, otros corchetes con el número de la fila que queramos dentro.

Caso de España: eje temporal

Vamos a centrarnos en los patos de España de la Api del covid-19 con el objetico de representar en un gráfico la evolución de la pandemia en este país. Para ello creamos un dataframe con estos datos definiendo previamente la url.

In [25]:
url_es = 'https://api.covid19api.com/country/spain/status/confirmed/live'

Repetimos el proceso con la nueva url y la función de Pandas .read_json()

In [26]:
df_es = pd.read_json(url_es)
In [27]:
df_es
Out[27]:
Country CountryCode Province City CityCode Lat Lon Cases Status Date
0 Spain ES 40.46 -3.75 0 confirmed 2020-01-22 00:00:00+00:00
1 Spain ES 40.46 -3.75 0 confirmed 2020-01-23 00:00:00+00:00
2 Spain ES 40.46 -3.75 0 confirmed 2020-01-24 00:00:00+00:00
3 Spain ES 40.46 -3.75 0 confirmed 2020-01-25 00:00:00+00:00
4 Spain ES 40.46 -3.75 0 confirmed 2020-01-26 00:00:00+00:00
... ... ... ... ... ... ... ... ... ... ...
817 Spain ES 40.46 -3.75 11662214 confirmed 2022-04-18 00:00:00+00:00
818 Spain ES 40.46 -3.75 11736893 confirmed 2022-04-19 00:00:00+00:00
819 Spain ES 40.46 -3.75 11736893 confirmed 2022-04-20 00:00:00+00:00
820 Spain ES 40.46 -3.75 11736893 confirmed 2022-04-21 00:00:00+00:00
821 Spain ES 40.46 -3.75 11736893 confirmed 2022-04-22 00:00:00+00:00

822 rows × 10 columns

La función .columns dice el nombre de las distintas columnas que hay.

In [28]:
df_es.columns
Out[28]:
Index(['Country', 'CountryCode', 'Province', 'City', 'CityCode', 'Lat', 'Lon',
       'Cases', 'Status', 'Date'],
      dtype='object')

Al ver las columnas de esta manera resulta mucho más facil detectar qué categorías de datos tenemos que usar para nuestro objetivo. Como queremos representar la evolución en el tiempo de la pandemia en España nos interesan las categorías "Cases" y "Date".

In [29]:
df_es.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 822 entries, 0 to 821
Data columns (total 10 columns):
 #   Column       Non-Null Count  Dtype              
---  ------       --------------  -----              
 0   Country      822 non-null    object             
 1   CountryCode  822 non-null    object             
 2   Province     822 non-null    object             
 3   City         822 non-null    object             
 4   CityCode     822 non-null    object             
 5   Lat          822 non-null    float64            
 6   Lon          822 non-null    float64            
 7   Cases        822 non-null    int64              
 8   Status       822 non-null    object             
 9   Date         822 non-null    datetime64[ns, UTC]
dtypes: datetime64[ns, UTC](1), float64(2), int64(1), object(6)
memory usage: 64.3+ KB

Con .info obtenemos la información básica del dataframe. La función .describe se centra en valores numéricos. Hace un conteo de los valores, la media, la mínima, la desviación típica...

In [30]:
df_es.describe()
Out[30]:
Lat Lon Cases
count 8.220000e+02 822.00 8.220000e+02
mean 4.046000e+01 -3.75 3.436625e+06
std 7.109753e-15 0.00 3.323205e+06
min 4.046000e+01 -3.75 0.000000e+00
25% 4.046000e+01 -3.75 3.428130e+05
50% 4.046000e+01 -3.75 3.181958e+06
75% 4.046000e+01 -3.75 4.956001e+06
max 4.046000e+01 -3.75 1.173689e+07
In [31]:
df_es
Out[31]:
Country CountryCode Province City CityCode Lat Lon Cases Status Date
0 Spain ES 40.46 -3.75 0 confirmed 2020-01-22 00:00:00+00:00
1 Spain ES 40.46 -3.75 0 confirmed 2020-01-23 00:00:00+00:00
2 Spain ES 40.46 -3.75 0 confirmed 2020-01-24 00:00:00+00:00
3 Spain ES 40.46 -3.75 0 confirmed 2020-01-25 00:00:00+00:00
4 Spain ES 40.46 -3.75 0 confirmed 2020-01-26 00:00:00+00:00
... ... ... ... ... ... ... ... ... ... ...
817 Spain ES 40.46 -3.75 11662214 confirmed 2022-04-18 00:00:00+00:00
818 Spain ES 40.46 -3.75 11736893 confirmed 2022-04-19 00:00:00+00:00
819 Spain ES 40.46 -3.75 11736893 confirmed 2022-04-20 00:00:00+00:00
820 Spain ES 40.46 -3.75 11736893 confirmed 2022-04-21 00:00:00+00:00
821 Spain ES 40.46 -3.75 11736893 confirmed 2022-04-22 00:00:00+00:00

822 rows × 10 columns

Definimos los ejes: El valor de la gráfica es el número de casos (eje Y) y las fechas (eje X).

Con la función set_index, ponemos la columna Dates la primera para organizar los datos a partir de la misma. Puesto que el eje X son las fechas comenzamos por esta categoría.

In [32]:
df_es.set_index('Date')
Out[32]:
Country CountryCode Province City CityCode Lat Lon Cases Status
Date
2020-01-22 00:00:00+00:00 Spain ES 40.46 -3.75 0 confirmed
2020-01-23 00:00:00+00:00 Spain ES 40.46 -3.75 0 confirmed
2020-01-24 00:00:00+00:00 Spain ES 40.46 -3.75 0 confirmed
2020-01-25 00:00:00+00:00 Spain ES 40.46 -3.75 0 confirmed
2020-01-26 00:00:00+00:00 Spain ES 40.46 -3.75 0 confirmed
... ... ... ... ... ... ... ... ... ...
2022-04-18 00:00:00+00:00 Spain ES 40.46 -3.75 11662214 confirmed
2022-04-19 00:00:00+00:00 Spain ES 40.46 -3.75 11736893 confirmed
2022-04-20 00:00:00+00:00 Spain ES 40.46 -3.75 11736893 confirmed
2022-04-21 00:00:00+00:00 Spain ES 40.46 -3.75 11736893 confirmed
2022-04-22 00:00:00+00:00 Spain ES 40.46 -3.75 11736893 confirmed

822 rows × 9 columns

Pero además del número de casos confirmados los demás datos no nos interesan. Queremos cruzar el datos de las fechas con los de casos confirmados para lograr un gráfico que represente la evolución de la pandemia en España. Por lo que añadimos [ ] en el nombre de la otra columna:

In [33]:
df_es.set_index('Date')['Cases']
Out[33]:
Date
2020-01-22 00:00:00+00:00           0
2020-01-23 00:00:00+00:00           0
2020-01-24 00:00:00+00:00           0
2020-01-25 00:00:00+00:00           0
2020-01-26 00:00:00+00:00           0
                               ...   
2022-04-18 00:00:00+00:00    11662214
2022-04-19 00:00:00+00:00    11736893
2022-04-20 00:00:00+00:00    11736893
2022-04-21 00:00:00+00:00    11736893
2022-04-22 00:00:00+00:00    11736893
Name: Cases, Length: 822, dtype: int64

Así vemos que ya solo nos muestra la información que necesitamos. A continuación, utilizamos la función .plot() al final de la sintaxis anterior para pintar la gráfica. Esta función es una de las funciones de Python por defecto.

In [35]:
df_es.set_index('Date')['Cases'].plot()
Out[35]:
<AxesSubplot:xlabel='Date'>

La función .plot(title='...') sirve para titular la gráfica:

In [37]:
df_es.set_index('Date')['Cases'].plot(title="Casos de COVID19 en España")
Out[37]:
<AxesSubplot:title={'center':'Casos de COVID19 en España'}, xlabel='Date'>

Así tenemos la representación gráfica que queríamos partiendo de unos datos. Podemos tratar el gráfico como imagen y gruardarlo como archivo independiente para poder utilizarlo donde nos interese.

La librería Pandas es muy útil tambien para comparar datos. Vamos a repetir este proceso con otro país, Italia por ejemplo, para luego comparar las curvas de ambos países.

Caso de Italia: eje temporal

Repetimos el proceso esta vez en un sólo paso porque ya sabemos hacerlo:

  1. Definimos una variable (url) con los datos de la Api del covid-19 para Italia
  2. Definimos una variable (dataframe) con la función de Pandas .read_json()
  3. Sobre la variable anterior aplicamos la función .set:index()[] con las columnas de los datos que queremos curzar para su representación.
    • Al final de la sintaxis añadimos la función de Python .plot(title='...') para que nos muestre directamente estos datos representados en un gráfico titulado.
In [48]:
url_it = 'https://api.covid19api.com/country/italy/status/confirmed/live'
df_it = pd.read_json(url_it)
df_it.set_index('Date')['Cases'].plot(title="Casos de COVID19 en Italia")
Out[48]:
<AxesSubplot:title={'center':'Casos de COVID19 en Italia'}, xlabel='Date'>

Así obtenemos el gráfico resultante. Una vez seguido el procedimiento podemos utilizar los tres tipos de códigos empleados arriba para conocer la gráfica de otros países. Escojo Francia por su cercanía.

Caso de Francia: eje temporal

In [49]:
url_fr = 'https://api.covid19api.com/country/france/status/confirmed/live'
df_fr = pd.read_json(url_fr)
df_fr.set_index('Date')['Cases'].plot(title="Casos de COVID19 en Francia")
Out[49]:
<AxesSubplot:title={'center':'Casos de COVID19 en Francia'}, xlabel='Date'>

Comparación de países: España - Italia

Ahora que tenemos la evolución de la pandemia en tres países, España, Francia e Italia, los comparamos en un sólo gráfico. Primero comparamos solo Italia y España. Para ello buscaremos concatenar las columnas de los casos de los distitntos países, definiendo primero qué incluimos en esta categoría: columna Date.

Definimos las variables a concatenar. Lo hacemos como anteriormente, con la función .set_index()[] sobre el dataframe correspondiente en cada caso:

In [52]:
casos_es = df_es.set_index('Date')['Cases']
casos_it = df_it.set_index('Date')['Cases']

Ahora concatenamos las variables recién definidas con la función .concat para crear una serie con ambos países y poder compararlos.

In [53]:
pd.concat([casos_es,casos_it],axis=1)
Out[53]:
Cases Cases
Date
2020-01-22 00:00:00+00:00 0 0
2020-01-23 00:00:00+00:00 0 0
2020-01-24 00:00:00+00:00 0 0
2020-01-25 00:00:00+00:00 0 0
2020-01-26 00:00:00+00:00 0 0
... ... ...
2022-04-18 00:00:00+00:00 11662214 15730676
2022-04-19 00:00:00+00:00 11736893 15758002
2022-04-20 00:00:00+00:00 11736893 15858442
2022-04-21 00:00:00+00:00 11736893 15934437
2022-04-22 00:00:00+00:00 11736893 16008181

822 rows × 2 columns

Pero con los datos presentados de esta manera no rsulta intuitivo inferir qué columna es para cada país. Necesitamos nombrarlas. Para ello creamos una variable ("vs") con la sintaxis anterior para nombrar de esta forma la primera fila y poder renombrar sus categorías.

In [78]:
vs = pd.concat([casos_es,casos_it],axis=1)
vs
Out[78]:
Cases Cases
Date
2020-01-22 00:00:00+00:00 0 0
2020-01-23 00:00:00+00:00 0 0
2020-01-24 00:00:00+00:00 0 0
2020-01-25 00:00:00+00:00 0 0
2020-01-26 00:00:00+00:00 0 0
... ... ...
2022-04-18 00:00:00+00:00 11662214 15730676
2022-04-19 00:00:00+00:00 11736893 15758002
2022-04-20 00:00:00+00:00 11736893 15858442
2022-04-21 00:00:00+00:00 11736893 15934437
2022-04-22 00:00:00+00:00 11736893 16008181

822 rows × 2 columns

A esta variable creada le añadimos la función .columns indiccándole las categorías.

In [80]:
vs.columns = ['España', 'Italia']

Lo comprobamos:

In [81]:
vs.columns
Out[81]:
Index(['España', 'Italia'], dtype='object')

Lo ejecutamos

In [82]:
vs
Out[82]:
España Italia
Date
2020-01-22 00:00:00+00:00 0 0
2020-01-23 00:00:00+00:00 0 0
2020-01-24 00:00:00+00:00 0 0
2020-01-25 00:00:00+00:00 0 0
2020-01-26 00:00:00+00:00 0 0
... ... ...
2022-04-18 00:00:00+00:00 11662214 15730676
2022-04-19 00:00:00+00:00 11736893 15758002
2022-04-20 00:00:00+00:00 11736893 15858442
2022-04-21 00:00:00+00:00 11736893 15934437
2022-04-22 00:00:00+00:00 11736893 16008181

822 rows × 2 columns

Ahora que ya tenemos los datos a pintar respresentados de esta manera clara aplicamos la función .plot(title="...") sobre la variable anterior.

In [83]:
vs.plot(title="Comparación de la evolución de la pandemia en España e Italia")
Out[83]:
<AxesSubplot:title={'center':'Comparación de la evolución de la pandemia en España e Italia'}, xlabel='Date'>

Ya tenemos el resultado. Ahora puede ser interesante incluir el país restante.

Comparación de los tres países: España - Italia - Francia

Repetimos el proceso anterior creando la variable para los casos de Francia.

In [64]:
casos_es = df_es.set_index('Date')['Cases']
casos_it = df_it.set_index('Date')['Cases']
casos_fr = df_fr.set_index('Date')['Cases']
In [67]:
pd.concat([casos_es,casos_it,casos_fr],axis=1)
Out[67]:
Cases Cases Cases
Date
2020-01-22 00:00:00+00:00 0.0 0.0 0
2020-01-22 00:00:00+00:00 0.0 0.0 0
2020-01-22 00:00:00+00:00 0.0 0.0 0
2020-01-22 00:00:00+00:00 0.0 0.0 0
2020-01-22 00:00:00+00:00 0.0 0.0 0
... ... ... ...
2022-04-22 00:00:00+00:00 11736893.0 16008181.0 2641
2022-04-22 00:00:00+00:00 11736893.0 16008181.0 454
2022-04-22 00:00:00+00:00 11736893.0 16008181.0 72648
2022-04-22 00:00:00+00:00 11736893.0 16008181.0 37038
2022-04-23 00:00:00+00:00 NaN NaN 27416764

9865 rows × 3 columns

In [68]:
vs = pd.concat([casos_es,casos_it,casos_fr],axis=1)
vs
Out[68]:
Cases Cases Cases
Date
2020-01-22 00:00:00+00:00 0.0 0.0 0
2020-01-22 00:00:00+00:00 0.0 0.0 0
2020-01-22 00:00:00+00:00 0.0 0.0 0
2020-01-22 00:00:00+00:00 0.0 0.0 0
2020-01-22 00:00:00+00:00 0.0 0.0 0
... ... ... ...
2022-04-22 00:00:00+00:00 11736893.0 16008181.0 2641
2022-04-22 00:00:00+00:00 11736893.0 16008181.0 454
2022-04-22 00:00:00+00:00 11736893.0 16008181.0 72648
2022-04-22 00:00:00+00:00 11736893.0 16008181.0 37038
2022-04-23 00:00:00+00:00 NaN NaN 27416764

9865 rows × 3 columns

In [69]:
vs.columns = ['España', 'Italia', 'Francia']

Para que no nos pinte la franja con los casos acumulados de los tres países sino que distinga la de cada país añadimos kind='area'.

In [109]:
vs.plot(title="España vs Italia vs Francia", kind='area')
Out[109]:
<AxesSubplot:title={'center':'España vs Italia vs Francia'}, xlabel='Date'>

Guardar los datos (csv) y gráfico (png)

Al pinchar con el boton derecho encima de cada gráfico puedo gurardalo en el ordenador local como imagen. Pero también puedo hacerlo en Jupyter. Eso es últil para utilizar el archivo en otro cuaderno y para tener los datos representados en una hoja aparte. Para ello indicamos el nombre de la variable de nuestro gráfico añadiendo la función .to_csv('...'). Queremos guardarlo como un archivo csv para que guarde los datos tabulados.

In [71]:
vs.to_csv('esvsit.csv')

Comprobamos que esté el archivo con un lsprecedido de ! porque es comando de Bash.

In [72]:
ls
 Api-pandas-folium.ipynb   Python-api-covid19-pandas.ipynb   Shared_Resources@
 esvsit.csv                Python-prueba.ipynb
'Probando con R.ipynb'     seaborn-data/
In [73]:
!ls
 Api-pandas-folium.ipynb   Python-api-covid19-pandas.ipynb   Shared_Resources
 esvsit.csv		   Python-prueba.ipynb
'Probando con R.ipynb'	   seaborn-data

Para guardarlo como imagen necesitamos importar la librería Matplolib.pyplot Lo hacemos con su abreviación plt y utilizamos su función .savefig.

In [116]:
import matplotlib.pyplot as plt
vs.plot(title='Evolución pandemia: España vs Italia')
plt.savefig('esvsitvsmx.png')
In [117]:
!ls
 api-pandas-folium.ipynb  'Probando con R.ipynb'
'Borrador p.4.ipynb'	   python-api-covid19-pandas.ipynb
 esvsit.csv		   python-csv-covid19-pandas.ipynb
 esvsitvsmx.png		   Python-prueba.ipynb
 practica-4		   seaborn-data
 practica-4-grafico.png    Shared_Resources