È sempre una buona idea esaminare i nostri dati prima di iniziare a tracciare. Possiamo leggere i dati in un dataframe pandas e visualizzare le prime 10 righe:
import pandas as pd# Read in data and examine first 10 rows
flights = pd.read_csv('data/formatted_flights.csv')
flights.head(10)
I ritardi di arrivo dei voli sono in minuti e valori negativi significano che il volo era in anticipo (si scopre che i voli tendono spesso ad arrivare in anticipo, solo mai quando ci siamo noi!) Ci sono oltre 300.000 voli con un ritardo minimo di -60 minuti e un ritardo massimo di 120 minuti. L’altra colonna nel dataframe è il nome della compagnia aerea che possiamo usare per i confronti.
Un ottimo modo per iniziare ad esplorare una singola variabile è l’istogramma. Un istogramma divide la variabile in bins, conta i punti dati in ogni bin e mostra i bins sull’asse delle x e i conteggi sull’asse delle y. Nel nostro caso, i bin saranno un intervallo di tempo che rappresenta il ritardo dei voli e il conteggio sarà il numero di voli che rientrano in quell’intervallo. La larghezza di banda è il parametro più importante per un istogramma e dovremmo sempre provare alcuni valori diversi di larghezza di banda per selezionare quello migliore per i nostri dati.
Per fare un istogramma di base in Python, possiamo usare sia matplotlib che seaborn. Il codice qui sotto mostra le chiamate di funzione in entrambe le librerie che creano figure equivalenti. Per le chiamate di plot, specifichiamo la larghezza dei bin per il numero di bins. Per questa trama, userò dei bins di 5 minuti di lunghezza, il che significa che il numero di bins sarà l’intervallo dei dati (da -60 a 120 minuti) diviso per la larghezza del bin, 5 minuti ( bins = int(180/5)
).
Per gli istogrammi più basilari, Io andrei con il codice di matplotlib perché è più semplice, ma useremo la funzione seaborn distplot
più avanti per creare diverse distribuzioni ed è bene avere familiarità con le diverse opzioni.
Come sono arrivato a 5 minuti per la larghezza dei bin? L’unico modo per capire un binwidth ottimale è provare più valori! Qui sotto c’è il codice per fare la stessa figura in matplotlib con una serie di valori di larghezza di banda. In definitiva, non c’è una risposta giusta o sbagliata alla larghezza di banda, ma ho scelto 5 minuti perché penso che rappresenti meglio la distribuzione.
La scelta della larghezza di banda influenza significativamente il grafico risultante. Una larghezza di banda più piccola può rendere il grafico disordinato, ma una larghezza di banda più grande può oscurare le sfumature dei dati. Matplotlib sceglierà automaticamente una larghezza di banda ragionevole per voi, ma a me piace specificare la larghezza di banda da solo dopo aver provato diversi valori. Non c’è una vera risposta giusta o sbagliata, quindi provate alcune opzioni e vedete quale funziona meglio per i vostri dati particolari.
Quando gli istogrammi falliscono
Gli istogrammi sono un ottimo modo per iniziare ad esplorare una singola variabile tratta da una categoria. Tuttavia, quando vogliamo confrontare le distribuzioni di una variabile attraverso più categorie, gli istogrammi hanno problemi di leggibilità. Per esempio, se vogliamo confrontare le distribuzioni dei ritardi di arrivo tra compagnie aeree, un approccio che non funziona bene è quello di creare istogrammi per ogni compagnia aerea sullo stesso grafico:
(Si noti che l’asse y è stato normalizzato per tenere conto del diverso numero di voli tra le compagnie aeree. Per fare questo, passate l’argomento norm_hist = True
alla chiamata della funzione sns.distplot
.)
Questo grafico non è molto utile! Tutte le barre che si sovrappongono rendono quasi impossibile fare confronti tra le compagnie aeree. Vediamo alcune possibili soluzioni a questo problema comune.
Soluzione #1: Istogrammi affiancati
Invece di sovrapporre gli istogrammi delle compagnie aeree, possiamo metterli fianco a fianco. Per fare questo, creiamo una lista dei ritardi di arrivo per ogni compagnia aerea, e poi la passiamo nella chiamata della funzione plt.hist
come una lista di liste. Dobbiamo specificare diversi colori da usare per ogni compagnia aerea e un’etichetta in modo da poterli distinguere. Il codice, compresa la creazione delle liste per ogni compagnia aerea è qui sotto:
Di default, se passiamo una lista di liste, matplotlib metterà le barre affiancate. Qui, ho cambiato la larghezza dei bin a 15 minuti perché altrimenti il grafico è troppo ingombrante, ma anche con questa modifica, questo non è un dato efficace. Ci sono troppe informazioni da elaborare in una volta sola, le barre non si allineano con le etichette, ed è ancora difficile confrontare le distribuzioni tra le linee aeree. Quando facciamo un grafico, vogliamo che sia il più facile possibile da capire per l’osservatore, e questa figura non soddisfa questo criterio! Guardiamo una seconda potenziale soluzione.
Soluzione #2: barre impilate
Invece di tracciare le barre per ogni compagnia aerea fianco a fianco, possiamo impilarle passando il parametro stacked = True
alla chiamata dell’istogramma:
# Stacked histogram with multiple airlines
plt.hist(, bins = int(180/15), stacked=True,
normed=True, color = colors, label=names)
Bene, questo non è affatto meglio! Qui, ogni compagnia aerea è rappresentata come una sezione del tutto per ogni bin, ma è quasi impossibile fare dei confronti. Per esempio, con un ritardo di -15 a 0 minuti, United Air Lines o JetBlue Airlines hanno una dimensione maggiore della barra? Non posso dirlo e nemmeno gli spettatori saranno in grado di farlo. Generalmente non sono un sostenitore delle barre impilate perché possono essere difficili da interpretare (anche se ci sono casi d’uso come quando si visualizzano le proporzioni). Entrambe le soluzioni che abbiamo provato usando gli istogrammi non hanno avuto successo, e quindi è il momento di passare al diagramma di densità.
Density Plots
Primo, cos’è un diagramma di densità? Un grafico di densità è una versione smussata e continua di un istogramma stimato dai dati. La forma più comune di stima è conosciuta come stima della densità del kernel. In questo metodo, una curva continua (il kernel) viene disegnata in ogni singolo punto dei dati e tutte queste curve vengono poi aggiunte insieme per fare una singola stima di densità liscia. Il kernel più spesso usato è una gaussiana (che produce una curva a campana gaussiana in ogni punto dei dati). Se, come me, trovate questa descrizione un po’ confusa, date un’occhiata al seguente grafico:
Qui, ogni piccola linea nera verticale sull’asse delle x rappresenta un punto dati. I kernel individuali (Gaussiane in questo esempio) sono mostrati disegnati in linee rosse tratteggiate sopra ogni punto. La curva solida blu è creata sommando le singole gaussiane e forma il grafico di densità complessivo.
L’asse x è il valore della variabile proprio come in un istogramma, ma cosa rappresenta esattamente l’asse y? L’asse y in un grafico di densità è la funzione di densità di probabilità per la stima della densità del kernel. Tuttavia, dobbiamo fare attenzione a specificare che si tratta di una densità di probabilità e non di una probabilità. La differenza è che la densità di probabilità è la probabilità per unità sull’asse x. Per convertire in una probabilità effettiva, dobbiamo trovare l’area sotto la curva per un intervallo specifico sull’asse x. Un po’ confusamente, poiché questa è una densità di probabilità e non una probabilità, l’asse y può assumere valori maggiori di uno. L’unico requisito del grafico di densità è che l’area totale sotto la curva si integri a uno. In genere tendo a pensare all’asse y di un grafico di densità come un valore solo per i confronti relativi tra diverse categorie.
Piani di densità in Seaborn
Per fare i grafici di densità in seaborn, possiamo usare la funzione distplot
o kdeplot
. Continuerò ad usare la funzione distplot
perché ci permette di fare più distribuzioni con una sola chiamata di funzione. Per esempio, possiamo fare un grafico di densità che mostra tutti i ritardi di arrivo sopra l’istogramma corrispondente:
# Density Plot and Histogram of all arrival delays
sns.distplot(flights, hist=True, kde=True,
bins=int(180/5), color = 'darkblue',
hist_kws={'edgecolor':'black'},
kde_kws={'linewidth': 4})
Finalmente, siamo arrivati ad una soluzione efficace! Con il diagramma di densità, possiamo facilmente fare confronti tra le compagnie aeree perché il diagramma è meno ingombrante. Ora che finalmente abbiamo il grafico che vogliamo, arriviamo alla conclusione che tutte queste compagnie aeree hanno distribuzioni di ritardo di arrivo quasi identiche! Tuttavia, ci sono altre compagnie aeree nel set di dati, e possiamo tracciarne uno che è un po’ diverso per illustrare un altro parametro opzionale per i grafici di densità, l’ombreggiatura del grafico.
Piani di densità ombreggiati
Riempire il grafico di densità può aiutarci a distinguere tra distribuzioni che si sovrappongono. Anche se questo non è sempre un buon approccio, può aiutare a sottolineare la differenza tra le distribuzioni. Per ombreggiare i diagrammi di densità, passiamo shade = True
all’argomento kde_kws
nella chiamata distplot
.
sns.distplot(subset, hist = False, kde = True,
kde_kws = {'shade': True, 'linewidth': 3},
label = airline)
Se ombreggiare o meno il grafico è, come altre opzioni di tracciatura, una questione che dipende dal problema! Per questo grafico, penso che abbia senso perché l’ombreggiatura ci aiuta a distinguere i grafici nelle regioni in cui si sovrappongono. Ora, abbiamo finalmente qualche informazione utile: I voli Alaska Airlines tendono ad essere in anticipo più spesso di United Airlines. La prossima volta che hai l’opzione, sai quale compagnia aerea scegliere!
Rug Plots
Se vuoi mostrare ogni valore in una distribuzione e non solo la densità smussata, puoi aggiungere un rug plot. Questo mostra ogni singolo punto di dati sull’asse x, permettendoci di visualizzare tutti i valori reali. Il vantaggio di usare distplot
di seaborn è che possiamo aggiungere il rug plot con una singola chiamata di parametro rug = True
(con anche qualche formattazione).
Con molti punti dati il rug plot può diventare sovraffollato, ma per alcune serie di dati, può essere utile visualizzare ogni punto dati. Il rug plot ci permette anche di vedere come il density plot “crea” dati dove non ce ne sono, perché crea una distribuzione kernel in ogni punto dei dati. Queste distribuzioni possono fuoriuscire dalla gamma dei dati originali e dare l’impressione che Alaska Airlines abbia ritardi che sono sia più brevi che più lunghi di quelli effettivamente registrati. Dobbiamo stare attenti a questo artefatto dei grafici di densità e farlo notare agli spettatori!
Conclusioni
Spero che questo post vi abbia dato una serie di opzioni per visualizzare una singola variabile da una o più categorie. Ci sono ancora più grafici univariati (di una singola variabile) che possiamo fare, come i grafici empirici di densità cumulativa e i grafici quantile-quantile, ma per ora ci limiteremo agli istogrammi e ai grafici di densità (e anche ai grafici a tappeto!). Non preoccupatevi se le opzioni sembrano schiaccianti: con la pratica, fare una buona scelta diventerà più facile, e potete sempre chiedere aiuto se necessario. Inoltre, spesso non c’è una scelta ottimale e la decisione “giusta” dipenderà dalle preferenze e dagli obiettivi della visualizzazione. La cosa buona è che non importa quale trama vogliate fare, ci sarà un modo per farlo in Python! Le visualizzazioni sono un mezzo efficace per comunicare i risultati, e conoscere tutte le opzioni disponibili ci permette di scegliere la figura giusta per i nostri dati.
Accetto feedback e critiche costruttive e posso essere raggiunto su Twitter @koehrsen_will.