Uso de la API del Covid19 con Pandas

En esta práctica, vamos a usar la API COVID-19, desarrollada por Kyle Redelinghuys y basada en los datos que proporciona la Universidad Johns Hopkins.

Instalación librerías

Para empezar, tenemos que instalar la librería necesaria para proyectar los datos que obtengamos sobre la incidencia de la COVID-19. Para ello, usamos el comando pip install pandas. Para especificar que lo que estamos haciendo es ejecutar un comando bash, ponemos un ! al inicio de la línea.

In [1]:
!pip install pandas
Requirement already satisfied: pandas in /usr/local/lib/python3.8/dist-packages (1.3.1)
Requirement already satisfied: pytz>=2017.3 in /usr/local/lib/python3.8/dist-packages (from pandas) (2020.4)
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: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.7.3->pandas) (1.14.0)

Configuración de Pandas

Una vez instalada, tenemos que importarla al proyecto que estamos realizando. Para ello, usamos la función import, e importamos la librería como pd, de forma abreviada, tal y como sigue a continuación.

In [2]:
import pandas as pd

Crear variable

Ya está instalada la librería Pandas y la hemos importado. Ahora ya podemos empezar a crear las variables necesarias para, posteriormente, realizar los gráficos con los datos de la API. Lo primero será definir la variable url, que será la que le diga a Python el origen de los datos.

In [3]:
url = 'https://api.covid19api.com/countries'

Crear Dataframe

Una vez tenemos el enlace donde se encuentran los datos, podemos empezar a mostrarlos. Lo primero será crear un dataframe, una tabla con filas y columnas en la que aparecerán los datos. Para ello, usamos la función de Pandas que lee el formato .json, en el que están los datos de la API: pd.read_json(url). Al poner (url), le estamos indicando a Pandas cuáles son los datos que tiene que leer.

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

Ejecutamos el df para visualizar que todo está correcto.

In [5]:
df
Out[5]:
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 tabla

Como vemos, al componerse de 248 filas, solo se nos muestra un extracto, las primeras y las últimas filas. Ahora vamos a seguir explorando la tabla.

Por ejemplo, vamos a visualizar las 6 primeras filas. Para ello, a través de head, le decimos que nos muestre el dataframe con las X primeras filas, que en este caso le hemos indicado que sean 6.

In [6]:
df.head(6)
Out[6]:
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

Ahora lo mismo, pero al contrario, empezando por el final. Para decirle que queremos comenzar por el final, en lugar de head usamos tail, con el mismo formato: entre paréntesis indicamos el X número de filas que queremos visualizar.

In [7]:
df.tail(2)
Out[7]:
Country Slug ISO2
246 Latvia latvia LV
247 Papua New Guinea papua-new-guinea PG

Si queremos conocer más datos técnicos acerca de la composición de lo que estamos usando, podemos usar info, que nos indicará de qué tipo son los datos por columnas, el total de filas y columnas, cuánto utiliza de memoria o si existen datos nulos.

In [8]:
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

Si queremos filtrar por columnas para ver los datos de alguna en particular, seguimos usando el df pero ahora, entre corchetes, ponemos el nombre de la columna que queramos visualizar. Por ejemplo, para ver una lista (abreviada) de países, usamos 'Country'.

In [9]:
df['Country']
Out[9]:
0                     Gambia
1                   Paraguay
2        Trinidad and Tobago
3                    Austria
4      Sao Tome and Principe
               ...          
243               Cape Verde
244                   Israel
245                  Bolivia
246                   Latvia
247         Papua New Guinea
Name: Country, Length: 248, dtype: object

Además de esto, también podemos cruzar filas con columnas. Es decir, saber qué valor tiene la fila X en la columna Y. Para ello, añadimos otro corchete a los que tenemos especificando el número de la fila. En este caso, queremos saber qué país está codificado en la fila 66 de la tabla o dataframe.

In [10]:
df['Country'][66]
Out[10]:
'Honduras'

Una vez hemos testeado algunas formas de visualización del dataframe de los países, vamos a centrarnos en algunos territorios concretos para ver su evolución en tiempo real de los casos confirmados.

Para hacer esto, tenemos que definir de nuevo el enlace desde el que Pandas leerá los datos y crear, a partir de este, el dataframe. En esta ocasión, veremos los datos de España, por lo que obtenemos desde la API los casos confirmados en tiempo real para el país y los definimos. Posteriormente, los mostramos para ver que todo ha ido bien.

In [11]:
url_es = 'https://api.covid19api.com/country/spain/status/confirmed/live'
df_es = pd.read_json(url_es)
df_es
Out[11]:
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
... ... ... ... ... ... ... ... ... ... ...
816 Spain ES 40.46 -3.75 11662214 confirmed 2022-04-17 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 rows × 10 columns

Al igual que hicimos anteriormente, vamos a ver diferentes datos de la tabla. Para empezar, queremos listar las columnas existentes y saber qué datos contiene cada una. Lo hacemos mostrando el dataframe de España y añadiendo columns.

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

De la misma manera, podemos cruzar filas con las columnas para saber un dato concreto. Por ejemplo, para saber cuál es el dato que se encuentra en la primera fila, empezando por el principio, filtramos por la columna 'Date', y con .head(x) le indicamos el número que queremos.

In [13]:
df_es['Date'].head(1)
Out[13]:
0   2020-01-22 00:00:00+00:00
Name: Date, dtype: datetime64[ns, UTC]

Además, para saber los tipos de datos contenidos en el dataframe, si existen datos nulos y el tamaño total de la tabla, usamos info.

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

Si profundizamos en cuestiones estadísticas, podemos saber, por ejemplo, datos como la media, la desviación estándar, los diferentes cuartiles y el valor mínimo y máximo, usamos describe.

In [15]:
df_es.describe()
Out[15]:
Lat Lon Cases
count 8.210000e+02 821.00 8.210000e+02
mean 4.046000e+01 -3.75 3.426515e+06
std 1.421952e-14 0.00 3.312558e+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.180212e+06
75% 4.046000e+01 -3.75 4.953930e+06
max 4.046000e+01 -3.75 1.173689e+07

Aquí volvemos a mostrar el dataframe entero, aunque aparece de forma abrevada por cuestión de espacio, sin filtrar por columna o tipo de datos.

In [16]:
df_es
Out[16]:
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
... ... ... ... ... ... ... ... ... ... ...
816 Spain ES 40.46 -3.75 11662214 confirmed 2022-04-17 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 rows × 10 columns

A continuación, colocamos como referencia la fecha de los datos, para empezar a obtener una imagen general de la evolución de los datos. Para ello, fijamos con set_index el nombre de la columna que queremos colocar como referencia, que en este caso es la fecha ('Date').

In [17]:
df_es.set_index('Date')
Out[17]:
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-17 00:00:00+00:00 Spain ES 40.46 -3.75 11662214 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

821 rows × 9 columns

Para ceñirnos estrictamente a los datos que queremos ver, y así dejar fuera los que son innecesarios, como el país, la latitud y la longitud o el código del país, entre corchetes especificamos la(s) columna(s) que queramos mostrar además de la de la fecha.

In [18]:
df_es.set_index('Date')['Cases']
Out[18]:
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-17 00:00:00+00:00    11662214
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
Name: Cases, Length: 821, dtype: int64

Vamos a pasar a la representación gráfica. Manteniendo lo anterior, es decir, los datos que queremos visualizar (fecha y número de casos, para ver la evolución temporal), añadimos plot y le ponemos un título al gráfico, dentro de los paréntesis a partir de plot.

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

Datos de Italia

Ahora repetimos el mismo proceso que hemos hecho hasta ahora pero con otro país, pero centrándonos solo en la representación visual de los datos.En este caso se ha elegido Italia.

In [20]:
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 Ben Italia")
Out[20]:
<AxesSubplot:title={'center':'Casos de Covid19 Ben Italia'}, xlabel='Date'>

Datos de México

De nuevo, escogemos un tercer país de la API y volvemos a visualizarlo a través de plot de su dataframe. Se ha elegido México.

In [21]:
url_mex = 'https://api.covid19api.com/country/mexico/status/confirmed/live'
df_mex = pd.read_json(url_mex)
df_mex.set_index('Date')['Cases'].plot(title="Casos de Covid19 en México")
Out[21]:
<AxesSubplot:title={'center':'Casos de Covid19 en México'}, xlabel='Date'>

Comparación

Una vez que hemos visto diversos países por separados, es el momento de unir todos sus datos para poder compararlos y ver cómo han ido evolucionando sus casos confirmados de coronavirus a lo largo de un periodo temporal.

Para ello, creamos una nueva variable por cada país que contenga solo los datos que hemos ido necesitando y trabajando anteriormente: fecha y número de casos confirmados.

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

Una vez definidas estas variables, empezamos a jugar con ellas y mostrándolas, esta vez haciendo uso de la concatenación de la librería de Pandas.

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

821 rows × 3 columns

Para simplificar esta agrupación, creamos una nueva variable a partir de la concatenación anterior, a la que llamaremos 'vs' y la mostramos.

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

821 rows × 3 columns

Ahora, damos nombre a las columnas para organizar bien los datos y el gráfico. Una vez hecho esto, mostramos el gráfico con plot y elegimos el tipo de gráfico, que en este caso, será de área.

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

Expportamos nuestra nueva variable, que hemos limpiado para que contenga únicamente los datos necesarios, y la exportamos a un archivo separado por comas (.csv), con la función to_csv.

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

Verificamos que se haya guardado ejecutando el comando bash ls.

In [27]:
!ls
api-pandas-folium.ipynb  pruebas-r.ipynb		  Shared_Resources
esvsit.csv		 python-api-covid19-pandas.ipynb  Untitled1.ipynb
esvsit.png		 python-pruebas.ipynb		  Untitled.ipynb

Para guardar el gráfico como imagen PNG, tenemos que importar la librería pyplot de matplotlib, que ya se encuentra instalada. Generamos el gráfico de nuevo y con plt.savefig('nombre-grafico.png') se crea la imagen.

In [28]:
import matplotlib.pyplot as plt
vs.plot()
plt.savefig('esvsit.png')

Volvemos a verificar que se ha exportado correctamente y que el gráfico existe como imagen PNG con el nombre que le hemos dado.

In [29]:
!ls
api-pandas-folium.ipynb  pruebas-r.ipynb		  Shared_Resources
esvsit.csv		 python-api-covid19-pandas.ipynb  Untitled1.ipynb
esvsit.png		 python-pruebas.ipynb		  Untitled.ipynb