Visualizzazione post con etichetta Tips & tricks. Mostra tutti i post
Visualizzazione post con etichetta Tips & tricks. Mostra tutti i post

20 luglio 2025

Come impiegare l'operatore %>% e l'argomento FUN

Anche se l'obiettivo di questi post rimane sempre quello di fornire gli strumenti più semplici, quelli utili nella fase iniziale di apprendimento – notoriamente tutta in salita e nella quale quello che conta è "rompere il ghiaccio" con R  occasionalmente può essere interessante affrontare argomenti un poco più tecnici, come i due che vediamo ora.

L'operatore %>%

Il simbolo %>% viene impiegato per indicare l'operatore pipeil termine sta per il sostantivo "tubo" ma anche per l'espressione verbale "trasportare con una tubatura", ed è proprio in questo senso che viene impiegato. L'operatore pipe è stato introdotto la prima volta con il pacchetto magrittr [1] che ne riporta la seguente descrizione: 
"[il pacchetto] fornisce un meccanismo per concatenare i comandi con il nuovo operatore di inoltro pipe, %>%. Questo operatore inoltrerà un valore, o il risultato di un'espressione, alla successiva chiamata/espressione di funzione. [l'operatore] fornisce un supporto flessibile per il tipo di espressioni sul lato destro. Per ulteriori informazioni, consultare la descrizione del pacchetto. Per citare René Magritte, 'Ceci n'est pas une pipe'. " [2]

In altre parole: l'operatore %>% fornisce la "tubatura" che consente – in modo completamente trasparente per il programmatore  di inoltrare i dati in uscita da una funzione all'ingresso della funzione che segue. Vediamo questo breve esempio. Abbiamo il set di dati ais [3] 

> ais
     rcc  wcc   hc   hg ferr   bmi   ssf pcBfat    lbm    ht    wt sex   sport
1   3.96  7.5 37.5 12.3   60 20.56 109.1  19.75  63.32 195.9  78.9   f  B_Ball
…...
202 5.38  6.3 46.0 15.7   32 21.07  34.9   6.26  72.00 190.8  76.7   m  Tennis
 
e vogliamo calcolare la media, la deviazione standard e l'errore standard della concentrazione di emoglobina (hg) nel sangue dei 202 atleti australiani ivi inclusi suddividendoli per sport praticato (sport) e per sesso (sex).

Copiate e incollate nella Console di R questo script e premete ↵ Invio.

# COME IMPIEGARE l'operatore %>% (pipe)
#
library (DAAG) # carica il pacchetto che include il set di dati ais
library(dplyr) # carica il pacchetto con l'operatore pipe e altre funzioni
library(plotrix) # carica il pacchetto per il calcolo dell'errore standard
# calcola media, deviazione standard ed errore standard separatamente per sport e per sesso
pipe_hg <- ais %>% group_by(sport, sex) %>% summarise(media=mean(hg), ds=sd(hg), es=std.error(hg)) %>% ungroup()
#
pipe_hg # mostra i risultati
#

Dopo avere installato e caricato i pacchetti necessari, per realizzare la tabella che contiene i risultati desiderati impieghiamo più volte l'operatore pipe (%>%), che trasferisce i dati da una funzione alla successiva in questo modo:
→ i dati (ais) sono trasferiti (%>%) alla funzione group_by();
→ la funzione group_by()  che raggruppa i dati in sottoinsiemi per sport praticato (sport) e per sesso dell'atleta (sex) – trasferisce il risultato di questa operazione (%>%) alla funzione summarise();
→ la funzione summarise() calcola la media mean(), la deviazione standard sd() e l'errore standard std.error() della variabile hg – la concentrazione nel sangue dell'emoglobina (espressa in g/dL, grammi per decilitro di sangue) dei 202 atleti australiani suddivisi per sport e per sesso – e trasferisce il risultato di questa operazione (%>%) alla funzione ungroup();
la funzione ungroup() rimuove una serie di valori impiegati provvisoriamente per generare il risultato finale, che viene infine salvato (<-) nella tabella pipe_hg.

Ed ecco la tabella risultante, ottenuta quindi con una sola riga di codice:

> pipe_hg # mostra i risultati
# A tibble: 17 × 5
   sport   sex   media    ds    es
   <fct>   <fct> <dbl> <dbl> <dbl>
 1 B_Ball  f      13.1 0.878 0.243
 2 B_Ball  m      15.1 0.922 0.266
 3 Field   f      14.6 0.682 0.258
 4 Field   m      16.0 0.805 0.232
 5 Gym     f      13.6 0.860 0.430
 6 Netball f      12.8 0.567 0.118
 7 Row     f      14.0 0.740 0.158
 8 Row     m      15.4 0.711 0.184
 9 Swim    f      13.6 0.583 0.194
10 Swim    m      15.5 0.655 0.182
11 T_400m  f      13.8 1.04  0.312
12 T_400m  m      15.3 0.824 0.194
13 T_Sprnt f      14.2 0.556 0.278
14 T_Sprnt m      16.2 1.49  0.450
15 Tennis  f      13.5 1.10  0.414
16 Tennis  m      15.6 1.48  0.741
17 W_Polo  m      15.5 0.718 0.174


L'argomento FUN

L'argomento FUN consente di specificare una o più funzioni e di applicarle in sequenza a una variabile. Per illustrarlo impieghiamo gli stessi dati dell'esempio precedente allo stesso scopo: calcolare la media, la deviazione standard e l'errore standard della concentrazione di emoglobina nel sangue di 202 atleti australiani suddividendoli per sport praticato e per sesso. 

Copiate e incollate nella Console di R questo script e premete ↵ Invio.

# COME IMPIEGARE l'argomento FUN
#
library (DAAG) # carica il pacchetto che include il set di dati ais
library(plotrix) # carica il pacchetto per il calcolo dell'errore standard
#
# calcola media, deviazione standard ed errore standard separatamente per sport e per sesso
#
FUN_hg <- aggregate(hg~sport+sex, data=ais, FUN=function(x) c(media=mean(x), ds=sd(x), es=std.error(x))) 
#
FUN_hg # mostra i risultati 
#

Dopo avere installato e caricato i pacchetti necessari, la tabella che contiene i risultati desiderati viene realizzata con la funzione aggregate() che nell'ordine:
→ nel nostro set di dati (data=aisraggruppa (~) i valori di concentrazione dell'emoglobina (hg) in sottoinsiemi per sport praticato (sport) e per sesso dell'atleta (sex);
 con l'argomento FUN e con il valore =function(x) specifica che sui dati devono essere effettuati i calcoli di seguito elencati;
 con la funzione c() elenca le funzioni da impiegare per i calcoli;
 con le funzioni mean(), sd() e std.error() effettua i calcoli di media, deviazione standard ed errore standard sui dati raggruppati per sport e per sesso, salvando i risultati nelle variabili media, ds ed es

I risultati sono infine riportati (<-) nella tabella FUN_hg e, a parte l'ordinamento e gli arrotondamenti, sono identici a quelli ottenuti con lo script precedente, impiegando anche in questo caso una sola riga di codice.

> FUN_hg # mostra i risultati 
     sport sex   hg.media      hg.ds      hg.es
1   B_Ball   f 13.1307692  0.8778616  0.2434750
2    Field   f 14.6285714  0.6824326  0.2579353
3      Gym   f 13.6000000  0.8602325  0.4301163
4  Netball   f 12.8173913  0.5670114  0.1182301
5      Row   f 14.0318182  0.7396179  0.1576871
6     Swim   f 13.5666667  0.5830952  0.1943651
7   T_400m   f 13.7727273  1.0354621  0.3122036
8  T_Sprnt   f 14.1750000  0.5560276  0.2780138
9   Tennis   f 13.5285714  1.0965313  0.4144499
10  B_Ball   m 15.1416667  0.9219134  0.2661335
11   Field   m 16.0250000  0.8046738  0.2322893
12     Row   m 15.3866667  0.7110020  0.1835799
13    Swim   m 15.5076923  0.6550592  0.1816807
14  T_400m   m 15.3055556  0.8235306  0.1941080
15 T_Sprnt   m 16.1909091  1.4936228  0.4503442
16  Tennis   m 15.6500000  1.4821156  0.7410578
17  W_Polo   m 15.5176471  0.7178399  0.1741017

Conclusione: nel corso dell'elaborazione dei dati può essere utile tenere a portata di mano qualche esempio di codice, come questi due, che ricorda come impiegare l'operatore %>% e l'argomento FUN. Non trovate molto altro sul web, ma potete provare ricercando ad esempio "R %>% operator examples" o "R FUN function examples".


-----------

[1] Vedere il Reference manual del pacchetto: Package ‘magrittr’.
https://cran.r-project.org/web/packages/magrittr/magrittr.pdf

[2] "Provides a mechanism for chaining commands with a new forward-pipe operator, %>%. This operator will forward a value, or the result of an expression, into the next function call/expression. There is flexible support for the type of right-hand side expressions. For more information, see package vignette. To quote Rene Magritte, 'Ceci n'est pas un pipe.' ".

[3] Vedere il post Il set di dati ais nel quale trovate anche come caricare i dati senza impiegare il pacchetto DAAG

14 febbraio 2025

Come realizzare colori personalizzati [2]

Per predisporre colori personalizzati si possono impiegare queste tre funzioni:
→ rgb(red, green, blue, alpha) che genera i colori regolando il livello di intensità dei tre colori fondamentali rosso (red), verde (green) e blu (blue) e la trasparenza del colore (alpha);
→ hsv(h, s, v, alpha) che genera i colori regolando colore (h), saturazione (s), luminosità (v) e trasparenza (alpha);
→ hcl(h, c, l, alpha) che genera i colori regolando colore (h), cromaticità (c), luminanza (l) e trasparenza (alpha).

La funzione rgb() è trattata estesamente in un post a parte [1], qui vediamo invece le altre due, e vediamo poi come combinare i risultati di tutte e tre in palette personalizzate ovvero tavolozze che si possono impiegare per applicare automaticamente colori differenti alle diverse componenti di un grafico.

Copiate e incollate nella Console di R questo script e premete ↵ Invio.

# PERSONALIZZAZIONE DEI COLORI con la funzione hsv()
# regolando colore h, saturazione s, luminosità v, trasparenza alpha
#
mydata <- rnorm(5000, mean=0, sd=1) # genera cinquemila valori con media=0, ds=1
windows() # apre e inizializza una nuova finestra grafica
par(mfrow=c(4,4)) # suddivisione la finestra grafica in 4 righe per 4 colonne
# colore h
hist(mydata, col=hsv(h=0.9, s=1.0, v=1.0)) 
hist(mydata, col=hsv(h=0.6, s=1.0, v=1.0)) 
hist(mydata, col=hsv(h=0.4, s=1.0, v=1.0)) 
hist(mydata, col=hsv(h=0.1, s=1.0, v=1.0)) 
# saturazione s
hist(mydata, col=hsv(h=0.6, s=0.9, v=1.0))  
hist(mydata, col=hsv(h=0.6, s=0.6, v=1.0)) 
hist(mydata, col=hsv(h=0.6, s=0.4, v=1.0)) 
hist(mydata, col=hsv(h=0.6, s=0.1, v=1.0)) 
# luminosità v
hist(mydata, col=hsv(h=0.4, s=1.0, v=0.9, alpha=0.5)) 
hist(mydata, col=hsv(h=0.4, s=1.0, v=0.6, alpha=0.5)) 
hist(mydata, col=hsv(h=0.4, s=1.0, v=0.4, alpha=0.5)) 
hist(mydata, col=hsv(h=0.4, s=1.0, v=0.1, alpha=0.5)) 
# trasparenza alpha
hist(mydata, col=hsv(h=0.1, s=1.0, v=1.0, alpha=0.9)) 
hist(mydata, col=hsv(h=0.1, s=1.0, v=1.0, alpha=0.6)) 
hist(mydata, col=hsv(h=0.1, s=1.0, v=1.0, alpha=0.4)) 
hist(mydata, col=hsv(h=0.1, s=1.0, v=1.0, alpha=0.1)) 
#

Nella funzione hsv(h, s, v, alpha) gli argomenti:
→ colore (h)
→ saturazione (s)
→ luminosità (v)
→ trasparenza (alpha)
possono assumere solamente valori compresi tra 0 e 1.

Allo scopo di illustrare i risultati forniti dalla funzione con istogrammi colorati:
→ nella prima riga di istogrammi è stato fatto variare l'argomento colore (h);
→ nella seconda riga è stato fatto variare l'argomento saturazione (s)
→ nella terza riga è stato fatto variare l'argomento luminosità (v);
→ nell'ultima riga è stato fatto varare l'argomento trasparenza (alpha).

Come si vede i colori della prima riga, con il massimo di saturazione e di luminosità e senza alcuna trasparenza, sono vividi. Gli altri colori di base possibili possono ovviamente essere visualizzati variando opportunamente i valori di (h), mentre si lasciano la combinazione dei diversi valori possibili per i quattro argomenti e i relativi risultati in termine di colore all'eventuale interesse e alla sperimentazione.


Da notare infine che i dati impiegati negli esempi sono generati ex-novo ogniqualvolta viene eseguito lo script, pertanto i grafici saranno sempre lievemente diversi gli uni dagli altri e da quelli qui riportati. Inoltre differenze più o meno importanti nel colore sono determinate dai monitor (per i quali esistono metodi di taratura in grado di ridurle) e nel caso delle stampe dal fatto che le stampanti impiegano la sintesi sottrattiva del colore (ciano, giallo e magenta sommati danno il nero).

Ora copiate e incollate nella Console di R questo script e premete ↵ Invio.

# PERSONALIZZAZIONE DEI COLORI con la funzione hcl()
# regolando colore h, cromaticità c, luminanza l e trasparenza alpha
#
mydata <- rnorm(5000, mean=0, sd=1) # genera cinquemila valori con media=0, ds=1
windows() # apre e inizializza una nuova finestra grafica
par(mfrow=c(4,4)) # suddivisione la finestra grafica in 4 righe per 4 colonne 
# colore h
hist(mydata, col=hcl(h=60))
hist(mydata, col=hcl(h=120)) 
hist(mydata, col=hcl(h=240))
hist(mydata, col=hcl(h=300))
# cromaticità c
hist(mydata, col=hcl(h=120, c=100, l=40))  
hist(mydata, col=hcl(h=120, c=100, l=60)) 
hist(mydata, col=hcl(h=120, c=100, l=80)) 
hist(mydata, col=hcl(h=120, c=100, l=90)) 
# luminanza l
hist(mydata, col=hcl(h=240, c=60, l=40))  
hist(mydata, col=hcl(h=240, c=80, l=60)) 
hist(mydata, col=hcl(h=240, c=100, l=80)) 
hist(mydata, col=hcl(h=240, c=120, l=90)) 
# trasparenza alpha
hist(mydata, col=hcl(h=300, c=90, l=40, alpha=0.5))  
hist(mydata, col=hcl(h=300, c=90, l=60, alpha=0.5)) 
hist(mydata, col=hcl(h=300, c=90, l=80, alpha=0.5)) 
hist(mydata, col=hcl(h=300, c=90, l=90, alpha=0.5)) 
#

Nella funzione hcl(h, c, l, alpha) che genera i colori:
→ il colore (h) può assumere valori compresi tra 0 e 360;
→ il limite superiore della cromaticità (c) dipende dai valori di colore e luminanza;
→ la luminanza (l) può assumere valori compresi tra 0 e 100;
→ la trasparenza (alpha) può assumere valori compresi tra 0 e 1.

I colori della prima riga di istogrammi, che impiegano i valori di default
c=35 e l=85, mettono in evidenza la possibilità di ottenere con questa funzione colori pastello che è difficile trovare tra i 657 colori forniti nel pacchetto base di R [2].

Agendo su cromaticità (seconda riga) e luminanza (terza riga) si possono ottenere colori più saturi. Anche in questo caso si lasciano la combinazione dei diversi valori possibili per i quattro argomenti e i relativi risultati in termine di colore all'eventuale interesse e alla sperimentazione.


Una volta ottenuti i colori desiderati, si possono impiegare le funzioni che li hanno generati per ottenere i rispettivi codici esadecimali, che sono quelli che R impiega. Farlo è semplicissimo in quanto le tre funzioni per la generazione di colori, come avviene a titolo di esempio con queste tre righe di codice,

# generazione del codice esadecimale del colore
#
rgb(0.7, 0.2, 0.3, 0.5)
hsv(h=0.6, s=0.4, v=1.0)
hcl(h=120, c=100, l=60)
#

quando sono eseguite singolarmente 

> rgb(0.7, 0.2, 0.3, 0.5)
[1] "#B3334D80"
> hsv(h=0.6, s=0.4, v=1.0)
[1] "#99C2FF"
> hcl(h=120, c=100, l=60)
[1] "#39A700"

forniscono direttamente il codice esadecimale corrispondente, che può poi essere impiegato direttamente come valore dell'argomento col. Da notare che in questo esempio il codice esadecimale "#B3334D80" prodotto con la funzione rgb() ha due caratteri aggiuntivi (80) in quanto comporta anche la trasparenza (0.5) che non è stata prevista nelle altre due funzioni.

A questo punto i codici esadecimali (incluso il doppio apice che li racchiude) possono essere raccolti in tavolozze (palette) da impiegare per applicare automaticamente colori differenti alle diverse componenti di un grafico, come illustrato negli esempi che seguono.

Ora copiate e incollate nella Console di R questo script e premete ↵ Invio.

# PALETTE (TAVOLOZZE) PERSONALIZZATE
# boxplot differenziati in base a un fattore
#
mydata <- data.frame(xval=1:50, yval=rnorm(50), casi=rep(c("A", "B", "C", "D", "E"), each=10)) # genera i dati di esempio
windows() # apre e inizializza una nuova finestra grafica 
par(mfrow=c(2,2)) # suddivide la finestra grafica in 2 righe per 2 colonne
#
mypalette1 <- c("#F8A19F80", "#90AD1C80", "#F6222E80", "#1CFFCE80", "#2ED9FF80") # tavolozza di colori con trasparenza al 50% 
boxplot(yval~casi, data=mydata, horizontal=FALSE, notch=FALSE, col=mypalette1)  # traccia il boxplot
#
mypalette2 <- c("#AA0DFE80", "#3283FE80", "#85660D80", "#782AB680", "#56565680") # tavolozza di colori con trasparenza al 50% 
boxplot(yval~casi, data=mydata, horizontal=FALSE, notch=FALSE, col=mypalette2)  # traccia il boxplot
#
mypalette3 <- c("#1C8356", "#16FF32", "#F7E1A0", "#E2E2E2", "#1CBE4F") # tavolozza di colori senza trasparenza
boxplot(yval~casi, data=mydata, horizontal=FALSE, notch=FALSE, col=mypalette3) # traccia il boxplot
#
mypalette4 <- c("#C4451C", "#DEA0FD", "#FE00FA", "#325A9B", "#FEAF16") # tavolozza di colori senza trasparenza
boxplot(yval~casi, data=mydata, horizontal=FALSE, notch=FALSE, col=mypalette4)  # traccia il boxplot
#

Come si vede a questo punto diventa semplice predisporre differenti combinazioni di colori e applicarle allo stesso grafico per valutarne preventivamente l'estetica, come nel caso di questo grafico a scatola con i baffi (boxplot).


Ancor più interessante può essere l'applicazione delle stesse combinazioni di colori impiegate qui sopra a un grafico di dispersione (scatterplot) realizzato con ggplot

Copiate e incollate nella Console di R questo script e premete ↵ Invio.

# PALETTE (TAVOLOZZE) PERSONALIZZATE con ggplot
# scatterplot differenziati in base a un fattore
#
library(ggplot2) # carica il pacchetto per la grafica
library(gridExtra) # carica il pacchetto per combinare i grafici in una sola figura
#
mydata <- data.frame(xval=1:50, yval=rnorm(50), casi=rep(c("A", "B", "C", "D", "E"), each=10)) # genera i dati di esempio
windows() # apre e inizializza una nuova finestra grafica
#
mypalette1 <- c("#F8A19F80", "#90AD1C80", "#F6222E80", "#1CFFCE80", "#2ED9FF80") # tavolozza di colori con trasparenza al 50% 
plot1 <- ggplot(mydata, aes(x=xval, y=yval, color=casi)) + geom_point(size=4) +   scale_color_manual(values=mypalette1) + theme_minimal()
#
mypalette2 <- c("#AA0DFE80", "#3283FE80", "#85660D80", "#782AB680", "#56565680") # tavolozza di colori con trasparenza al 50% 
plot2 <- ggplot(mydata, aes(x=xval, y=yval, color=casi)) + geom_point(size=4) + scale_color_manual(values=mypalette2) + theme_minimal()
#
mypalette3 <- c("#1C8356", "#16FF32", "#F7E1A0", "#E2E2E2", "#1CBE4F") # tavolozza di colori senza trasparenza
plot3 <- ggplot(mydata, aes(x=xval, y=yval, color=casi)) + geom_point(size=4) +   scale_color_manual(values=mypalette3) + theme_minimal()
#
mypalette4 <- c("#C4451C", "#DEA0FD", "#FE00FA", "#325A9B", "#FEAF16") # tavolozza di colori senza trasparenza
plot4 <- ggplot(mydata, aes(x=xval, y=yval, color=casi)) + geom_point(size=4) +   scale_color_manual(values=mypalette4) + theme_minimal()
#
# combina i grafici in una sola figura
grid.arrange(plot1, plot2, plot3, plot4, nrow=2, ncol=2)
#

Questo è il risultato, nel quale si può apprezzare come l'impiego di colori possa essere più soddisfacente dell'impiego di simboli, soprattutto nel caso di colori per i quali è stato previsto un effetto di trasparenza, che consente una migliore rappresentazione dei singoli dati quando questi sono molto ravvicinati (vedasi ad esempio il secondo grafico in alto a destra).


Ed ecco un ultimo esempio, un grafico a barre (barplot) realizzato con ggplot che mostra come anche nei grafici di questo tipo i colori possono essere impiegati per identificare i sottoinsiemi identificati da specifici fattori, sempre impiegando le palette precedenti. Copiate e incollate nella Console di R questo script e premete ↵ Invio.

# PALETTE (TAVOLOZZE) PERSONALIZZATE con ggplot
# barplot differenziati in base a un fattore
#
library(ggplot2) # carica il pacchetto per la grafica
library(gridExtra) # carica il pacchetto per combinare i grafici in una sola figura
#
mydata <- data.frame(xval=1:15, yval=rnorm(15), casi=rep(c("A", "B", "C", "D", "E"), each=3)) # genera i dati di esempio
windows() # apre e inizializza una nuova finestra grafica
#
mypalette1 <- c("#F8A19F80", "#90AD1C80", "#F6222E80", "#1CFFCE80", "#2ED9FF80") # tavolozza di colori con trasparenza al 50% 
plot1 <- ggplot(mydata, aes(x=xval, y=yval, color=casi, fill=casi)) + geom_bar(stat="identity") + scale_color_manual(values=mypalette1) + scale_fill_manual(values=mypalette1) + theme_minimal()
#
mypalette2 <- c("#AA0DFE80", "#3283FE80", "#85660D80", "#782AB680", "#56565680") # tavolozza di colori con trasparenza al 50% 
plot2 <- ggplot(mydata, aes(x=xval, y=yval, color=casi, fill=casi)) + geom_bar(stat="identity") + scale_color_manual(values=mypalette2) + scale_fill_manual(values=mypalette2) + theme_minimal()
#
mypalette3 <- c("#1C8356", "#16FF32", "#F7E1A0", "#E2E2E2", "#1CBE4F") # tavolozza di colori senza trasparenza
plot3 <- ggplot(mydata, aes(x=xval, y=yval, color=casi, fill=casi)) + geom_bar(stat="identity") + scale_color_manual(values=mypalette3) + scale_fill_manual(values=mypalette3) + theme_minimal()
#
mypalette4 <- c("#C4451C", "#DEA0FD", "#FE00FA", "#325A9B", "#FEAF16") # tavolozza di colori senza trasparenza
plot4 <- ggplot(mydata, aes(x=xval, y=yval, color=casi, fill=casi)) + geom_bar(stat="identity") + scale_color_manual(values=mypalette4) + scale_fill_manual(values=mypalette4) + theme_minimal()
#
# combina i grafici in una sola figura
grid.arrange(plot1, plot2, plot3, plot4, nrow=2, ncol=2)
#

Questo è il risultato.


Conclusione: la realizzazione di colori personalizzati con le funzioni rgb(), hsv() e hcl() può rappresentare il punto di partenza per la loro combinazione in palette che possono essere salvate e riutilizzate al bisogno per dare un'impronta personale ai propri grafici.


----------


[2] Vedere il post Nomi e codici dei colori di R