Puntamento e dintorni

Alla fine di questa puntata…

  • dovreste riuscire ad accedere/modificare gli elementi di qualunque oggetto
  • dovreste riuscire a “filtrare” gli oggetti in base a condizioni
  • dovreste riuscire ad indicizzare un oggetto

e molto probabilmente…

  • a questo punto ci siamo, vi tocca rispondere: “ma fa veramente al caso mio?”

Essere o non essere

Riprendiamo il lavoro fatto:

rm(list=ls())
load("introduzioneR_updated.RData")
vettoreLunghezza10
lun mar mer gio ven lun mar mer gio ven 
  1   2   3   4   5   6   7   8   9  10 

I valori booleani TRUE e FALSE sono trattati nelle operazioni algebriche come 1 e 0 rispettivamente:

vettoreLunghezza10 > 5
  lun   mar   mer   gio   ven   lun   mar   mer   gio   ven 
FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE 
as.numeric(vettoreLunghezza10 > 5)
 [1] 0 0 0 0 0 1 1 1 1 1

Questo permette di contare il numero di elementi che soddisfano una o più condizioni usando la funzione sum:

sum(vettoreLunghezza10 > 5)
[1] 5

Questo in alternativa all’estrazione degli elementi e al successivo controllo della lunghezza:

length(vettoreLunghezza10[vettoreLunghezza10 > 5])
[1] 5

NOTA: le parentesi quadre servono per accedere agli elementi di un oggetto (con qualche particolarità a seconda del tipo di oggetto - vedi a seguire)

MEMO: le parentesi tonde servono per: - cambiare l’ordine di priorità delle operazioni - stampare nel caso di un’assegnazione esplicita

Come ne caviamo fuori qualcosa?

La funzione which restituisce invece le posizioni degli elementi che soddisfano la condizione:

which(vettoreLunghezza10 > 5)
lun mar mer gio ven 
  6   7   8   9  10 

Queste posizioni possono essere utilizzate per estrarre gli elementi

vettoreLunghezza10[which(vettoreLunghezza10 > 5)]
lun mar mer gio ven 
  6   7   8   9  10 

E’ possibile però (più velocemente) passare in input all’operatore di estrazione [ direttamente il vettore di booleani

vettoreLunghezza10 > 5
  lun   mar   mer   gio   ven   lun   mar   mer   gio   ven 
FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE 
vettoreLunghezza10[vettoreLunghezza10 > 5]
lun mar mer gio ven 
  6   7   8   9  10 

Pari o dispari?

Proviamo ad esempio ad estrarre i numeri pari dal vettore resto della divisione per due:

vettoreLunghezza10 %% 2
lun mar mer gio ven lun mar mer gio ven 
  1   0   1   0   1   0   1   0   1   0 

I numeri pari hanno resto pari a 0:

vettoreLunghezza10 %% 2 == 0
  lun   mar   mer   gio   ven   lun   mar   mer   gio   ven 
FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE 

Per cui si può sapere quali sono le posizioni degli elementi che soddisfano la condizione usando la funzione which:

which(vettoreLunghezza10 %% 2 == 0)
mar gio lun mer ven 
  2   4   6   8  10 

ed estrarre gli elementi usando la funzione [

vettoreLunghezza10[vettoreLunghezza10 %% 2 == 0]
mar gio lun mer ven 
  2   4   6   8  10 

Analogamente, ecco i numeri divisibili per 3:

vettoreLunghezza10 %% 3 == 0
  lun   mar   mer   gio   ven   lun   mar   mer   gio   ven 
FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE 
which(vettoreLunghezza10 %% 3 == 0)
mer lun gio 
  3   6   9 

Quando ci sono due condizioni…

E’ possibile controllare più condizioni contemporaneamente: l’operatore & (AND logico) controlla se le due condizioni sono verificate simultaneamente; l’operatore | (OR logico) controlla se almeno una delle due condizioni è verificata

Controlliamo se il numero è divisibile sia per 2 che per 3:

vettoreLunghezza10 %% 2 == 0 & vettoreLunghezza10 %% 3 == 0
  lun   mar   mer   gio   ven   lun   mar   mer   gio   ven 
FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE 

Questa è la posizione del numero in questione

which((vettoreLunghezza10 %% 2 == 0 & vettoreLunghezza10 %% 3 == 0))
lun 
  6 

e questo è il numero:

vettoreLunghezza10[(vettoreLunghezza10 %% 2 == 0 & vettoreLunghezza10 %% 3 == 0)]
lun 
  6 

Controlliamo se il numero è divisibile per 2 o per 3:

vettoreLunghezza10 %% 2 == 0 | vettoreLunghezza10 %% 3 == 0
  lun   mar   mer   gio   ven   lun   mar   mer   gio   ven 
FALSE  TRUE  TRUE  TRUE FALSE  TRUE FALSE  TRUE  TRUE  TRUE 

Possiamo negare la condizione usando l’operatore ! (NOT logico): in questo caso ci chiediamo quale numero non è divisibile per 2 o per 3:

!(vettoreLunghezza10 %% 2 == 0 | vettoreLunghezza10 %% 3 == 0)
  lun   mar   mer   gio   ven   lun   mar   mer   gio   ven 
 TRUE FALSE FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE FALSE 

Tutti, nessuno o almeno uno…

La funzione any controlla se la condizione è verificata su almeno uno degli elementi del vettore considerato, mentre la funzione all controlla se la condizione è verificata per tutti gli elementi.

  • Si tratta di tutti numeri interi?
all(vettoreLunghezza10%%2 == 0)
[1] FALSE
  • Non c’é nessun numero maggiore di 10?
!all(vettoreLunghezza10 > 10)
[1] TRUE
  • Ci sono numeri divisibili per 2 oppure per 3?
any(vettoreLunghezza10%%2 == 0 | vettoreLunghezza10%%3 == 0)
[1] TRUE
any(vettoreLunghezza10%%2 == 0, vettoreLunghezza10%%3 == 0)
[1] TRUE
  • Ci sono numeri divisibili per 2 e per 3?
any(vettoreLunghezza10%%2 == 0 & vettoreLunghezza10%%3 == 0)
[1] TRUE
  • C’è almeno un numero non divisibile per due o per tre?
any(!(vettoreLunghezza10 %% 2 == 0 | vettoreLunghezza10 %% 3 == 0))
[1] TRUE
  • Non c’è nessun nessun che non sia divisibile per due o per tre?
all(!(vettoreLunghezza10 %% 2 == 0 | vettoreLunghezza10 %% 3 == 0))
[1] FALSE

Proviamo su strutture dati più complesse?

Si può ripetere la stessa cosa su un oggetto di tipo matrice: controllo se i numeri contenuti sono divisibile per 2:

matrice1
      colonna1 colonna2
riga1        1        2
riga2        3        4
riga3        5        6
riga4        7        8
riga5        9       10
attr(,"names")
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
matrice1 %% 2 == 0
      colonna1 colonna2
riga1    FALSE     TRUE
riga2    FALSE     TRUE
riga3    FALSE     TRUE
riga4    FALSE     TRUE
riga5    FALSE     TRUE

In questo caso le posizioni degli elementi che soddisfano la condizione sono restituite usando un solo indice di puntamento che scorre per colonna:

which(matrice1 %% 2 == 0)
[1]  6  7  8  9 10

Se vado ad estrarre gli elementi che soddisfano la condizione richiesta, devo accettare il passaggio dalla matrice al vettore:

matrice1[matrice1 %% 2 == 0]
 f  g  h  i  j 
 2  4  6  8 10 

Lo stesso accade sull’oggetto di tipo array

array3d
, , strato1

      colonna1 colonna2 colonna3
riga1        1        5        9
riga2        2        6       10
riga3        3        7       11
riga4        4        8       12

, , strato2

      colonna1 colonna2 colonna3
riga1       13       17       21
riga2       14       18       22
riga3       15       19       23
riga4       16       20       24

attr(,"names")
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x"
array3d %% 2 == 0
, , strato1

      colonna1 colonna2 colonna3
riga1    FALSE    FALSE    FALSE
riga2     TRUE     TRUE     TRUE
riga3    FALSE    FALSE    FALSE
riga4     TRUE     TRUE     TRUE

, , strato2

      colonna1 colonna2 colonna3
riga1    FALSE    FALSE    FALSE
riga2     TRUE     TRUE     TRUE
riga3    FALSE    FALSE    FALSE
riga4     TRUE     TRUE     TRUE
which(array3d %% 2 == 0)
 [1]  2  4  6  8 10 12 14 16 18 20 22 24
array3d[array3d %% 2 == 0]
 b  d  f  h  j  l  n  p  r  t  v  x 
 2  4  6  8 10 12 14 16 18 20 22 24 

Chi cerca trova?

Per indicizzare un oggetto è possibile usare: - un vettore di interi (positivi o negativi) - un vettore di valori booleani - i nomi (“positivi” o “negativi”)

Inizia la caccia: ricerca usando le posizioni

Vediamo come è possibile accedere ai vari elementi di un oggetto (chiaramente questo permette sia di estrarre gli elementi che di cambiarne il valore)

L’operatore per accedere agli elementi è la [

E’ possibile usare un vettore di interi che indica la posizione degli elementi cui si vuole accedere. Il vettore può essere composto: - di numeri positivi, che indicano le posizioni di interesse - di numeri negativi per escludere particolari posizioni

Primo elemento:

vettoreLunghezza10[1]
lun 
  1 

Primo e terzo elemento:

vettoreLunghezza10[c(1, 3)]
lun mer 
  1   3 

Escludo il primo e il terzo elemento:

vettoreLunghezza10[c(-1, -3)]
mar gio ven lun mar mer gio ven 
  2   4   5   6   7   8   9  10 

Continua la caccia: ricerca usando condizioni

Posso utilizzare anche un vettore di valori logici (TRUE/FALSE): l’operatore [ in questo caso restituisce solo gli elementi corrispondenti alle posizioni TRUE

vettoreLunghezza3
[1] 1 2 3
vettoreLunghezza3[c(T,F,T)]
[1] 1 3

L’uso dei vettori di valori logici permette di estrarre elementi sfruttando gli operatori relazionali: l’operatore relazione restituisce infatti un vettore di valori logici (TRUE/FALSE)

vettoreLunghezza3 %% 2 == 0
[1] FALSE  TRUE FALSE

che può essere passato in input all’operatore [

vettoreLunghezza3[vettoreLunghezza3 %% 2 == 0]
[1] 2

Nel caso il vettore di valori logici passato all’operatore [ sia di lunghezza inferiore al numero di elementi contenuti nel vettore cui si accede, viene applicata la regola del riciclaggio

vettoreLunghezza10
lun mar mer gio ven lun mar mer gio ven 
  1   2   3   4   5   6   7   8   9  10 
vettoreLunghezza10[c(T)]
lun mar mer gio ven lun mar mer gio ven 
  1   2   3   4   5   6   7   8   9  10 
vettoreLunghezza10[c(F)]
named integer(0)
vettoreLunghezza10[c(T,F)]
lun mer ven mar gio 
  1   3   5   7   9 

Ancora a caccia: ricerca per nomi

E’ possibile sfruttare anche i nomi per accedere agli elementi del vettore: attenzione, nel caso di nomi ripetuti viene restituito solo il primo elemento se si passa la stringa all’operatore [

vettoreLunghezza10
lun mar mer gio ven lun mar mer gio ven 
  1   2   3   4   5   6   7   8   9  10 
vettoreLunghezza10["lun"]
lun 
  1 

Si può ovviare al problema lavorando direttamente sull’attributo names

names(vettoreLunghezza10) == "lun"
 [1]  TRUE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE
which(names(vettoreLunghezza10) == "lun")
[1] 1 6
vettoreLunghezza10[names(vettoreLunghezza10) == "lun"]
lun lun 
  1   6 

Estensione al caso di strutture dati più complesse

Le stesse regole valgono anche per le matrici: se si utilizza un solo indice per il puntamento si sta scorrendo la matrice per colonna

matrice1
      colonna1 colonna2
riga1        1        2
riga2        3        4
riga3        5        6
riga4        7        8
riga5        9       10
attr(,"names")
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
matrice1[7]
g 
4 
matrice1[c(2,7)]
b g 
3 4 

Nel caso delle matrici, lavorando con un solo indice e con gli operatori relazionali, si ottiene in output un vettore con gli elementi della matrice che soddisfano la/e condizione/i richiesta

matrice1 > 4
      colonna1 colonna2
riga1    FALSE    FALSE
riga2    FALSE    FALSE
riga3     TRUE     TRUE
riga4     TRUE     TRUE
riga5     TRUE     TRUE
matrice1[matrice1 > 4]
 c  d  e  h  i  j 
 5  7  9  6  8 10 

Questo vale anche nel caso la condizione è verificata per un blocco rettangolare che potrebbe quindi essere restituito ancora come matrice

(matrice1 > 3 & matrice1 <6) | (matrice1 > 8)
      colonna1 colonna2
riga1    FALSE    FALSE
riga2    FALSE     TRUE
riga3     TRUE    FALSE
riga4    FALSE    FALSE
riga5     TRUE     TRUE
matrice1[(matrice1 > 3 & matrice1 <6) | (matrice1 > 8)]
 c  e  g  j 
 5  9  4 10 

Se si utilizza un doppio indice si sta scorrendo la matrice per riga (primo numero) e per colonna (secondo numero): posso usare una sintassi per accedere agli elementi di una matrice che sfrutta due indici: il primo è l’indice di riga e il secondo è l’indice di colonna

Per accedere all’elemento (prima riga, seconda colonna):

matrice1[1,2]
[1] 2

Per accedere all’intera prima riga:

matrice1[1,]
colonna1 colonna2 
       1        2 

Per accedere all’intera seconda colonna:

matrice1[,2]
riga1 riga2 riga3 riga4 riga5 
    2     4     6     8    10 

Per accedere a tutta la matrice, in alternativa al nome dell’oggetto, posso quindi usare:

matrice1[,]
      colonna1 colonna2
riga1        1        2
riga2        3        4
riga3        5        6
riga4        7        8
riga5        9       10

NOTA: vedi sotto per una differenza con l’accesso usando il solo nome nel caso di assegnazione

Anche in questo caso posso usare su ciascuna delle due dimensioni un vettore di posizioni. Ad esempio estraggo la sottomatrice considerando la prima e la terza riga:

matrice1[c(1,3),]
      colonna1 colonna2
riga1        1        2
riga3        5        6

Dalla prima alla terza riga:

matrice1[1:3,]
      colonna1 colonna2
riga1        1        2
riga2        3        4
riga3        5        6

Nel caso in cui l’estrazione corrisponde ad un vettore l’oggetto in output viene automaticamente semplificato (si perde la dimensione):

matrice1[1:2,2]
riga1 riga2 
    2     4 
class(matrice1[1:2,2])
[1] "integer"

Da confrontare con l’analogo nel caso di estrazione di una sottomatrice:

matrice1[1:3,]
      colonna1 colonna2
riga1        1        2
riga2        3        4
riga3        5        6
class(matrice1[1:3,])
[1] "matrix" "array" 

Una sintassi analoga permette di accedere agli elementi di un array a più dimensioni, naturalmente includendo un indice per ciascuna delle dimensioni considerate.

Elemento sulla prima riga, terza colonna, secondo strato:

array3d[1,3,2]
[1] 21

Estraggo il primo strato:

array3d[,,1]
      colonna1 colonna2 colonna3
riga1        1        5        9
riga2        2        6       10
riga3        3        7       11
riga4        4        8       12

Anche in questo caso, ove possibile, la struttura viene semplificata:

class(array3d)
[1] "array"
class(array3d[,,1])
[1] "matrix" "array" 

Estraggo la prima riga e tutte le colonne per ciascuno strato:

array3d[1,,]
         strato1 strato2
colonna1       1      13
colonna2       5      17
colonna3       9      21

Attenzione alla disposizione dell’output: la prima colonna corrisponde alla prima riga del primo strato e la seconda colonna alla prima riga del secondo strato:

array3d[1,,1]
colonna1 colonna2 colonna3 
       1        5        9 
array3d[1,,2]
colonna1 colonna2 colonna3 
      13       17       21 

Discorso analogo vale se lavoro con gli indici di colonna:

array3d[,2,]
      strato1 strato2
riga1       5      17
riga2       6      18
riga3       7      19
riga4       8      20
array3d[,2,1]
riga1 riga2 riga3 riga4 
    5     6     7     8 
array3d[,2,2]
riga1 riga2 riga3 riga4 
   17    18    19    20 

Anche per gli array posso usare un vettore di indici per indicare le righe/colonne cui sono interessato (se gli indici sono positivi) o da escludere (se gli indici sono negativi).

Estraggo, per ciascuno strato, gli elementi sulla prima e terza riga (tutte le colonne):

array3d[c(1,3),,]
, , strato1

      colonna1 colonna2 colonna3
riga1        1        5        9
riga3        3        7       11

, , strato2

      colonna1 colonna2 colonna3
riga1       13       17       21
riga3       15       19       23

Estraggo, per ciascuno strato, gli elementi dalla prima alla terza riga (tutte le colonne):

array3d[1:3,,]
, , strato1

      colonna1 colonna2 colonna3
riga1        1        5        9
riga2        2        6       10
riga3        3        7       11

, , strato2

      colonna1 colonna2 colonna3
riga1       13       17       21
riga2       14       18       22
riga3       15       19       23

In alternativa avrei potuto escludere la quarta riga per ciascuno strato:

array3d[-4,,]
, , strato1

      colonna1 colonna2 colonna3
riga1        1        5        9
riga2        2        6       10
riga3        3        7       11

, , strato2

      colonna1 colonna2 colonna3
riga1       13       17       21
riga2       14       18       22
riga3       15       19       23

Questa volta escludo la prima e la quarta riga per ciascuno strato:

array3d[c(-1,-4),,]
, , strato1

      colonna1 colonna2 colonna3
riga2        2        6       10
riga3        3        7       11

, , strato2

      colonna1 colonna2 colonna3
riga2       14       18       22
riga3       15       19       23

Anche per gli array, laddove definiti, posso usare i nomi per puntare agli elementi:

attributes(array3d)
$dim
[1] 4 3 2

$names
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x"

$dimnames
$dimnames[[1]]
[1] "riga1" "riga2" "riga3" "riga4"

$dimnames[[2]]
[1] "colonna1" "colonna2" "colonna3"

$dimnames[[3]]
[1] "strato1" "strato2"

Lavorando con i nomi degli elementi devo usare la sintassi con il singolo indice

array3d["x"]
 x 
24 
array3d[c("b","x")]
 b  x 
 2 24 

Posso analogamente lavorare sui nomi delle dimensioni. NOTA: attenzione alla disposizione dell’output (i nomi ci aiutano a capire la “provenienza” dei vari vettori)

array3d["riga1",,]
         strato1 strato2
colonna1       1      13
colonna2       5      17
colonna3       9      21
array3d[,"colonna3",]
      strato1 strato2
riga1       9      21
riga2      10      22
riga3      11      23
riga4      12      24
array3d[,,"strato2"]
      colonna1 colonna2 colonna3
riga1       13       17       21
riga2       14       18       22
riga3       15       19       23
riga4       16       20       24

Anche nel caso dei nomi posso usare un vettore di nomi:

array3d[c("riga1","riga3"),,]
, , strato1

      colonna1 colonna2 colonna3
riga1        1        5        9
riga3        3        7       11

, , strato2

      colonna1 colonna2 colonna3
riga1       13       17       21
riga3       15       19       23

Con i nomi non posso però usare la negazione per escludere l’elemento:

array3d[-"x"]
array3d[-c("riga1","riga2"),,]
array3d[c(-"riga1",-"riga2"),,]

La sintassi in questo caso diventa più macchinosa per escludere l’elemento di nome b

array3d[names(array3d)!="b"]
 a  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x 
 1  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 

Per escludere gli elementi sulla riga di nome riga1:

array3d[rownames(array3d)!="riga1"]
 b  c  d  f  g  h  j  k  l  n  o  p  r  s  t  v  w  x 
 2  3  4  6  7  8 10 11 12 14 15 16 18 19 20 22 23 24 

Per escludere gli elementi sulle righe di nome riga1 e riga3:

array3d[rownames(array3d)!="riga1" & rownames(array3d)!="riga3"]
 b  d  f  h  j  l  n  p  r  t  v  x 
 2  4  6  8 10 12 14 16 18 20 22 24 

Sull’array posso usare un vettore di valori logici, facendo attenzione al fatto che la struttura di output in questo caso viene sempre semplificata. I numeri > 12 si trovano tutti nel secondo strato dell’array e quindi potrebbero essere restituiti come matrice ma questo non avviene:

array3d > 12
, , strato1

      colonna1 colonna2 colonna3
riga1    FALSE    FALSE    FALSE
riga2    FALSE    FALSE    FALSE
riga3    FALSE    FALSE    FALSE
riga4    FALSE    FALSE    FALSE

, , strato2

      colonna1 colonna2 colonna3
riga1     TRUE     TRUE     TRUE
riga2     TRUE     TRUE     TRUE
riga3     TRUE     TRUE     TRUE
riga4     TRUE     TRUE     TRUE
array3d[array3d > 12]
 m  n  o  p  q  r  s  t  u  v  w  x 
13 14 15 16 17 18 19 20 21 22 23 24 

Sia per i vettori che per le matrici che per gli array posso accedere agli elementi con la sintassi vista sopra per riassegnare nuovi valori alle posizioni specificate:

vettoreLunghezza10[c(1, 5)]
lun ven 
  1   5 
vettoreLunghezza10[c(1, 5)] <- c(10, 50)
vettoreLunghezza10
lun mar mer gio ven lun mar mer gio ven 
 10   2   3   4  50   6   7   8   9  10 

Anche nel caso dell’assegnazione vale la regola del riciclaggio:

vettoreLunghezza10[c(1, 5)] <- 0
vettoreLunghezza10
lun mar mer gio ven lun mar mer gio ven 
  0   2   3   4   0   6   7   8   9  10 

Con lo stesso messaggio di warning visto in precedenza

vettoreLunghezza10[1:5] <- 1:3
Warning in vettoreLunghezza10[1:5] <- 1:3: number of items to replace is not a
multiple of replacement length
vettoreLunghezza10
lun mar mer gio ven lun mar mer gio ven 
  1   2   3   1   2   6   7   8   9  10 

NOTA: Per accedere a tutti gli elementi di un vettore/matrice/array3d posso usare sia solo il nome della variabile che una sintassi con l’operatore [

Ad esempio per la matrice1 posso scrivere:

matrice1
      colonna1 colonna2
riga1        1        2
riga2        3        4
riga3        5        6
riga4        7        8
riga5        9       10
attr(,"names")
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
matrice1[]
      colonna1 colonna2
riga1        1        2
riga2        3        4
riga3        5        6
riga4        7        8
riga5        9       10
attr(,"names")
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
matrice1[,]
      colonna1 colonna2
riga1        1        2
riga2        3        4
riga3        5        6
riga4        7        8
riga5        9       10

Rispetto all’estrazione di elementi non fa alcuna differenza ma una differenza è riscontrabile se invece si fa riferimento all’assegnazione di elementi:

varAppoggio <- matrice1
varAppoggio
      colonna1 colonna2
riga1        1        2
riga2        3        4
riga3        5        6
riga4        7        8
riga5        9       10
attr(,"names")
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
varAppoggio <- 10
varAppoggio
[1] 10

Usando una delle sintassi con l’operatore [ l’assegnazione avviene invece preservando la struttura dell’oggetto

varAppoggio <- matrice1
varAppoggio[] <- 100
varAppoggio
      colonna1 colonna2
riga1      100      100
riga2      100      100
riga3      100      100
riga4      100      100
riga5      100      100
attr(,"names")
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"

L’effetto “fisarmonica”

Una cosa abbastanza particolare è il ridimensionamento automatico del vettore in fase di assegnazione. Se provo ad accedere al 15° elemento del vettore ho uno strano ouput:

vettoreLunghezza10[15]
<NA> 
  NA 

Che forse diventa più chiaro se assegno un valore al quindicesimo elemento (che non esiste):

vettoreLunghezza10[15] <- 15
vettoreLunghezza10
lun mar mer gio ven lun mar mer gio ven                     
  1   2   3   1   2   6   7   8   9  10  NA  NA  NA  NA  15 

NOTA: il ridimensionamento automatico non funziona nel caso di matrici e array

matrice1
matrice1[6,4]
matrice1[6,4] <- 10

Ricerca su liste

Creazione e stampa di una lista:

lista <- list(vettore=1:10, matrice1=matrix(1:12, 4, 3), testo=letters[1:5])
lista
$vettore
 [1]  1  2  3  4  5  6  7  8  9 10

$matrice1
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

$testo
[1] "a" "b" "c" "d" "e"

Creazione e stampa di un dataframe:

df <- data.frame(a=letters[1:10], b=1:10, c=10:1)
df
   a  b  c
1  a  1 10
2  b  2  9
3  c  3  8
4  d  4  7
5  e  5  6
6  f  6  5
7  g  7  4
8  h  8  3
9  i  9  2
10 j 10  1

Quanti elementi ci sono nella lista?

length(lista)
[1] 3

E quanti nel dataframe?

length(df)
[1] 3

MEMO: Il dataframe è un tipo particolare di lista:

is.list(df)
[1] TRUE
is.data.frame(df)
[1] TRUE
as.list(df)
$a
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"

$b
 [1]  1  2  3  4  5  6  7  8  9 10

$c
 [1] 10  9  8  7  6  5  4  3  2  1

Sia la lista che il dataframe sono contenitori per oggetti di tipo diverso:

is.atomic(lista)
[1] FALSE
is.atomic(df)
[1] FALSE

Per puntare agli elementi della lista ci sono diverse opzioni: - accesso attraverso l’indice dell’elemento usando l’operatore di estrazione [[

Con l’operatore [[ si accede direttamente all’elemento della lista (semplificando la struttura di output)

lista[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10
is.atomic(lista[[1]])
[1] TRUE

Si può usare anche l’operatore di estrazione [

lista[1]
$vettore
 [1]  1  2  3  4  5  6  7  8  9 10

ma in questo caso viene restituita una sottolista con un solo elemento

is.atomic(lista[1])
[1] FALSE
is.list(lista[1])
[1] TRUE

L’operatore [ permette però di accedere a più elementi della lista

lista[c(1,3)]
$vettore
 [1]  1  2  3  4  5  6  7  8  9 10

$testo
[1] "a" "b" "c" "d" "e"

Questo non è invece possibile usando l’operatore [[. Se si prova il comando:

lista[[c(1,3)]]
[1] 3

E’ come se stessi scrivendo:

lista[[1]][3]
[1] 3

Stesso problema si ha se si cerca di usare la [[ con un indice negativo:

lista[[-2]]

Sintassi consentita con la [ per escludere uno o più elementi:

lista[-2]
$vettore
 [1]  1  2  3  4  5  6  7  8  9 10

$testo
[1] "a" "b" "c" "d" "e"
lista[c(-1,-3)]
$matrice1
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

E’ possibile sfruttare i nomi degli elementi nel caso di una lista con nomi:

names(lista)
[1] "vettore"  "matrice1" "testo"   

In questo caso è possibile usare l’operatore $ tra nome della lista e nome dell’elemento che si vuole estrarre

lista$vettore
 [1]  1  2  3  4  5  6  7  8  9 10

In alternativa è possibile usare la [ o le [[ con le differenze viste nel caso degli indici:

lista[["vettore"]]
 [1]  1  2  3  4  5  6  7  8  9 10
is.atomic(lista[["vettore"]])
[1] TRUE
lista["vettore"]
$vettore
 [1]  1  2  3  4  5  6  7  8  9 10
is.atomic(lista["vettore"])
[1] FALSE

Per estrarre due o più elementi è però necessario usare la singola [

lista[c("vettore", "testo")]
$vettore
 [1]  1  2  3  4  5  6  7  8  9 10

$testo
[1] "a" "b" "c" "d" "e"

Così come con gli indici non è possibile usare le [[

lista[[c("vettore", "testo")]]

Il dataframe è una particolare lista: valgono quindi tutte le cose viste per la lista

df[[1]]
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
class(df[[1]])
[1] "character"
df[1]
   a
1  a
2  b
3  c
4  d
5  e
6  f
7  g
8  h
9  i
10 j
class(df[[2]])
[1] "integer"
df$a
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
df[c("a","c")]
   a  c
1  a 10
2  b  9
3  c  8
4  d  7
5  e  6
6  f  5
7  g  4
8  h  3
9  i  2
10 j  1
df[-2]
   a  c
1  a 10
2  b  9
3  c  8
4  d  7
5  e  6
6  f  5
7  g  4
8  h  3
9  i  2
10 j  1

In più per i dataframe è possibile usare la singola [ anche con la sintassi di puntamento vista per le matrici.

Ecco alcuni esempi: - per estrarre la prima colonna

df[,1]
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
  • per estrarre la prima e la terza colonna
df[,c(1,3)]
   a  c
1  a 10
2  b  9
3  c  8
4  d  7
5  e  6
6  f  5
7  g  4
8  h  3
9  i  2
10 j  1
  • per escludere la seconda colonna
df[,-2]
   a  c
1  a 10
2  b  9
3  c  8
4  d  7
5  e  6
6  f  5
7  g  4
8  h  3
9  i  2
10 j  1
  • per estrarre la prima riga
df[2,]
  a b c
2 b 2 9
  • per escludere la prima riga
df[-1,]
   a  b c
2  b  2 9
3  c  3 8
4  d  4 7
5  e  5 6
6  f  6 5
7  g  7 4
8  h  8 3
9  i  9 2
10 j 10 1
  • per accedere all’elemento sulla riga 5 - colonna 2
df[5, 2]
[1] 5
  • per estarre un blocco: righe da 5 a 10 + colonna 1 e 2
df[5:10, c(1,3)]
   a c
5  e 6
6  f 5
7  g 4
8  h 3
9  i 2
10 j 1

E’ possibile utilizzare in combinazione la sintassi per accedere agli elementi della lista e poi ai particolari elementi: - estrae la matrice alla seconda posizione della lista

lista[[2]]
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
  • estrae la seconda e terza colonna della matrice che si trova alla seconda posizione della lista
lista[[2]][,c(2,3)]
     [,1] [,2]
[1,]    5    9
[2,]    6   10
[3,]    7   11
[4,]    8   12