• Home
  • Chi sono
  • Risorse
  • Contatti
  • Approfondimenti
  • Cerca nel sito

Lorenzo Govoni

Business e Tecnologia

  • Big Data
  • Business
  • Excel
  • Intelligenza Artificiale

Analisi Covid: come i governi hanno reagito alla pandemia nel 2020

Il 2020 verrà certamente ricordato come l’anno della pandemia Covid-19.

Nessuno è riuscito a prevedere cosa sarebbe potuto accadere: un disastro dal punto di vista sanitario ed economico, per non parlare di quello sociale.

In quest’articolo, voglio mostrare un’analisi interessante presa da Rikunert, in merito a questa epidemia. L’autore prende in analisi i risultati della pandemia della Germania fino ad aprile, considerando poi la reazione dei governi d’Europa sempre in quel lasso di tempo.

Ho voluto estendere l’analisi proposta da Rikunert valutando i dati italiani fino ai giorni nostri e successivamente, anziché visualizzare la reazione dei governi d’Europa ho preferito visualizzare quanto successo a livello mondiale.

Il dataset è quello ricevuto e trovato da Oxford a questo sito ed è aggiornato quotidianamente: si tratta del COVID-19 Government Response Tracker (OxCGRT) di Oxford, il quale raccoglie sistematicamente informazioni su diverse risposte politiche comuni che i governi hanno adottato per rispondere alla pandemia su 18 indicatori come la chiusura delle scuole e le restrizioni di viaggio e dispone di dati da oltre 180 paesi.

Tengo a precisare che con questo articolo non voglio creare nessun genere di polemica: semplicemente visualizzare e mostrare quanto è successo della disgrazia che ci ha colpiti.

NB: in questa analisi non si vuole tentare di prevedere quale sarà il numero di contagi in una certa regione o città, o altri dati di questo genere. Quindi non verrà utilizzato nessun tipo di algoritmo, ma piuttosto diverse visualizzazioni.

 

Importare le librerie

L’analisi richiede l’utilizzo di qualche libreria, di seguito importate ed elencate:

import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt 
import seaborn as sns 
from datetime import datetime, timedelta
from mpl_toolkits.axes_grid1 import make_axes_locatable
import geopandas as gpd
import cv2

Tra le librerie di utilizzo abbiamo:

  • Numpy: una delle più grandi librerie di calcolo matematico e scientifico;
  • Pandas: la libreria che fornisce gli strumenti per l’analisi e il recupero dei dati;
  • Os: Il modulo che fornisce la possibilità di utilizzare le funzionalità dipendenti dal sistema operativo;
  • MatplotLib: libreria Python standard utilizzata per la creazione di diagrammi e grafici 3D;
  • Seaborn: una libreria di visualizzazione dei dati Python basata su matplotlib. Fornisce un’interfaccia di alto livello per disegnare grafici statistici attraenti e informativi.
  • Datetime, timedelta: il primo è un modulo che fornisce classi per manipolare date e ore, mentre il secondo è un oggetto del modulo datetime che consente di rappresentare differenza di durate.
  • Make_Axes_locatable: fa parte di una raccolta di classi di supporto per facilitare la visualizzazione di immagini (multiple) con matplotlib.
  • Geopandas: progetto open source per semplificare il lavoro con i dati geospaziali in Python. Permette di estendere i tipi di dati utilizzati in pandas per consentire operazioni spaziali sui tipi geometrici.
  • Cv2: libreria Python progettata per risolvere problemi di computer vision e rappresenta la versione evoluta di Open-CV (prima conosciuta come cv).

 

Importare il dataset

Importiamo il set di dati e consideriamo come data massima il 15 dicembre:

ox_data_url = r'https://raw.githubusercontent.com/OxCGRT/covid-policy-tracker/master/data/OxCGRT_latest.csv'
df = pd.read_csv(ox_data_url, parse_dates=['Date'], dayfirst=False)
df = df.loc[df['Date'] <= datetime(2020, 12, 15), :]
df.head()

Vediamo un’anteprima di quanto estratto:

 

Analisi covid in Italia

Come ben sappiamo, l’Italia è stato uno dei primi paesi a subire gli effetti del virus.

Già il 23 febbraio abbiamo assistito alle prime misure per contrarre l’epidemia, fino ad arrivare in lockdown totale il 9 marzo (un blocco così dell’economia e del movimento di persone non si vedeva dalla seconda guerra mondiale, vedi fonte).

Poi sappiamo tutti cosa è successo.

Per quanto riguarda la nostra analisi, vengono di seguito rappresentate un paio di funzioni per personalizzare i grafici che successivamente saranno creati e visualizzati. Nella prima, nuss_style_fun, vengono definite le dimensioni dei grafici, la legenda, il titolo, ecc.. mentre nella seconda, draw_cases (che richiama poi al suo interno la prima) permette di rappresentare i casi di covid, il numero di morti e le restrizioni adottate dai governi.


def nuss_style_fun(fig, ax, title, author_line=True):
    
    #remove top and right frame parts
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    
    # set left and bottom axis to grey
    ax.spines['left'].set_color('grey')
    ax.spines['bottom'].set_color('grey')
    
    # set ticks to grey
    ax.tick_params(axis='x', colors='grey')
    ax.tick_params(axis='y', colors='grey')
    
    #set labels to grey
    ax.yaxis.label.set_color('grey')
    ax.xaxis.label.set_color('grey') 
    
    # align axis labels with axis ends
    ax.set_xlabel(xlabel=None,
                  position=[0, 0],
                  horizontalalignment='left',
                  color='grey',
                  size=14)
    ax.set_ylabel(ylabel=None,
                  position=[0, 1],
                  horizontalalignment='right',
                  color='grey',
                  size=14)
    
    #align title
    ax.set_title(label=title,
                 loc='left',
                 color=(0.41, 0.41, 0.41),
                 size=20)
    
    #author line
    if author_line:
        fig.text(0.99, 0.01, '@lorenzo', color='lightgrey', style='italic',
             horizontalalignment='right')
    
    return fig, ax


def draw_cases(x, y, color, title, label=None, xlabel='Date', ylabel='Cases', text1_y=12, text2_y=12, drawstyle='default'):
    
    fig, ax = plt.subplots(figsize=[10.67, 5.33])
    sns.lineplot(x=x,
                 y=y,
                 marker='o',
                 linewidth=1,
                 color=color,
                 drawstyle=drawstyle,
                 label=label,
                 ax=ax)
    fig, ax = nuss_style_fun(fig, ax, title=title)
    ax.set(xlabel='Date',
           ylabel=ylabel)
    ax.xaxis.set_ticks(np.arange(start=x.min(), 
                                 stop=max(x.max(), datetime.strptime('2020-12-15', '%Y-%m-%d')), 
                                 step=timedelta(days=40)))

    if True:
        ax.text(x='2020-01-01',
            y=text1_y,
            s='Soft lockdown',
            horizontalalignment='right',
            verticalalignment='top',
            rotation='vertical',
            color='orange',
            size=14)
        ax.axvline('2020-01-01', linestyle='--', color='orange', linewidth=1)

        ax.text(x='2020-12-15',
            y=text2_y,
            s='Lockdown eased?',
            horizontalalignment='right',
            verticalalignment='top',
            rotation='vertical',
            color='orange',
            size=14)
        ax.axvline('2020-12-15', linestyle='--', color='orange', linewidth=1)
    
    return fig, ax

Prima di rappresentare i grafici, vediamo qualche informazione del dataframe df importato in precedenza, dapprima le colonne che lo costituiscono:

df.columns

Poi il valore delle date (ho tanti record perché per ogni data fino ad oggi sono rappresentati i vari paesi del mondo):

df["Date"]

Vediamo i paesi che sono inclusi nel dataset:

df['CountryName'].unique()

Definiamo il nostro stato, ed estraiamo dal dataset di Oxford, le date dei primi contagi, quanti di essi erano e le persone decedute confermate:

country_of_interest = 'Italy'
minimal_number_of_cases = 10
mask_country = df['CountryName'] == country_of_interest
mask_dates = df.index >= df[mask_country].index[df.loc[mask_country, 'ConfirmedCases'] >= minimal_number_of_cases].min()
mask = mask_country & mask_dates
df.loc[mask, ["Date","CountryName","ConfirmedCases","ConfirmedDeaths"]].head(20)

Associamo ad una lista indi i dati dell’italia. Dopodichè possiamo vedere il dato al 15/12/2020 (già sicuramente differente dal giorno dopo), del numero totale di morti accertati e numero totale di casi:

i= 1
indi=[]

for i in range(len(df.index)):
      if  (df.iloc[i]['CountryName'] == 'Italy') == True:
          indi.append(df.index[i])
i+=1

# Casi totali Covid in Italia al 15-12-2020
print( df.loc[[min(indi)+349], ["Date","CountryName","ConfirmedCases","ConfirmedDeaths"]])

Ora vediamo su un grafico questi risultati richiamando le funzioni create in precedenza. Il primo è l’andamento dei casi di covid in italia:

fig, ax = draw_cases(x=df.loc[mask, 'Date'], 
                     y=df.iloc[::-1].loc[mask, 'ConfirmedCases'], 
                     color='navy', 
                     title='Growth of Italian Covid-19 cases is exponential',
                     ylabel='Cumulative cases', 
                     text1_y=df.iloc[::-1].loc[mask, 'ConfirmedCases'].max(), 
                     text2_y=df.iloc[::-1].loc[mask, 'ConfirmedCases'].max())
fig.savefig('D_cum_cases_ox.png', dpi=250, bbox_inches='tight')

Notiamo che la crescita dei casi risulta esponenziale da metà ottobre, mentre nei mesi precedenti si ha avuto un leggero incremento:

 

Per quanto riguarda il numero di morti, l’andamento è leggermente differente: si ha avuto una crescita iniziale, una riduzione nei mesi estivi e poi essi sono tornati a crescere nuovamente ad ottobre.

fig, ax = draw_cases(x=df.loc[mask, 'Date'], 
                     y=df.iloc[::-1].loc[mask, 'ConfirmedDeaths'], 
                     color='navy', 
                     title='Growth of Italian Covid-19 death seems to be not exponential',
                     ylabel='Cumulative cases', 
                     text1_y=df.iloc[::-1].loc[mask, 'ConfirmedDeaths'].max(), 
                     text2_y=df.iloc[::-1].loc[mask, 'ConfirmedDeaths'].max())
fig.savefig('D_cum_death_ox.png', dpi=250, bbox_inches='tight')

 

Infine visualizziamo nel lasso di tempo le restrizioni apportate dal governo: il picco massimo lo abbiamo ottenuto tra marzo e aprile, e nei mesi autunnali si sta riprendendo.

fig, ax = draw_cases(x=df.loc[mask, 'Date'], 
                     y=df.iloc[::-1].loc[mask, 'StringencyIndexForDisplay'], 
                     color='navy', 
                     title='Italy\'s restriction severity in response to Covid19',
                     ylabel='Stringency Index of government response', 
                     text1_y=df.iloc[::-1].loc[mask, 'StringencyIndex'].max(), 
                     text2_y=df.iloc[::-1].loc[mask, 'StringencyIndex'].max(),
                    drawstyle='steps-post')
ax.set(ylim=[-0.5, 100])
fig.savefig('plot.png', dpi=250, bbox_inches='tight')

 

Reazione dei governi nel mondo al Covid-19

In questo secondo step valutiamo come i governi hanno reagito alla pandemia adottando o meno misure restrittive. La misura adottata è quella vista anche dal grafico precedente: StrigencyIndexForDisplay. Questa misura composita è un semplice punteggio additivo di sette indicatori (S1-S7 che prendono in considerazione politiche come chiusure scolastiche, divieti di viaggio, ecc.) misurato su una scala ordinale, ridimensionato per variare da 0 a 100.

Come viene detto sul sito, questa misura è solo a scopo comparativo e non deve essere interpretata come una valutazione dell'adeguatezza o l'efficacia della risposta di un paese.

Per rappresentare su mappa questo indice, ci serve la libreria OpenCV e geopandas (importate in precedenza).

In aggiunta dobbiamo scaricare i dati dei paesi del mondo rappresentati tramite vettori da questo sito.

world = gpd.read_file('C:\\Users\\Lorenzo\\dropbox\\Hobby\\Immagini\\Covid\World\\ne_10m_admin_0_countries.shp')

Visualizziamo le colonne della variabile world appena letta da geopandas:

world.columns

Vediamo la sovranità dello stato Italiano:

world[world['SOVEREIGNT']=='Italy']

Uniamo alla variabile world, in cui abbiamo le informazioni per rappresentare la mappa, le variabili del dataset df, visto in precedenza. Salviamo l’unione del dataset nella variabile world_updated:

world_updated = world.merge(right=df.loc[df['Date']==df['Date'].max(), ['CountryName', 'CountryCode', 'StringencyIndexForDisplay']], 
                    how='left',
                    left_on='ADM0_A3', 
                    right_on='CountryCode',
                   suffixes=('', '')).copy()

Definiamo i parametri e le configurazioni delle immagini delle mappe che andremo a creare:

params = {"text.color" : (0.41, 0.41, 0.41),
          'axes.labelcolor' : (0.41, 0.41, 0.41),
          "xtick.color" : (0.41, 0.41, 0.41),
          "ytick.color" : (0.41, 0.41, 0.41),
          'axes.edgecolor': (0.41, 0.41, 0.41),
         'axes.linewidth': 0.25}
plt.rcParams.update(params)

Creiamo ora una funzione per rappresentare la mappa geografica del mondo, personalizzata come visto per l’analisi covid:

def visualise_europe_choropleth(world,
                                date_text,
                                author_line=True):
    
    fig, ax = plt.subplots(figsize=[10.67, 5.33])
    divider = make_axes_locatable(ax)
    cax = divider.append_axes("top", size="5%", pad=0.5)
    ax.axis('off')
    world.plot(column="StringencyIndexForDisplay", 
                edgecolor='lightgrey', 
                cmap='jet',
                linewidth=0.5,
                vmin=0,
                vmax=100,
               missing_kwds={'color': 'lightgrey'},
               legend=True,
               legend_kwds={'label': "Response stringency index",
                            'orientation': "horizontal",
                           'format': '%.0f%%',
                           'shrink': 0.5,
                           },
                ax=ax,
              cax=cax)
    
    ax.set_title('Government reaction to Covid-19\n\n',
                 color=(0.41, 0.41, 0.41),
                 size=26)
#    ax.set(xlim=[-24, 50],
#          ylim=[33, 70])
    
    ax.text(x=-26,
            #y=43.5,
            y=-65,
            s=date_text,
            horizontalalignment='left',
            verticalalignment='bottom',
            color=(0.41, 0.41, 0.41),
            size=24)
    
    #author line
    if author_line:
        fig.text(0.83, 0.05, '@lorenzo', color='lightgrey', style='italic',
             horizontalalignment='right')
        
    fig.text(0.205, 0.05, 'Data: Oxford COVID-19 Government Response Tracker', color='lightgrey',
             horizontalalignment='left')

    return fig, ax

Richiamiamo la funzione appena creata, passando i dati richiesti, e salviamo l’immagine che viene creata:

fig, ax = visualise_europe_choropleth(world_updated, 
                                      date_text=df['Date'].max().strftime("%d %b %Y"),
                                      author_line=True)
fig.savefig('C:\\Users\\Lorenzo\\Dropbox\\Hobby\\Immagini\\Covid\\EU_restriction_severity.png', dpi=250, bbox_inches='tight')

Gli stati in grigio sono dovuti al fatto che nel dataset non sono incluse informazioni sull’indice il 15 dicembre.

Siamo pronti ora a creare un ciclo per creare l’andamento dei governi da inizio anno al 15-12-20. Ogni immagine creata la salviamo in una cartella del pc:

dpi_count = 100
start_date = df['Date'].min() 
end_date = df['Date'].max() - timedelta(days=1)
delta = timedelta(days=1)
counter = 0
expl_i = 0
while start_date <= end_date:
    
    date_text = start_date.strftime("%d %b %Y")
    print(date_text)
    
    world_updated = world.merge(right=df.loc[df['Date']==pd.Timestamp(start_date), ['CountryName', 'CountryCode', 'StringencyIndexForDisplay']], 
                    how='left',
                    left_on='ADM0_A3', 
                    right_on='CountryCode',
                   suffixes=('', '')).copy()
    
    fig, ax = visualise_europe_choropleth(world_updated, 
                                          date_text=date_text,
                                          author_line=True)
    
    if start_date == df['Date'].min():
        frames_per_date = 10
    else:
        frames_per_date = 3
    
    for i in range(frames_per_date):  # number of frames
        fig.savefig('C:\\Users\\Lorenzo\\Dropbox\\Hobby\\Immagini\\Covid\\Immagini\\EU_severity_{:03d}.png'.format(counter+i), dpi=dpi_count, bbox_inches='tight')
    plt.close(fig)
    
    start_date += delta
    counter += frames_per_date

for i in range(20):  # number of end frames
    fig.savefig('C:\\Users\\Lorenzo\\Dropbox\\Hobby\\Immagini\\Covid\\Immagini\\EU_severity_{:03d}.png'.format(counter+i), dpi=dpi_count, bbox_inches='tight')

Eseguito il ciclo, creiamo il video, tramite la libreria cv2, che mostra come hanno reagito i governi del mondo:

dir_path = 'C:\\Users\\Lorenzo\\Dropbox\\Hobby\\Immagini\\Covid\\Immagini\\'
ext = '.png'
output = 'covid-government-response.avi'
shape = 960, 720
fps = 5

images = [f for f in os.listdir(dir_path) if f.endswith(ext)]

fourcc = cv2.VideoWriter_fourcc(*'DIVX')
video = cv2.VideoWriter(output, fourcc, fps, shape)

for image in images:
    image_path = os.path.join(dir_path, image)
    image = cv2.imread(image_path)
    resized=cv2.resize(image,shape) 
    video.write(resized)

video.release()

Ecco il risultato di quanto ottenuto al seguente link.

Conclusione

L’articolo visto oggi è un po’ diverso da quelli che abbiamo solitamente visto: il covid è un argomento delicato, che ha cambiato quest’anno la vita di tutti noi.

Ho voluto mostrare l’analisi impostata inizialmente da Rikunert, approfondendola e andando a visualizzare i dati fino al giorno 15 dicembre prima dell’andamento italiano.

Dopodichè ho mostrato come poter creare video da immagini salvate, per vedere come i governi nel mondo hanno reagito la pandemia, utilizzando l’indice di rigore o restrizione.

Ulteriori analisi potranno essere eseguite partendo da questi dati per approfondire e indicare come la situazione si è evoluta, sperando in un futuro prossimo dove il covid sarà sconfitto e si potrà ottenere un ritorno agognato alla normalità.

  • La gestione delle scorte tramite il lotto economicoLa gestione delle scorte tramite il lotto economico
  • Tre tecniche di regolarizzazione: Ridge, Lasso ed Elastic NetTre tecniche di regolarizzazione: Ridge, Lasso ed…
  • Introduzione alla Linear Discriminant Analysis (LDA)Introduzione alla Linear Discriminant Analysis (LDA)
  • Chatbot: lo strumento per incrementare le vendite del tuo businessChatbot: lo strumento per incrementare le vendite…
Share
Pin
Share
Tweet

Intelligenza Artificiale codice, Machine Learning

  • Home
  • Archivio
  • Risorse
  • Newsletter
  • Cerca nel sito

Copyright © 2021 · Lorenzo Govoni - Privacy Policy