Rappresentazioni grafiche (e dintorni)

Pacchetti utili e dati

Prima di iniziare carichiamo l’insieme di pacchetti tidyverse, che sfrutteremo sia per la manipolazione dei dati (pacchetto dplyr) che per la grafica (pacchetto ggplot2).

Per leggere i dati in formato MS-Excel è necessario caricare in memoria anche il pacchetto readxl.

library(tidyverse)
library(readxl)

A questo punto è possibile caricare i dati (attenzione al percorso in cui si trova il file: si può sfruttare anche l’interfaccia di RStudio per importare il file e copiare il codice che viene generato dall’interfaccia).

anoressia <- read_excel("../dati/DatiAnoressia.xlsx")

La funzione colnames permette di vedere i nomi delle colonne (delle variabili) della tabella di dati:

colnames(anoressia)
 [1] "DuratamalattiaMesi"               
 [2] "EtaPrimoRicoveroAnni"             
 [3] "EtaEsordioAnni"                   
 [4] "Sottotipo"                        
 [5] "BMI"                              
 [6] "NumeroRicoveri"                   
 [7] "DurataPrimaOspedalizzazioneGiorni"
 [8] "Insight"                          
 [9] "Anamnesifamiliare"                
[10] "Tentatividisuicidio"              
[11] "InformazioniFamiglia"             
[12] "MorganRussellOutcome"             

Può essere conveniente sfruttare la funzione clean_names del pacchetto janitor (da caricare in memoria) per avere un formato dei nomi delle variabili più coerente:

library(janitor)
anoressia <- clean_names(anoressia)
colnames(anoressia)
 [1] "duratamalattia_mesi"                 
 [2] "eta_primo_ricovero_anni"             
 [3] "eta_esordio_anni"                    
 [4] "sottotipo"                           
 [5] "bmi"                                 
 [6] "numero_ricoveri"                     
 [7] "durata_prima_ospedalizzazione_giorni"
 [8] "insight"                             
 [9] "anamnesifamiliare"                   
[10] "tentatividisuicidio"                 
[11] "informazioni_famiglia"               
[12] "morgan_russell_outcome"              

Codifica dei dati: le variabili qualitative

Per gestire le variabili qualitative in R si possono sfruttare i factor. Al riguardo maggiori dettagli sono contenuti nel file gestione-manipolazione-dati.html.

L’utilizzo dei factor inserisce delle etichette testuali, che corrispondono a quelle che vengono chiamate modalità o livelli di una variabile qualitativa, accanto ai codici numerici ad essi corrispondenti. Questa codifica ha effetto sulla reportistica (grafici e tabelle) e sulle funzioni di sintesi. Consideriamo ad esempio il test per il confronto tra medie della variabile eta_esordio_anni tra i due gruppi individuati dalla variabile sottotipo:


    Welch Two Sample t-test

data:  eta_esordio_anni by sottotipo
t = -1.0625, df = 97.402, p-value = 0.2906
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -3.320078  1.004752
sample estimates:
mean in group 1 mean in group 2 
       16.97959        18.13725 

In questo caso nell’output viene stampato il codice numerico corrispondente alle due modalità delle variabili qualitative.

Per effettuare la codifica di una variabile qualitativa possiamo sfruttare la funzione factor, indicando le etichette testuali da associare ai numeri nell’argomento labels:

 [1] restrittivo vomito      restrittivo vomito      restrittivo
 [6] restrittivo restrittivo vomito      restrittivo restrittivo
[11] vomito      vomito      vomito      vomito      restrittivo
[16] restrittivo restrittivo vomito      vomito      vomito     
[21] restrittivo vomito      restrittivo restrittivo vomito     
[26] vomito      vomito      restrittivo vomito      vomito     
[31] restrittivo vomito      vomito      vomito      restrittivo
[36] vomito      vomito      vomito      restrittivo restrittivo
[41] vomito      vomito      restrittivo vomito      vomito     
[46] vomito      restrittivo restrittivo vomito      restrittivo
[51] vomito      restrittivo vomito      restrittivo vomito     
[56] restrittivo restrittivo vomito      restrittivo restrittivo
[61] restrittivo restrittivo restrittivo restrittivo vomito     
[66] vomito      vomito      restrittivo vomito      vomito     
[71] vomito      vomito      restrittivo restrittivo restrittivo
 [ reached getOption("max.print") -- omitted 25 entries ]
Levels: restrittivo vomito

Per modificare/aggiungere colonne ad una tabella possiamo sfruttare il verbo mutate, aggiungendo una colonna con la codifica o sovrascrivendo la codifica numerica con la corrispondente variabile factor.

Di seguito l’istruzione per la codifica delle variabili qualitative contenute nella tabella:

Abbiamo sfruttato anche la funzione recode_factor, molto utile per ricodificare un factor in un numero di livello differenti. Vale la pena evidenziare che nel verbo mutate si può fare riferimento anche a variabili non presenti già nella tabella ma prodotte da un’istruzione precedente nello stesso verbo. Nell’istruzione sopra, ad esempio, la colonna morgan_due_categorie viene creata sfruttando la codifica definita nella stessa istruzione per la variabile morgan_russell_outcome.

Se effettuiamo nuovamente il test per il confronto tra le due medie, in questo caso l’output risulta più leggibile, in quanto sfrutta i nomi delle modalità (i livelli dei fattori) e non i corrispondenti codici numerici:

t.test(eta_esordio_anni ~ sottotipo, data=anoressia)

    Welch Two Sample t-test

data:  eta_esordio_anni by sottotipo
t = -1.0625, df = 97.402, p-value = 0.2906
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -3.320078  1.004752
sample estimates:
mean in group restrittivo      mean in group vomito 
                 16.97959                  18.13725 

ggplot2: una grammatica per i grafici

Per la costruzione di un grafico in R esistono differenti approcci. Quello che sfrutteremo si ispira alla teoria nota come Grammar of graphics, di cui trovate una trattazione esaustiva nell’omonimo volume di L. Wilkinson del 2005. La trasposizione in R è offerta nel pacchetto ggplot2. Alcuni riferimenti utili al riguardo:

Anatomia di un grafico

La funzione principale per la costruzione di un grafico è la funzione ggplot. Il grafico può essere visto come un insieme di strati (dati, assi, oggetti geometrici, trasformazioni statistiche, panelli, ecc.).

Per costruire un grafico in ggplot i dati devono necessariamente essere memorizzati in un oggetto tabellare (data.frame o tibble), che viene passato alla funzione ggplot sfruttando l’argomento data:

ggplot(data = anoressia)

Il comando sopra crea un grafico vuoto. Si possono specificare una o due variabili da utilizzare per la rappresentazione, a seconda del tipo di grafico desiderato. Se ad esempio si utilizzano sia la x che la y, la funzione prepara il sistema di assi:

ggplot(data = anoressia, 
       aes(x = eta_esordio_anni, 
           y = eta_primo_ricovero_anni))

Una volta specificati i dati e il sistema di assi è necessario indicare un attributo geometrico che verrà utilizzato per rappresentare i dati. La seguente istruzione produce il classico diagramma di dispersione, o scatter plot:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point()

E’ possibile cambiare gli attributi estetici usati per la rappresentazione usando dei valori fissati. Di seguito un esempio dello stesso grafico cambiando colore, dimensione e forma usata per i punti:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point(col = "blue", size = 2, shape = "triangle")

La cosa interessante di questo sistema grafico è la possibilità di impostare gli attributi dei vari oggetti geometrici in funzione dei valori che un’altra variabile assume nella tabella dei dati:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point(aes(col = sottotipo))

E’ importante evidenziare che quando si vuole fare riferimento a colonne presenti nella tabella dei dati, è necessario inserire i nomi nella funzione helper aes (che sta per aestetichs). Il seguente grafico usa un colore diverso in corrispondenza delle diverse modalità della variabile sottotipo:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point(aes(col = sottotipo))

Un esempio equivalente dove insieme al colore viene cambiata anche la forma del punto sempre in base alle modalità della variabile sottotipo:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point(aes(col = sottotipo, shape = sottotipo))

E’ possibile usare congiuntamente sia attributi “statici” che attributi dinamici, come nel seguente esempio:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point(aes(shape = sottotipo,
                 col = sottotipo), size = 3)

E’ naturalmente possibile abbinare i vari attributi estestici a differenti variabili:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point(aes(col = sottotipo,
                 shape = morgan_due_categorie), size = 3)

Esistono una serie di temi predefiniti per i grafici. Per cambiare il tema di default con il tema in “bianco e nero” si può aggiungere un ulteriore strato al grafico:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point(aes(shape = sottotipo,
                 col = sottotipo), size = 3) +
  theme_bw()

Tutti i temi predefiniti iniziano con il prefisso theme_. Oltre a quelli predefiniti nel pacchetto ggplot2, altre due interessanti pacchetti da esplorare sono ggthemes e ggsci (quest’ultimo contiene temi e palette di colori preimpostati per alcune importanti riviste scientifiche).

Un’altra funzionalità molto interessante è la possibilità di costruire dei grafici condizionati per gruppi di unità. E’ possibile sfruttare a tale riguardo due funzioni alternative: facet_wrap e facet_grid.

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point() +
  facet_wrap(~ insight) +
  theme_bw()

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point() +
  facet_grid(~ insight) +
  theme_bw()

Le due funzioni sono sostanzialmente equivalenti quando si usa una sola variabile di condizionamento, come negli esempi sopra.

Qualche differenza esiste invece se si utilizzano due variabili di condizionamento, come illustrato di seguito:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point() +
  facet_wrap(insight ~ sottotipo) +
  theme_bw()

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point() +
  facet_grid(insight ~ sottotipo) +
  theme_bw()

E’ importante evidenziare che quanto detto in precedenza con riferimento agli attributi estetici di un grafico viene automaticamente applicato a ciascun pannello che lo compone nel caso di grafici condizionati, come nell’esempio seguente:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point(aes(col = sottotipo)) +
  facet_wrap(~ insight) +
  theme_bw()

La funzione facet_wrap consente di specificare il numero di righe e colonne in cui si vuole dividere la struttura grafica, mentre facet_grid ha il vantaggio di permettere di aggiungere i grafici marginali, ovvero quelli costruiti su tutti i dati:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point() +
  facet_grid(~ insight, margins = TRUE) +
  theme_bw()

Nel caso di un condizionamento su una sola variabile, il grafico può essere organizzato in righe semplicemente cambiando la posizione della variabile nella sintassi di tipo formula:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point() +
  facet_grid(insight ~ ., margins = TRUE) +
  theme_bw()

Nel caso di un condizionamento su due variabili, l’aggiunta dei grafici marginali avviene con riferimento ad entrambe le variabili:

ggplot(data = anoressia, 
       aes(eta_esordio_anni, 
           eta_primo_ricovero_anni)) +
  geom_point() +
  facet_grid(insight ~ sottotipo, margins = TRUE) +
  theme_bw()

Istogramma

Una tipica rappresentazione grafica per dati numerici è l’istogramma. In questo caso è necessario specificare solo la variabile da usare sull’asse orizzontale: geom_histogram automaticamente raggruppa i dati ed effettua il conteggio in corrispondenza di ciascun gruppo:

E’ possibile fissare il numero di classi dell’istogramma: o l’ampiezza delle stesse:

E’ possibile cambiare gli attributi “statici” dell’istogramma:

Anche in questo caso è possibile sfruttare una seconda variabile (da specificare nella funzione helper aes per colorare le barre dell’istogramma):

In questo caso è sicuramente più leggibile dividere il grafico in due pannelli separati:

Come già visto in precedenza, è naturalmente possibile usare anche due variabili di stratificazione per ottenere dei grafici in corrispondenza di ciascuna distribuzione condizionata:

Boxplot

Un’altra rappresentazione grafica molto comune per dati numerici è il boxplot, che rappresenta i tre quartili, il minimo e il massimo (sintesi a 5 dei dati) ed evidenzia eventuali valori anomali.

Il boxplot richiede sempre di specificare sia la x che la y. Nel caso di un boxplot semplice, è necessario fissare ad una costante il valore della x, come nel seguente esempio:

Se si vuole un boxplot orientato orizzontalmente, si può sfruttare la funzione coord_flip per ruotare le coordinate:

Molto immediati, ai fini del confronto di distribuzioni condizionate, sono i boxplot paralleli, che si ottengono semplicemente inserendo la variabile di stratificazione in corrispondenza dell’argomento x:

Anche in questo caso si può ruotare l’orientamento del grafico usando coord_flip (non funziona l’inversione dei valori di x e y):

E’ possibile colorare i boxplot per una più immediata lettura sfruttando l’argomento fill:

Si può eliminare la legenda dal grafico (in questo caso ridondante) sfruttando l’argomento legend.position della funzione theme:

Anche in questo caso è possibile cambiare il tema del grafico:

Attenzione a quello che succede se usiamo prima la funzione theme e poi la funzione theme_bw (o qualunque altra funzione che ci permetta di impostare un tema per il grafico):

Anche per i boxplot, come per tutti i grafici, è possibile sfruttare l’organizzazione per pannelli in caso di dati divis per gruppi:

Diagrammi a barre

La rappresentazione grafica di una tabella di frequenza (univariata e bivariata) può essere ottenuta con un diagramma a barre:

E’ possibile sfruttare l’attributo di riempimento per inserire sul grafico l’informazione anche di una seconda variabile. In questo caso le barre possono essere impilate (default, ovvero position = "stack") o affiancate (position = "dodge"):

Nel caso di barre impilate, usando fill come valore dell’argomento position, si ottiene la rappresentazione delle distribuzioni condizionate in frequenze relative, che permette un più agevole confronto tra i vari gruppi:

E’ possibile rappresentare le frequenze relative o quelle percentuali sull’asse verticale:

La funzione di sintesi (stat) associata per default ad un diagramma a barra è la funzione di conteggio. Questo permette di utilizzare direttamente la serie grezza e la funzione di rappresentazione costruirà e rappresenterà la tabella di frequenza. Talora si può avere a disposizione direttamente la tabella di frequenza: in questo caso è necessario indicare esplicitamente di non usare alcuna trasformazione nella rappresentazione (stat = "identity"):

# A tibble: 3 x 2
  morgan_russell_outcome count
  <fct>                  <int>
1 povero                    31
2 intermedio                35
3 buono                     34

Questo si rivela utile per usare i diagrammi a barre per altri tipi di tabelle, diversi dalle tabelle di frequenza. Se ad esempio vogliamo rappresentare la seguente tabella delle medie:

# A tibble: 3 x 2
  morgan_russell_outcome bmi_medio
  <fct>                      <dbl>
1 povero                      13.6
2 intermedio                  14.6
3 buono                       14.9

basta sfruttare la stessa sintassi vista in precedenza, cambiando la tabella di input e i nomi delle colonne in cui sono riportati i dati:

E’ possibile aggiungere in corrispondenza di ciascun barra un segmento la cui lunghezza è associata alla variabilità del gruppo (scarto quadratico medio). Se aggiungiamo alla precedente di sintesi anche l’informazione sullo scarto quadratico medio:

# A tibble: 3 x 3
  morgan_russell_outcome bmi_medio bmi_sd
  <fct>                      <dbl>  <dbl>
1 povero                      13.6   2.25
2 intermedio                  14.6   1.96
3 buono                       14.9   2.32

possiamo sfruttare geom_errorbar per ottenere il grafico desiderato:

Possiamo infine completare il grafico scegliendo un colore diverso per ciascun barra (e nascondendo la legenda):

Una variante dei boxplot

Una variante dei boxplot consiste nel rappresentare, per ciascuna distribuzione condizionata, oltre al classico boxplot, anche i singoli punti corrispondenti alle unità.

A tale riguardo conviene partire dai singoli punti:

Per evitare la sovrapposizione dei punti è possibile impostare a jitter la position dei punti, aggiungendo un piccolo rumore casuale:

Possiamo sovraimporre un punto (rosso e triangolare) per evidenziare la posizione delle medie di gruppo. A tale riguardo possiamo sfruttare la tabella tbl_medie costruita in precedenza: Dal grafico precedente si vede come è possibile utilizzare un differente dataset per ciascun strato della rappresentazione: nell’esempio abbiamo usato la tabella anoressia per la costruzione del grafico iniziale e la tabella tbl_medie per rappresentare le medie di gruppo.

A questo punto possiamo sovraimporre sul grafico il boxplot:

Per evitare che il boxplot copra i punti possiamo semplicemente cambiare l’ordine di rappresentazione, spostando geom_boxplot prima dei due geom_point:

O in alternativa possiamo sfruttare l’argomento alpha, che permette di impostare il livello di trasparenza del boxplot: