R è un linguaggio adatto all'analisi statistica. In statistica si trattano continuamente vettori di elementi omogenei (tutti dello stesso tipo), e infatti R gestisce i vettori come un tipo primitivo, al pari dei numeri, dei booleani e delle stringhe. Anzi, in realtà il vettore è il tipo di R più semplice possibile: un numero per R non è altro che un vettore di numeri di lunghezza 1.
Ecco alcune funzioni (e operatori) per la costruzione di vettori:
c(v1, ...., vn)
restituisce un vettore i cui elementi, nell'ordine, sono v1
, ... vn
.
> c(1,10,4,2)
[1] 1 10 4 2
from:to
restituisce il vettore di tutti i numeri compresi tra from
e to
.
> 4:10
[1] 4 5 6 7 8 9 10
> 4.2:10
[1] 4.2 5.2 6.2 7.2 8.2 9.2
seq(from=1,to=1,by=1)
restituisce il vettore dei numeri compresi tra from
e to
, a passi di lunghezza by
. Notare che seq(from,to)
, senza il parametro by
, è esattamente uguale all'operatore :
(due punti).
> seq(4,10,3)
[1] 4 7 10
rep(x,times)
genera un vettore ottenuto replicando il vettore x
per il numero di volte times
.
> x=1:5
> rep(x,2)
[1] 1 2 3 4 5 1 2 3 4 5
Se il vettore generato è troppo lungo per essere visualizzato su una sola riga, sarà spezzato in righe consecutive. All'inizio di ogni riga, il simbolo [i]
(che per ora abbiamo sempre visto come [1]
) ci dice a che posizione del vettore corrisponde il primo elemento visualizzato in quella riga.
> 1:70 [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 [26] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 [51] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
Le espressioni sui vettori posso anche essere composte da più operazioni annidate, e vengono eseguite proprio come le espressioni sui numeri: prima si eseguono le operazioni all'interno delle parentesi più interne, poi si prosegue ad eseguire le operazioni più esterne. Ad esempio:
> rep(1:5,2) [1] 1 2 3 4 5 1 2 3 4 5
In seguito, per far vedere come viene eseguita una espressione complessa, si userà la seguente notazione (chiamata derivazione):
rep(1:5,2) => rep({1 2 3 4 5},2) => {1 2 3 4 5 1 2 3 4 5}
Questo vuol dire che prima 1:5
viene eseguita e genera il vettore {1 2 3 4 5}
, poi la rep
esterna viene eseguita e genera il vettore {1 2 3 4 5 1 2 4 5 5}
. Attenzione che rep({1 2 3 4 5},2)
non è un codice R valido. Le parentesi graffe sono eclusivamente una notazione che useremo all'interno delle derivazioni.
Tutti gli operatori e le funzioni aritmetiche si estendono direttamente ai vettori, sui quali vengono applicati elemento per elemento. Ad esempio, se x
e y
sono vettori numerici della stessa lunghezza, x+y
è il vettore in cui l'elemento i-esimo è la somma dell'elemento i-esimo di x
e dell'elemento i-esimo di y
. Analogamente sqrt(x)
è il vettore il cui elemento i-esimo è la radice quadrata dell'elemento i-esimo di x
.
> x=c(2,4,6) > x>5 [1] FALSE FALSE TRUE > x+1:3 [1] 3 6 9 > sqrt(x+1:3) [1] 1.732051 2.449490 3.000000
Notare che se una operazione coinvolge un vettore x
e un numero, allora il numero viene trasformato automaticamente in un vettore della stessa lunghezza di x
, e poi l'operazione ha luogo.
> x=c(2,4,6) > x+1 [1] 3 5 7
In realtà, questa procedura è più generale, e si applica ogni volta che si vuole operare con due vettori di lunghezza diversa. Quello più piccolo viene duplicato tante volte, fino ad avere la stessa lunghezza di quello più grande.
> c(1,2,3,4,5,6)+c(1,2) [1] 2 4 4 6 6 8
Se la lunghezza del vettore grande non è un multiplo esatto della lunghezza del vettore piccolo, l'operazione prosegue comunque come detto sopra, ma si genera un messaggio di avvertimento.
> c(1,2,3,4,5,6,7)+c(1,2) [1] 2 4 4 6 6 8 8 Warning message: In c(1, 2, 3, 4, 5, 6, 7) + c(1, 2) : longer object length is not a multiple of shorter object length
A parte quanto visto sopra, ovvero operazioni che agiscono elemento per elemento, esisono altre funzioni utili per la manipolazione di vettori che operano globalmente.
max(x)
restituisce il valore massimo del vettore x
;min(x)
restituisce il valore minimo del vettore x
;sum(x)
restituisce la somma di tutti gli elementi del vettore x
;prod(x)
restituisce il prodotto di tutti gli elementi del vettore x
;length(x)
restituisce la lunghezza del vettore x
;c(v1, ..., vn)
concatena i vettori v1
.... vn
.Ad esempio, la seguente espressione calcola la somma di tutti i numeri da 1 a 100.
> sum(1:100) [1] 5050
Notare che la funzione c
serve a due scopi: costruire un vettore elencandone gli elementi e concatenare i vettori. In realtà si tratta sempre della stessa cosa. Come abbiamo detto, in realtà R gestisce i numeri come vettori di lunghezza uno. Scrivere c(2,4,-1)
vuol dire quindi concatenare i vettore {2}
, {4}
, {-1}
.
Dato il vettore p
contenente una distribuzione di probabilità, che espressione R si può usare per calcolare il valore dell'entropia relativa a p
(ovvero la somma, per i che va da 1 alla lunghezza di p, di p[i] * log p[i])? Se p=c(0.5,0.3,0.2)
, il risultato di questa espressione dovrebbe essere 1.485475
. Si assuma che tutti gli elementi di p
siano diversi da zero.
Altri operatori si occupano di estrarre da un vettore un qualunque elemento o un suo sottovettore.
x[i]
estrae dal vettore x
l'elemento in posizione i
. A differenza che in Java (o in PHP), la prima posizione è la numero uno.
> x=c(1,10,4,5,20,2)
> x[2]
[1] 10
> c(9,8,7,6)[3]
[1] 7
> rep(1:5,2)[7]
[1] 2
Notare che è possibile applicare l'operatore di estrazione, così come qualunque operatore sui vettori, sia ad una variabile di tipo vettore, che direttamente ad una qualunque espressione. Questa, ad esempio, è la derivazione per l'ultima riga di cui sopra:
rep(1:5,2)[7] => rep({1 2 3 4 5},2)[7] => {1 2 3 4 5 1 2 3 4 5}[7] => 2
x[v]
dove v
è un vettore numerico, estrae da x
il sottovettore i cui indici sono presenti in v
.
> x=seq(1,20,by=2)
> x
[1] 1 3 5 7 9 11 13 15 17 19
> x[2:4]
[1] 3 5 7
> seq(1,20,by=2)[2:4]
[1] 3 5 7
È possibile usare valori negativi per v
e in questo caso si estraggono da x
tutti gli elementi tranne quelli di indice contenuti in v
(cambiato di segno). Ad esempio, x[-1]
estrare da x
tutti gli elementi tranne il primo. Non si possono mischiare in v
numeri positivi e negativi (il tutto sarebbe molto ambiguo).
> x[-2]
[1] 1 5 7 9 11 13 15 17 19
x[b]
dove b
è un vettore di booleani della stessa lunghezza di x
, estra da x
gli elementi posizione i per cui b[i]
è TRUE
. Se b
non ha la stessa lunghezza di x
allora b
viene duplicato più volte, come visto per le operazioni aritmetiche.
> c(10,4,5,1)[c(TRUE,FALSE,FALSE,TRUE)]
[1] 10 1
> seq(1,20,by=2)[c(TRUE,FALSE)]
[1] 1 5 9 13 17
La prima espressione estrae dal vettore c(10,4,5,1)
gli elementi in prima e quarta posizione, mentre la seconda espressione estrare da seq(1,20,by=2)
che è {1 3 5 7 9 11 13 15 17 19}
, gli elementi in posizione dispari.
Utilizzando queste operazioni di estrazione si possono realizzare facilmente operazioni di selezione molto complesse. Ad esempio, l'espressione x[x>0]
estrae da x
il sottovettore di tutti i suoi elementi positivi.
> x=c(-1,2,4,-3,0) > x[x>0] [1] 2 4
Questa è la derivazione corrispondente:
x[x>0] => {-1 2 4 -3, 0}[{-1 2 4 -3 0}>0] => {-1 2 4 -3 0}[{FALSE TRUE TRUE FALSE FALSE}] => {2 4}
ifelse
Una operazione simile alla selezione è quella fornita dalla funzione ifelse(test,yes,no)
. test
è un vettore di booleani, mentre yes
e no
devono essere vettori dello stesso tipo. Quello che fa questa funzione è creare un vettore delle stessa lunghezza di test
: per ogni i, da 1 alla lunghezza di test, l'elemento i-esimo del vettore risultato sarà preso da yes[i]
se test[i]
è TRUE
, da no[i]
altrimenti.
Normalmente i tre vettori devono essere tutti della stessa lunghezza, ma al solito R estende automaticamente i vettori più corti quando è necessario
> x=c(1,4,0,3,2,0) > ifelse(x==0,NaN,x+1) [1] 2 5 NaN 4 3 NaN
Questa è la derivazione corrispondente:
ifelse(x==0,NaN,x+1) => ifelse({1 4 0 3 2 0}==0,{NaN},{2 5 1 4 3 1}) => => ifelse({FALSE FALSE TRUE FALSE FALSE TRUE},{NaN NaN NaN NaN NaN NaN}{2 5 1 4 3 1})} => {2 5 NaN 4 3 NaN}
Migliorare l'esercizio precedente in modo che l'espressione funzioni anche quando p
contiene valori nulli. Ad esempio, se p=c(0,0.5,0.5)
, l'espressione deve restituire 1
(non altri valori e, in particolare, non deve restituire NaN
).