Vettorizzazione in Linguaggio R

I vettori sono alla base del linguaggio R. Attraverso di essi è possibile eseguire una singola operazione su tutti gli elementi di un vettore in modo molto efficiente. Questo concetto è chiamato vettorizzazione.

Introduzione alla Vettorizzazione in R

I vettori in linguaggio R risultano estremamente utili perché permettono di eseguire operazioni su un insieme di dati in modo molto efficiente ma soprattutto conciso. Questo concetto è chiamato vettorizzazione.

Per chiarire partiamo da un esempio. Supponiamo di avere il vettore seguente:

> vettore <- c(1, 2, 3, 4, 5)

Se volessimo moltiplicare ogni elemento del vettore per 2, in R possiamo scrivere:

> vettore * 2
[1]  2  4  6  8 10

In questo caso, R ha moltiplicato ogni singolo elemento del vettore per 2, restituendo un nuovo vettore con i risultati.

La potenza della vettorizzazione sta nel fatto che abbiamo dovuto scrivere semplicemente vettore * 2 ed automaticamente R ha eseguito l'operazione su ogni singolo elemento del vettore.

Analogamente possiamo sommare e sottrarre vettori tra di loro. Ad esempio, se avessimo un altro vettore vettore2:

> vettore2 <- c(5, 4, 3, 2, 1)

Potremmo sommare i due vettori in questo modo:

> vettore + vettore2
[1] 6 6 6 6 6

R, in maniera automatica, ha preso gli elementi dei due vettori corrispondenti allo stesso indice e li ha sommati tra di loro restituendo un nuovo vettore.

Analogamente possiamo moltiplicare elemento per elemento due vettori:

> vettore * vettore2
[1] 5 8 9 8 5

Si noti bene che in questo caso R non ha effettuato la moltiplicazione tra vettori come in algebra lineare, ma ha moltiplicato elemento per elemento i due vettori.

La principale potenza della vettorizzazione sta nel fatto che operazioni multiple sono eseguite in automatico e in modo molto efficiente. Questo rende R un linguaggio molto potente per l'analisi dati e la manipolazione di vettori numerici.

Definizione

Vettorizzazione in R

La vettorizzazione in R permette di eseguire la stessa operazione su tutti gli elementi di un vettore.

La sintassi per eseguire operazioni vettorizzate è la stessa che vale per gli elementi scalari.

Operazioni vettorializzate con vettori di lunghezza diversa

Negli esempi di sopra abbiamo usato vettori di lunghezza uguale. Cosa succede se usiamo vettori di lunghezza diversa?

In tal caso dobbiamo distinguere due casi:

  1. La lunghezza del vettore più corto è un multiplo intero della lunghezza del vettore più lungo;
  2. La lunghezza del vettore più corto non è un multiplo intero della lunghezza del vettore più lungo.

Partiamo dal primo caso. Per vedere cosa accade vediamo un esempio. Supponiamo di avere il vettore che segue:

> vettore3 <- c(1, 2, 3, 4, 5, 6)

In questo caso vettore3 è un vettore di lunghezza 6. Prendiamo il vettore vettore4 che segue, composto da soli 2 elementi:

> vettore4 <- c(1, -1)

Se proviamo a moltiplicare vettore3 per vettore4 otteniamo:

> vettore3 * vettore4
[1]  1 -2  3 -4  5 -6

In questo caso R non ha prodotto nessun errore ma, anzi, ha ripetuto il vettore più corto in modo da renderlo della stessa lunghezza del vettore più lungo. In sostanza è come se R avesse eseguito la seguente operazione:

> vettore3 * c(1, -1, 1, -1, 1, -1)
[1]  1 -2  3 -4  5 -6

Questo è stato possibile perché la lunghezza del vettore più corto è un multiplo intero della lunghezza del vettore più lungo.

Passiamo ora al secondo caso. Supponiamo di avere il vettore vettore5 che segue:

> vettore5 <- c(1, 2, 3, 4, 5, 6, 7)

Questo vettore è composto da 7 elementi. Prendiamo il vettore vettore6 che segue, composto da 3 elementi:

> vettore6 <- c(2, -2, 2)

Se proviamo a moltiplicare vettore5 per vettore6 otteniamo:

> vettore5 * vettore6
[1]   2  -4   6   8 -10  12  14
Warning message:
In vettore5 * vettore6 :
  longer object length is not a multiple of shorter object length

In sostanza quello che è accaduto è che R ha provato a ripetere il vettore più corto più volte. Quindi, per i primi 6 elementi di vettore5 ha potuto effettuare la moltiplicazione con vettore6. Per l'ultimo elemento di vettore5 ha potuto, invece, usare solo il primo elemento.

Per chiarire, quello che è accaduto è mostrato di seguito:

\begin{array}{ccccccrcr} \text{vettore5}[1] &amp; \cdot &amp; \text{vettore6}[1] &amp; \rightarrow &amp; 1 &amp; \cdot &amp; 2 &amp; \rightarrow &amp; 2 \\ \text{vettore5}[2] &amp; \cdot &amp; \text{vettore6}[2] &amp; \rightarrow &amp; 2 &amp; \cdot &amp; -2 &amp; \rightarrow &amp; -4 \\ \text{vettore5}[3] &amp; \cdot &amp; \text{vettore6}[3] &amp; \rightarrow &amp; 3 &amp; \cdot &amp; 2 &amp; \rightarrow &amp; 6 \\ \text{vettore5}[4] &amp; \cdot &amp; \text{vettore6}[1] &amp; \rightarrow &amp; 4 &amp; \cdot &amp; 2 &amp; \rightarrow &amp; 8 \\ \text{vettore5}[5] &amp; \cdot &amp; \text{vettore6}[2] &amp; \rightarrow &amp; 5 &amp; \cdot &amp; -2 &amp; \rightarrow &amp; -10 \\ \text{vettore5}[6] &amp; \cdot &amp; \text{vettore6}[3] &amp; \rightarrow &amp; 6 &amp; \cdot &amp; 2 &amp; \rightarrow &amp; 12 \\ \text{vettore5}[7] &amp; \cdot &amp; \color{red}{\text{vettore6}[1]} &amp; \rightarrow &amp; 7 &amp; \cdot &amp; \color{red}{2} &amp; \rightarrow &amp; 14 \\ \end{array}

Anche se R ha prodotto un risultato, ha anche generato un messaggio di avvertimento. Questo messaggio ci avvisa che la lunghezza del vettore più lungo non è un multiplo intero della lunghezza del vettore più corto.

Ricapitolando:

Definizione

Operazioni vettorializzate con vettori di lunghezza diversa

Quando R esegue un'operazione vettorializzata tra due vettori di lunghezza diversa, se la lunghezza del vettore più corto non è un multiplo intero della lunghezza del vettore più lungo, R restituisce un messaggio di avvertimento e procede con l'operazione elemento per elemento replicando il vettore più corto fino a raggiungere la lunghezza del vettore più lungo.

Generalizzazione della Vettorizzazione

In R tutti i valori scalari, come i semplici numeri, possono essere considerati a tutti gli effetti come vettori di lunghezza 1. Questo significa che possiamo eseguire operazioni vettorializzate anche tra scalari e vettori.

Per cui, tenendo presente quanto scritto sopra, possiamo scrivere:

> 2 * vettore
[1]  2  4  6  8 10

In questo caso R ha moltiplicato ogni singolo elemento del vettore per 2, restituendo un nuovo vettore con i risultati.

R mette a disposizione, inoltre, delle funzioni vettorizzate, ossia funzioni che operano su un vettore restituendo un risultato che dipende da tutti i valori del vettore stesso.

Ad esempio, esiste la funzione sum che restituisce la somma di tutti gli elementi di un vettore:

> vettore <- c(1, 2, 3, 4, 5)
> sum(vettore)
[1] 15

Analogamente esiste la funzione prod che restituisce il prodotto di tutti gli elementi di un vettore:

> prod(vettore)
[1] 120

Il vantaggio delle funzioni vettorizzate non è semplicemente di tipo sintattico, ossia che ci permettono di scrivere codice più conciso, ma è anche di tipo prestazionale. Infatti, le funzioni vettorizzate sono ottimizzate per eseguire operazioni su vettori in modo molto efficiente rispetto ad eseguire la singola operazione più volte.

Definizione

Funzioni Vettorizzate

Le fuzioni vettorizzate in R sono funzioni che operano su un vettore restituendo un risultato che dipende da tutti i valori del vettore stesso.

Esempi

Proviamo ad applicare la vettorizzazione studiano alcuni esempi.

Partiamo da un primo esempio. Supponiamo di avere il vettore che segue:

> vettore <- c(2, 4, 6, 2, 4, 6, 2, 4, 6)

Vogliamo scrivere un'espressione che restituisca un vettore composto da soli 1. Possiamo scrivere:

> vettore / c(2, 4, 6)
[1] 1 1 1 1 1 1 1 1 1

In questo caso R ha eseguito la divisione elemento per elemento tra vettore e il vettore c(2, 4, 6) che è stato replicato 3 volte.

Passiamo ad un secondo esempio. Supponiamo di avere un vettore che contiene una serie di temperature in gradi centigradi:

> temperature <- c(20, 25, 30, 35, 40)

Vogliamo convertire queste temperature in gradi Fahrenheit. La formula per convertire i gradi centigradi in gradi Fahrenheit è la seguente:

F = \frac{9}{5}C + 32

Dove F è la temperatura in gradi Fahrenheit e C è la temperatura in gradi centigradi.

Possiamo scrivere:

> (9 / 5) * temperature + 32
[1] 68 77 86 95 104

In Sintesi

In questa lezione abbiamo studiato che:

  • La vettorizzazione in R permette di eseguire la stessa operazione su tutti gli elementi di un vettore.
  • Le operazioni vettorializzate possono essere eseguite anche tra vettori di lunghezza diversa. In tal caso R replica il vettore più corto fino a raggiungere la lunghezza del vettore più lungo.
  • In R tutti i valori scalari possono essere considerati a tutti gli effetti come vettori di lunghezza 1. Questo significa che possiamo eseguire operazioni vettorializzate anche tra scalari e vettori.
  • R mette a disposizione delle funzioni vettorizzate che operano su un vettore restituendo un risultato che dipende da tutti i valori del vettore stesso.

Con questa lezione abbiamo concluso il primo capitolo della nostra guida al linguaggio R. A partire dal prossimo capitolo inizieremo a studiare le matrici e gli array in R.