Dati in R: tipi e classi

Matilde Trevisani

2024-03-14

Vettori

“Everything that exists in R is an object”. I vettori sono uno degli oggetti (o strutture di dati) più importanti. Il più semplice vettore è uno scalare, i.e., un singolo valore. Ecco qualche esempio (numerico, di testo e logico):

a <- 10
b <- 3 / 10
d <- "star"
e <- "10"
f <- T|F 
g <- T|NA 

Domande veloci

  1. Perchè non ho usato il nome c?
  2. Qual è il risultato di a*2? E di e*2?
  3. Qual è il risultato di T|F e di T|NA?
  4. Qual è il tipo dei vettori sopra creati? Quale comando di R si usa per conoscere il tipo di un oggetto?

Per verificare che un oggetto sia di un determinato tipo possiamo usare, is.nometipo(), e.g.,

is.integer(a) ; is.double(a)
## [1] FALSE
## [1] TRUE
is.character(e)
## [1] TRUE
is.logical(f)
## [1] TRUE

Per forzare il tipo di un oggetto, possiamo usare, e.g.,

as.character(a)
## [1] "10"
as.integer(e)
## [1] 10
as.numeric(f)
## [1] 1
as.numeric(d)
## Warning: NA introdotti per coercizione
## [1] NA

Nei casi in cui tale forzatura non abbia senso o faccia perdere informazioni si è avvisati!

Una finezza:

a==10L
## [1] TRUE
identical(a, 10L)
## [1] FALSE
identical(as.integer(a), 10L)
## [1] TRUE

Per creare vettori con più valori (o di lunghezza \(>1\)), il modo più comune è quello di concatenare o combinare gli elementi che lo compongono usando c() (l’uso delle parentesi tonde al di fuori del comando equivale a richiedere la stampa dell’output)

(v_num <- c(2, 3.6, 1e2))
## [1]   2.0   3.6 100.0
(v_cha <- c("hi", "goodbye", "farewell"))
## [1] "hi"       "goodbye"  "farewell"

Più esattamente, questi, avendo tutti gli elementi dello stesso tipo, sono detti vettori atomici.

Un’alternativa, utile soprattutto quando si vuole solo impostare un vettore, è usare:

(v_le0 <- vector())
## logical(0)
length(v_le0)
## [1] 0
(v_log <- vector(, length=2))
## [1] FALSE FALSE

Domande veloci

  1. Qual è il tipo di v_num, v_cha e v_log?
  2. Se combiniamo in tutte le maniere possibili i vettori appena creati, quale è il tipo dei vettori così creati?
v_mix_1 <- c(v_log, v_num)
v_mix_2 <- c(v_num, v_cha)
v_mix_3 <- c(v_log, v_cha)
  1. Qual è la logica sottintesa alla definizione del tipo di vettori con elementi di tipo misto?

Sequenze di numeri con una struttura ordinata

Per creare una sequenza di interi con incremento costante \(1\)

1:10
##  [1]  1  2  3  4  5  6  7  8  9 10

equivalente a

seq(1, 10, 1) ; seq(1, 10, length=10)
##  [1]  1  2  3  4  5  6  7  8  9 10
##  [1]  1  2  3  4  5  6  7  8  9 10

Se la variazione costante è un decremento, l’input from deve essere non minore di quello to.

seq(10, 1, -1)
##  [1] 10  9  8  7  6  5  4  3  2  1

I parametri di seq() da impostare sono by o length, ad esempio

seq(1, 10, 2)
## [1] 1 3 5 7 9
seq(1, 10, length=5)
## [1]  1.00  3.25  5.50  7.75 10.00
seq(1, 10, 10)
## [1] 1
seq(1, 10, length=1)
## [1] 1
seq(1, 10, 2.5)
## [1] 1.0 3.5 6.0 8.5
seq(1, 10, le=2.5)
## [1]  1.0  5.5 10.0

Se il vettore contiene sequenze ripetute

rep(2, 5)
## [1] 2 2 2 2 2
rep(c(2,5), 2)
## [1] 2 5 2 5
rep(c(2, 5), c(2, 5))
## [1] 2 2 5 5 5 5 5

Estrazione (Subsetting)

Il modo più comune per estrarre elementi da un vettore è usare le [] all’interno delle quali si indicano le posizioni degli elementi da estrarre.

x <- c(1, 2, 5)
x[1]
## [1] 1
x[1:2]
## [1] 1 2
x[c(1,3)]
## [1] 1 5
x[-2]
## [1] 1 5
x[-(1:2)]
## [1] 5

Domande veloci

Dato il vettore

y <- c(x, -1.2, 0, 10, 6.2, 3, -3, 9, 12, sqrt(2))
  1. Qual è la lunghezza ?
  2. Estrarre tutti gli elementi tranne il \(4^o\).
  3. Estrarre gli elementi in posizione \(3,5,10\).
  4. Estrarre tutti gli elementi tranne quelli in posizione \(3,5,10\).
  5. Estrarre tutti gli elementi in posizione dispari, e poi quelli in posizione pari.

L’estrazione può anche servirsi di espressioni logiche per indicare le posizioni degli elementi da estrarre.

x <- c(1:2,4,5,7,8,10,11)
x[x<5 | x>7]
## [1]  1  2  4  8 10 11

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

which(x<5 | x>7)
## [1] 1 2 3 4 8

Si possono effettuare anche su vettori con più di un elemento le stesse operazioni che abbiamo visto con gli scalari

 x <- 1:10
 
 x*2
##  [1]  2  4  6  8 10 12 14 16 18 20
 x > 5
##  [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE

Si noti come la stessa operazione viene ripetuta per ogni elemento del vettore se uno dei due vettori è uno scalare. Altrimenti il vettore più corto viene ripetuto tante volte quante necessarie per coprire la lunghezza del vettore più lungo.

x <- rep(10,8)
y <- c(1,2)
x*y   
## [1] 10 20 10 20 10 20 10 20
x+y
## [1] 11 12 11 12 11 12 11 12

Un caso particolare di ripetizione della funzione per ogni elemento di un vettore si ha con il comando paste(). Esso è il comando per eccellenza per combinare più stringhe in una sola, previa conversione in tipo carattere gli argomenti dati in input.

paste(1:3)
## [1] "1" "2" "3"
paste(1:3, 2)
## [1] "1 2" "2 2" "3 2"
paste0(1:3, 2)
## [1] "12" "22" "32"
paste(1:3, 2, sep=".")
## [1] "1.2" "2.2" "3.2"
paste("day", 1:5)
## [1] "day 1" "day 2" "day 3" "day 4" "day 5"

Due funzioni importanti sono all() e any che ritornano un solo valore logico, e.g.,

x <- 0:7
# Are all the x values bigger than 0?
all(x>0)
## [1] FALSE
# Are any of the x values negative?
any(x<0)
## [1] FALSE
# then, it must be True that
any(x>0)
## [1] TRUE

Ora calcoliamo qualche statistica sui dati della temperatura degli ultimi \(\ldots\) giorni

x <- c(16.5, 16, 17, 12)
length(x)
## [1] 4
sort(x)
## [1] 12.0 16.0 16.5 17.0
order(x)
## [1] 4 2 1 3
sort(x, decreasing=T)
## [1] 17.0 16.5 16.0 12.0
sum(x)/length(x)
## [1] 15.375
mean(x)
## [1] 15.375
min(x); max(x); range(x)
## [1] 12
## [1] 17
## [1] 12 17

Names (attributo)

Possiamo attribuire agli elementi di un vettore un nome per ognuno di essi. Partiamo da un vettore numerico (senza attributi):

x <- c(1,0,5)
str(x)
##  num [1:3] 1 0 5
attributes(x)
## NULL
x <- c(a=1, b=0, c=5)
# or
x <- c(1,0,5) ; names(x) <- c("a", "b", "c")
# or
setNames(c(1,0,5), c("a", "b", "c"))
## a b c 
## 1 0 5
names(x)
## [1] "a" "b" "c"
attributes(x)
## $names
## [1] "a" "b" "c"

Esercizio (a casa)

  1. Si definisca un vettore y con elementi \(8, 3, 5, 7, 6, 6, 8, 9, 2\). C’è qualche elemento \(<5\)? Quanti sono? Si crei un nuovo vettore z con gli elementi di y che sono \(<5\).
  2. Si crei il vettore logico
x <- c(T, T, F, T)

Come posso trasformarlo in modo che a T corrisponda \(1\) e a F lo \(0\)? Le funzioni sum e mean applicate su x cosa calcolano?

sum(x) ; mean(x)
  1. Si definisca un vettore avente i valori 9, 2, 3, 9, 4, 10, 4, 11. Si scriva il codice per calcolare la somma dei tre valori più grandi.
  2. Si crei un vettore x di lunghezza \(4\). cosa il codice
x[c(TRUE, TRUE, NA, FALSE)]

restituisce?

Matrici e arrays

Una matrice è una struttura dati 2D con elementi omogenei (gli elementi devono essere tutti dello stesso tipo). Una matrice è un caso speciale di un array, che è multidimensionale.

(x <- matrix(c(2,3,5,7,11,13), nrow=3))
##      [,1] [,2]
## [1,]    2    7
## [2,]    3   11
## [3,]    5   13
(x <- matrix(c(2,3,5,7,11,13), ncol=3))
##      [,1] [,2] [,3]
## [1,]    2    5   11
## [2,]    3    7   13

È possibile creare una matrice anche importando gli elementi da un file esterno. Ad esempio, si consideri il file ex.data che contiene

x  y  z
2  3  5 
11 13 17

Il contenuto del file può essere letto tramite la funzione scan() e assegnato ad una matrice 2x3 utilizzando i seguenti comandi

(x <- scan("data/ex.data", skip = 1, quiet = TRUE))
## [1]  2  3  5 11 13 17
(mx <- matrix(x, ncol=3, byrow=TRUE))
##      [,1] [,2] [,3]
## [1,]    2    3    5
## [2,]   11   13   17

Impostando byrow = TRUE si sovrascrive l’impostazione predefinita (FALSE) e gli elementi vengono importati per riga invece che per colonna. length() si generalizza a nrow() e ncol() per le matrici, e a dim() per gli array.

nrow(mx) ; ncol(mx) ; dim(mx)
## [1] 2
## [1] 3
## [1] 2 3

Per nominare righe e colonne è possibile usare le seguenti funzioni

rownames(mx) <- paste0("r", 1:2)
colnames(mx) <- c("a", "b", "c")
mx
##     a  b  c
## r1  2  3  5
## r2 11 13 17

Gli array sono matrici con una dimensione che può essere maggiore di \(2\).

x <- 1:20
(ax <- array(x, dim=c(5,2,2)))
## , , 1
## 
##      [,1] [,2]
## [1,]    1    6
## [2,]    2    7
## [3,]    3    8
## [4,]    4    9
## [5,]    5   10
## 
## , , 2
## 
##      [,1] [,2]
## [1,]   11   16
## [2,]   12   17
## [3,]   13   18
## [4,]   14   19
## [5,]   15   20
dim(ax)
## [1] 5 2 2

Per verificare se un oggetto è una matrice o un array si può utilizzare is.matrix() e is.array(), o scoprendo le dimensioni dell’oggetto. Si noti che le matrici con una singola riga o una singola colonna o array con una singola dimensione continuano a mantenere memoria delle dimensioni originali. Ad esempio,

str(2:4)
##  int [1:3] 2 3 4
y <- matrix(2:4, nrow = 1)    # row vector
str(y) 
##  int [1, 1:3] 2 3 4
y <- matrix(2:4, ncol = 1)    # column vector
str(y) 
##  int [1:3, 1] 2 3 4
y <- array(2:4, 3)           # 1d array 
str(y)
##  int [1:3(1d)] 2 3 4

Estrazione

Come per i vettori, gli elementi di una matrice possono essere selezionati utilizzando le parentesi quadre e indicando le posizioni delle righe e delle colonne.

mx[2,1]     # select the element in the cell (2,1)
## [1] 11
mx[2, ]      # select the second row  
##  a  b  c 
## 11 13 17
mx["r2", ]
##  a  b  c 
## 11 13 17
mx[ ,3]      # select the third column 
## r1 r2 
##  5 17
mx[ ,"c"]
## r1 r2 
##  5 17

È possibile estrarre anche sottoinsiemi di righe e/o colonne per definire una nuova matrice con solo gli elementi selezionati:

x <- matrix(1:16, ncol=4)
(y <- x[c(1,4),c(3,4)])
##      [,1] [,2]
## [1,]    9   13
## [2,]   12   16

L’uso delle [] vale anche per l’estrazione da array

ax[3,2,1]
## [1] 8
ax[ ,2, ]
##      [,1] [,2]
## [1,]    6   16
## [2,]    7   17
## [3,]    8   18
## [4,]    9   19
## [5,]   10   20
ax[-1, ,1]
##      [,1] [,2]
## [1,]    2    7
## [2,]    3    8
## [3,]    4    9
## [4,]    5   10

Esercizio

Si completi il codice sotto per ottenere una matrice con 2 righe e 3 colonne e con gli elementi dati dagli interi da 1 a 6.

a <- matrix(1:?, ??? ???)
  1. Se is.matrix(a) è TRUE, quale valore presumi dia is.array(a)?
  2. Estrai dalla matrice a la seconda colonna e salvalo in un nuovo oggetto nominato b. Che tipo di oggetto è b?
  3. Cosa pensi succeda se convertiamo b in una matrice?
  4. Si crei un array, d, di dimensioni 2, 3, 2, e elementi dati dagli integeri da 1 a 12. Cosa producono dim() e length() se applicati su d?
  5. Cosa produce il codice
d[, , 1] <- b

Liste

Le liste differiscono dai vettori atomici in quanto i loro elementi possono essere di qualsiasi tipo, incluso liste. Si usa anche il termine “componente” di una lista anzichè “valore” per evidenziare la differenza rispetto ad un elemento di un vettore atomico.

Una lista vuota di lunghezza prespecificata può essere creata con la funzione vector()

(x <- vector("list", length = 3))
## [[1]]
## NULL
## 
## [[2]]
## NULL
## 
## [[3]]
## NULL

Nel momento in cui conosciamo le componenti, possiamo o “riempire” la lista x appena creata o creare direttamente una lista con queste componenti.

x1 <- 1:3
x2 <- c("A", "B", "C", "D", "E")
x3 <- matrix(1:12, nrow=3)

x[[1]] <- x1; x[[2]] <- x2; x[[3]] <- x3
x
## [[1]]
## [1] 1 2 3
## 
## [[2]]
## [1] "A" "B" "C" "D" "E"
## 
## [[3]]
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
mylist <- list(x1, x2, x3)  # define the list 'mylist'
str(mylist)
## List of 3
##  $ : int [1:3] 1 2 3
##  $ : chr [1:5] "A" "B" "C" "D" ...
##  $ : int [1:3, 1:4] 1 2 3 4 5 6 7 8 9 10 ...

Quando si crea una lista è possibile, e spesso conveniente, assegnare a ciascun componente un nome.

(mylist2 <- list(comp1 = x1, comp2 = x2, comp3 = x3))
## $comp1
## [1] 1 2 3
## 
## $comp2
## [1] "A" "B" "C" "D" "E"
## 
## $comp3
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12

Per recuperare i nomi dei componenti possiamo usare la funzione names(), funzione generica che vale anche per molte altre strutture di dati.

names(mylist)
## NULL
names(mylist2)
## [1] "comp1" "comp2" "comp3"

Quando si concatenano liste con c() si crea una lista costituita dalle componenti delle liste date in input.

newlist <- c(mylist, mylist2)
is.list(newlist)
## [1] TRUE
str(newlist)
## List of 6
##  $      : int [1:3] 1 2 3
##  $      : chr [1:5] "A" "B" "C" "D" ...
##  $      : int [1:3, 1:4] 1 2 3 4 5 6 7 8 9 10 ...
##  $ comp1: int [1:3] 1 2 3
##  $ comp2: chr [1:5] "A" "B" "C" "D" ...
##  $ comp3: int [1:3, 1:4] 1 2 3 4 5 6 7 8 9 10 ...

Se si costruisce una lista di liste, si crea una gerarchia di liste

newlist <- list(mylist, mylist2)
str(newlist)
## List of 2
##  $ :List of 3
##   ..$ : int [1:3] 1 2 3
##   ..$ : chr [1:5] "A" "B" "C" "D" ...
##   ..$ : int [1:3, 1:4] 1 2 3 4 5 6 7 8 9 10 ...
##  $ :List of 3
##   ..$ comp1: int [1:3] 1 2 3
##   ..$ comp2: chr [1:5] "A" "B" "C" "D" ...
##   ..$ comp3: int [1:3, 1:4] 1 2 3 4 5 6 7 8 9 10 ...

Estrazione

Per estrarre componenti o elementi interni alle componenti di una lista si usano ancora le parentesi quadre - si noti l’output diverso a seconda che si usi [] o le parentesi quadre doppie[[]] - o, in caso siano presenti, i nomi delle componenti.

mylist[1]
## [[1]]
## [1] 1 2 3
mylist[[1]]
## [1] 1 2 3
mylist2$comp1
## [1] 1 2 3

Possiamo poi estrarre elementi interni ad una componente usando le sintassi note. E.g.,

mylist[[3]][,4]
## [1] 10 11 12

Possiamo ora completare il capitolo degli array per quanto riguarda i nomi delle dimensioni. L’assegnazione di (o il recupero dei) nomi di un array avviene con la funzione dimnames() e richiede una lista di vettori carattere con lunghezze pari alle dimensioni dell’array.

dim(ax)
## [1] 5 2 2
dimnames(ax)
## NULL
dimnames(ax) <- list(letters[1:5], LETTERS[1:2], paste0("m", 1:2))
ax
## , , m1
## 
##   A  B
## a 1  6
## b 2  7
## c 3  8
## d 4  9
## e 5 10
## 
## , , m2
## 
##    A  B
## a 11 16
## b 12 17
## c 13 18
## d 14 19
## e 15 20
ax['a',,'m1']
## A B 
## 1 6

Esercizio

  1. Si creino gli oggetti seguenti
x <- list(list(1, 2), c(3, 4))
y <- c(list(1, 2), c(3, 4))

Qual è la differenza? Si estragga l’elemento con valore \(4\) da entrambi. 2. Si definisca un array di dimensioni (4, 2, 2)

b <- array(1:16, c(4, 2, 2))

Si assegni una lista di vettori carattere (di lunghezza 4, 2, 2) a dimnames(b) per etichettare le dimensioni di b.

str(x) ; str(y)
## List of 2
##  $ :List of 2
##   ..$ : num 1
##   ..$ : num 2
##  $ : num [1:2] 3 4
## List of 4
##  $ : num 1
##  $ : num 2
##  $ : num 3
##  $ : num 4
x[[2]][2]
## [1] 4
y[[4]]
## [1] 4
dimnames(b) <- list(c("R1", "R2", "R3", "R4"), c("C1", "C2"), c("A", "B"))

Fattori

I fattori sono gli oggetti tramite cui R definisce variabili categoriali.

Si consideri il vettore

country <- c("Italy","Germany","France","Germany","Germany","Germany",
              "France","Italy","Italy","France")

Esso può essere definito come fattore con la funzione factor()

countryf <- factor(country)
str(countryf)
##  Factor w/ 3 levels "France","Germany",..: 3 2 1 2 2 2 1 3 3 1
class(countryf)
## [1] "factor"
typeof(countryf)
## [1] "integer"

I livelli dei fattori sono memorizzati in ordine alfabetico, o nell’ordine in cui sono stati esplicitamente specificati in levels al momento della creazione con factor().

countryf <- factor(country, levels=c("Italy", "France", "Germany"))
str(countryf)
##  Factor w/ 3 levels "Italy","France",..: 1 3 2 3 3 3 2 1 1 2

Quando le variabili categoriali sono ordinali, i livelli hanno un ordine naturale, La funzione ordered() crea tali fattori ordinati ma per il resto è identica a factor.

La tabella di frequenza di qualunque variabile si ottiene con table(). In questo caso si noti la differenza:

table(country)
## country
##  France Germany   Italy 
##       3       4       3
table(countryf)
## countryf
##   Italy  France Germany 
##       3       3       4

Supponiamo di avere anche le informazioni su età e sesso (1=Femmina e 2=Maschio)

age <- c(47,44,44,40,38,36,42,34,34,44)
gender <- c(1,1,2,1,1,2,1,2,2,2)

Qual è l’età media degli individui per ciascun Paese?

Possiamo usare la funzione tapply():

tapply(age, countryf, mean)
##    Italy   France  Germany 
## 38.33333 43.33333 39.50000

Il risultato è una struttura di lunghezza pari al numero dei livelli dei fattori.

Altre funzioni della stessa famiglia sono apply(), lapply() e sapply, utili per chiamare ripetutamente una funzione. Per visualizzare ulteriori dettagli utilizza l’ help.

La funzione factor() è particolarmente utile quando i dati contengono variabili categoriali con modalità espresse in forma numerica. Fondamentalmente trasforma i numeri in etichette (livelli).

Nel caso della variabile genere, può essere utile trasformarla in un fattore e definirne i livelli:

genderf <- factor(gender)
levels(genderf) <- c("F","M")
str(genderf)
##  Factor w/ 2 levels "F","M": 1 1 2 1 1 2 1 2 2 2

Se vogliamo risalire nuovamente alla codifica numerica

unclass(genderf)
##  [1] 1 1 2 1 1 2 1 2 2 2
## attr(,"levels")
## [1] "F" "M"
as.integer(genderf)
##  [1] 1 1 2 1 1 2 1 2 2 2

Esercizio

  1. Definisci un vettore x con gli elementi 5, 12, 13, 12. Costringi questo vettore a fattore e controlla la sua struttura. Come vengono definiti i livelli?
  2. Crea un fattore dalla sequenza di stringhe "1", "1", "0", "1", "1", "0" e nominalo fs. Cosa restituiscetypeof(fs)? Per sapere quanti sono gli “1” (qual è la somma del vettore booleano) quale o quali comandi usare tra quelli sotto?
sum(as.integer(c("1", "1", "0", "1", "1", "0")))
sum(as.integer(fs))
sum(as.integer(levels(fs)[fs]))
  1. Converti la variabile fattore del punto precedente in un fattore con livelli “m” e “f” e calcola la tabella di frequenza.
  2. Si creino i fattori
v1 <- factor(letters[1:5])
levels(v1) <- rev(levels(v1))
v2 <- factor(letters[1:5], levels = rev(letters[1:5]))

Sono differenti? Per quale ragione?

Dataframes

Un dataframe è il modo più comune per archiviare i dati in R e facilitare l’analisi dei dati.

Un dataframe rappresenta un modo semplice per organizzare i dati le cui righe sono unità statistiche, mentre le colonne sono le variabili. In effetti, può essere considerata come una matrice con colonne possibilmente di tipo e classe diversi.

Potrebbe essere visualizzato in forma di matrice e le relative righe e colonne estratte utilizzando le stesse regole applicabili sulle matrici. Tuttavia, un dataframe è una struttura bidimensionale, che condivide proprietà sia della matrice che della lista. In particolare, i seguenti vincoli deve essere soddisfatti:

  • le componenti devono essere vettori (numerici, di carattere o logici), fattori, matrici numeriche, liste o altri dataframe;
  • matrici, liste e dataframe forniscono tante variabili al nuovo dataframe quante sono rispettivamente le colonne, elementi o variabili;
  • i vettori numerici e logici e i fattori sono inclusi così come sono nel dataframe mentre i vettori carattere sono di default convertiti in fattore (con i livelli dati dai valori unici del vettore);
  • i vettori che appaiono come variabili nel dataframe devono avere tutti la stessa lunghezza e le matrici devono avere anche le righe tutte della stessa lunghezza.

In parole povere, un dataframe è una lista di vettori di uguale lunghezza.

Una lista i cui componenti sono come quelli descritti sopra può essere convertita in daframe utilizzando la funzione as.data.frame().

Creazione

La funzione data.frame() viene utilizzata per definire un dataframe con inputs vettori nominati come nel seguente esempio

under40 <- age < 40
dat <- data.frame(country=countryf, age=age, sex=genderf, under40=under40)

Le caratteristiche dell’oggetto appena creato possono essere ottenute con:

str(dat)
## 'data.frame':    10 obs. of  4 variables:
##  $ country: Factor w/ 3 levels "Italy","France",..: 1 3 2 3 3 3 2 1 1 2
##  $ age    : num  47 44 44 40 38 36 42 34 34 44
##  $ sex    : Factor w/ 2 levels "F","M": 1 1 2 1 1 2 1 2 2 2
##  $ under40: logi  FALSE FALSE FALSE FALSE TRUE TRUE ...
dplyr::glimpse(dat)
## Rows: 10
## Columns: 4
## $ country <fct> Italy, Germany, France, Germany, Germany, Germany, France, Ita…
## $ age     <dbl> 47, 44, 44, 40, 38, 36, 42, 34, 34, 44
## $ sex     <fct> F, F, M, F, F, M, F, M, M, M
## $ under40 <lgl> FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FAL…
class(dat)
## [1] "data.frame"
is.data.frame(dat)
## [1] TRUE

La “testa” (come la “coda”) di dat possono essere ottenute con:

head(dat)
tail(dat)

Una visione globale può essere ottenuta con

View(dat)

o dalla scheda Environment di RStudio.

Estrazione

L’estrazione di singoli elementi, colonne, righe o una selezione di elementi, è possibile utilizzando la stessa sintassi definita per le matrici. Di seguito sono riportati alcuni esempi di base.

dat[3,2]
## [1] 44
dat[1:3, 2:4]
dat[3, ]

Si noti che se l’output è una singola colonna, restituisce un vettore invece di un dataframe

x <- dat[, 2]
str(x)
##  num [1:10] 47 44 44 40 38 36 42 34 34 44

Quando si selezionano colonne da un dataframe è possibile utilizzare i nomi delle colonne invece dell’indice delle colonne (come d’altra parte valeva per le matrici). Ad esempio,

dat[ , c("age", "sex")]

Esiste un altro modo per selezionare colonne da un dataframe, ovvero utilizzando il list subsetting, che restituisce ancora un dataframe

dat["age"] 
str(dat["age"]) 
## 'data.frame':    10 obs. of  1 variable:
##  $ age: num  47 44 44 40 38 36 42 34 34 44

Se si vogliono estrarre singole variabili si può anche usare il simbolo \(\$\) (che restituisce un vettore diversamente da sopra)

dat$sex
##  [1] F F M F F M F M M M
## Levels: F M

Per eliminare una componente (colonna) si può assegnare NULL alla colonna specifica del dataframe:

dat$under40 <- NULL
head(dat)

È possibile “aggiungere” un dataframe al percorso di ricerca, utilizzando la funzione attach()

attach(dat)

Dopo di che si può accedere ad una variabile del dataframe “attached” direttamente (scrivendo solo il suo nome)

age
##  [1] 47 44 44 40 38 36 42 34 34 44

Per distaccare il dataframe si usa il comando detach()

detach(dat)

Esercizio

  1. Si crei un dataframe newdf con le variabili
x <- runif(8)
y <- letters[1:8]
z <- sample(c(rep(T,5),rep(F,3)))

Si descrivano le variabili (ci si aiuti con l’help).

  1. Si crei un dataframe con 5 righe e come colonne un vettore carattere che contiene nomi propri di persona e un vettore numerico che riporta le età.

Tibble

Una specializzazione dei dataframe è offerta dalla classe tibble.

library(readxl)
fav_food <- read_excel("data/favourite-food.xlsx")
fav_food
str(fav_food)
## tibble [5 × 6] (S3: tbl_df/tbl/data.frame)
##  $ Student ID    : num [1:5] 1 2 3 4 5
##  $ Full Name     : chr [1:5] "Sunil Huffmann" "Barclay Lynn" "Jayendra Lyne" "Leon Rossini" ...
##  $ favourite.food: chr [1:5] "Strawberry yoghurt" "French fries" "N/A" "Anchovies" ...
##  $ mealPlan      : chr [1:5] "Lunch only" "Lunch only" "Breakfast and lunch" "Lunch only" ...
##  $ AGE           : chr [1:5] "4" "5" "7" "99999" ...
##  $ SES           : chr [1:5] "High" "Middle" "Low" "Middle" ...

Questa classe migliora la presentazione dei dati, soprattutto quando sono di grandi dimensioni; non forza la conversione delle variabili carattere in fattore; non aggiunge fittizi nomi di riga.