Qual è la principale differenza tra una matrice e un data frame?
La matrice è un oggetto atomico: tutti gli elementi devono avere la
stessa modalità, e mescolando numeri e stringhe tutto viene convertito
in character. Il data frame è invece un oggetto non
atomico: internamente è una lista di vettori della stessa lunghezza (le
colonne), ciascuno con la propria modalità. È per questo la struttura
naturale per una matrice dei dati statistica, in cui le variabili
possono essere di tipo diverso.
La seconda opzione inventa un limite che non esiste. La terza è la
più insidiosa: anche una matrice può avere i nomi delle colonne
(attributo dimnames), ma resta un oggetto atomico; la
differenza sta nella struttura, non nei nomi. La quarta è del tutto
errata: un data frame può contenere colonne di qualunque modalità.
Si considerino le seguenti istruzioni, in cui df è un
data.frame e tb una tibble con lo
stesso contenuto (prova le istruzioni in R prima di
rispondere):
df <- data.frame(nome = c("Anna", "Luca", "Sara"), voto = c(28, 24, 30))
tb <- tibble::tibble(nome = c("Anna", "Luca", "Sara"), voto = c(28, 24, 30))
df[, 2]
tb[, 2]
Che cosa restituiscono le ultime due istruzioni?
Con un data.frame, estraendo una sola colonna con la
notazione [riga, colonna] R "semplifica" il risultato e
restituisce un vettore. Una tibble non semplifica mai:
tb[, 2] restituisce ancora una tibble, con una sola
colonna. Per ottenere il vettore da una tibble si usano
tb[[2]], tb[["voto"]] oppure
tb$voto.
La seconda opzione confonde il puntamento di una colonna con quello di un singolo elemento: lasciare vuoto l'indice di riga significa "tutte le righe". La terza è la più plausibile: tibble e data frame sono molto simili (una tibble è anche un data frame), ma differiscono proprio in comportamenti come questo. La quarta è errata: le colonne si possono indicare sia per posizione sia per nome.
Si eseguono le seguenti istruzioni:
l <- list(1:3, "a", TRUE)
class(l[2])
class(l[[2]])
Che cosa restituiscono le ultime due istruzioni, nell'ordine?
La singola parentesi quadra applicata a una lista restituisce una
sotto-lista: l[2] è una lista con un solo
elemento. La doppia parentesi quadra estrae invece l'elemento
stesso: l[[2]] è il vettore di caratteri
"a". Un'immagine utile: se la lista è un treno,
l[2] è il secondo vagone (ancora attaccato alla struttura
di treno), mentre l[[2]] è il contenuto del secondo
vagone.
La seconda opzione inverte i due comportamenti. La terza è l'errore più frequente: le due notazioni sembrano equivalenti ma restituiscono oggetti di classe diversa. La quarta riporta le classi del primo e del terzo elemento della lista.
Si eseguono le seguenti istruzioni:
studente <- list(nome = "Anna", voti = c(28, 30, 27))
studente$voti[2]
Che cosa restituisce l'ultima istruzione?
L'operatore $ estrae dalla lista l'elemento con il nome
indicato, cioè il vettore c(28, 30, 27); equivale a
studente[["voti"]]. A questo vettore si applica poi
[2], che ne estrae il secondo elemento: 30. Le
due operazioni sono valutate in sequenza, da sinistra a destra.
La seconda opzione ignora l'indice [2]. La terza è la
più insidiosa: voti è effettivamente il secondo elemento
della lista, ma l'indice [2] è applicato al vettore
estratto con $, non alla lista. La quarta confonde il
contenuto dell'elemento con il suo nome.
Dato il data frame
df <- data.frame(nome = c("Anna", "Luca", "Sara"), voto = c(28, 24, 30))
quale delle seguenti istruzioni non restituisce il
vettore numerico 28 24 30?
Un data frame è una lista di colonne, quindi valgono le stesse regole
delle liste: df["voto"], con la singola parentesi quadra e
un solo indice, restituisce un data frame con la sola colonna
voto, non il vettore. Tutte le altre istruzioni
restituiscono il vettore 28 24 30: $ e
[[ ]] estraggono l'elemento (la colonna), mentre
df[, "voto"], con la notazione a due indici, semplifica il
risultato in un vettore perché si seleziona una sola colonna.
In questa domanda la risposta corretta è l'istruzione che si comporta
diversamente dalle altre: le tre istruzioni che restituiscono il vettore
sono i distrattori. Tra queste df[, "voto"] è la più
insidiosa, perché usa anch'essa la singola parentesi quadra.
Si eseguono le seguenti istruzioni:
studente <- list(nome = "Anna", voti = c(28, 30))
studente$voti <- NULL
length(studente)
Che cosa restituisce l'ultima istruzione?
NULL rappresenta l'oggetto vuoto, l'assenza di qualunque
oggetto. Assegnare NULL a un elemento di una lista (o a una
colonna di un data frame) ha l'effetto di eliminarlo: la lista resta con
il solo elemento nome e la sua lunghezza diventa 1.
La seconda opzione immagina che l'assegnazione aggiunga un elemento.
La terza è il fraintendimento più naturale: ci si aspetta che l'elemento
rimanga "vuoto", ma NULL non è un valore che possa essere
contenuto: è l'assenza di oggetto, e l'elemento viene rimosso. La quarta
confonde il divieto di usare una parola riservata come nome
(NULL <- 1 dà errore) con la possibilità di usarla come
valore.
Quale delle seguenti istruzioni rispetta le regole di stile del tidyverse style guide adottate nel corso?
Le regole principali: i nomi degli oggetti sono scritti in minuscolo
con le parole separate da _ (snake case); per
l'assegnazione si usa <-; si lascia uno spazio attorno
agli operatori (<-, =, +, ...)
e dopo ogni virgola, mentre non si mettono spazi subito dentro le
parentesi.
La seconda opzione è codice funzionante, ma viola quasi tutte le
regole: nome in CamelCase, = per l'assegnazione,
nessuno spazio. La terza è la più insidiosa: il nome è corretto e gli
spazi dopo le virgole ci sono, ma usa = per l'assegnazione
e inserisce spazi dentro le parentesi. La quarta non è nemmeno codice
valido: media voti contiene uno spazio e non è un nome
ammesso.
In uno script R aperto in RStudio, quale delle seguenti righe crea una sezione che compare nel pannello di navigazione dello script (document outline)?
In uno script R tutto ciò che segue il simbolo # è un
commento e non viene eseguito. Un commento che termina con almeno
quattro trattini (----, ma valgono anche ====
o ####) viene riconosciuto da RStudio come etichetta di
sezione: compare nel document outline e permette di navigare lo
script. Si inserisce rapidamente con CTRL/CMD + SHIFT +
R.
La seconda opzione usa la sintassi dei commenti di altri linguaggi
(C, Java): in R // non è un commento e produce un errore.
La terza è la più plausibile: è un commento valido, ma senza i trattini
finali non viene riconosciuto come sezione (il doppio #
richiama i titoli di Markdown e Quarto, non degli script R). La quarta
chiama una funzione che non esiste.
Che cosa restituiscono, nell'ordine, le seguenti istruzioni?
length(c(1, NULL, 3))
length(c(1, NA, 3))
NA è un valore (mancante): occupa una
posizione nel vettore, che quindi ha lunghezza 3. NULL
invece è l'oggetto vuoto, ha lunghezza 0: combinandolo
con c() non aggiunge nulla, e il vettore risultante
1 3 ha lunghezza 2.
La seconda opzione inverte i due comportamenti. La terza è la più
insidiosa: tratta NULL come un valore mancante al pari di
NA, mentre la differenza tra "valore che manca" e "oggetto
che non c'è" è proprio il punto della domanda. La quarta riporta un
risultato senza alcun fondamento.
Che cosa restituisce la seguente istruzione?
c(1/0, 0/0, -1/0)
R segue le regole dell'aritmetica in virgola mobile: dividere un
numero positivo per zero dà Inf (infinito), un numero
negativo dà -Inf, mentre 0/0 è una forma
indeterminata e restituisce NaN (Not a Number).
Nessuna delle tre operazioni produce un errore.
La seconda opzione non ha fondamento matematico. La terza è la più
insidiosa: tratta anche 0/0 come infinito, ignorando che si
tratta di una forma indeterminata. La quarta applica a R il
comportamento di una calcolatrice o di altri linguaggi che interrompono
il calcolo.
Che cosa restituisce la seguente istruzione?
is.na(c(1, NA, NaN))
is.na() verifica, elemento per elemento, se il valore è
mancante e restituisce un vettore logico della stessa lunghezza. In R
anche NaN viene considerato un valore mancante, quindi
is.na() restituisce TRUE sia per
NA sia per NaN. Il viceversa non vale:
is.nan() restituisce TRUE solo per
NaN.
La seconda opzione conta i valori mancanti (cosa che si otterrebbe
con sum(is.na(...)), e il risultato sarebbe comunque 2). La
terza è la più plausibile: NaN e NA sono
valori riservati diversi, ma is.na() li considera entrambi
mancanti. La quarta risponde se il vettore "contiene" valori mancanti,
non quali elementi lo siano.
Che cosa restituisce la seguente istruzione?
mean(c(2, NA, 4))
Per default, un valore mancante si propaga nei calcoli: se uno dei
valori non è noto, non è nota neppure la media, e R restituisce
NA. Per calcolare la media dei soli valori disponibili si
usa l'argomento na.rm (NA remove):
mean(c(2, NA, 4), na.rm = TRUE) restituisce
3.
La seconda opzione, (2 + 0 + 4) / 3, tratta il dato
mancante come uno zero: un errore concettuale grave in statistica. La
terza è la più plausibile, perché è il risultato che si ottiene con
na.rm = TRUE, ma non è il comportamento di default. La
quarta è errata: la funzione restituisce NA, non un
errore.
Si vuole verificare quali elementi del vettore
x <- c(3, NA) sono mancanti. Che cosa restituisce
l'istruzione x == NA?
NA significa "valore non noto". Chiedersi se 3 sia
uguale a un valore non noto ha come risposta "non si sa", cioè
NA; lo stesso vale per il secondo confronto: due valori non
noti non si possono dire uguali, quindi anche NA == NA
restituisce NA. Per individuare i valori mancanti si usa la
funzione is.na(), che restituisce
FALSE TRUE.
La seconda opzione restituisce un singolo valore, ma il confronto è
vettoriale e produce un risultato per ogni elemento. La terza è l'errore
più frequente: è esattamente il risultato desiderato, ma si ottiene con
is.na(x), non con ==. La quarta è errata: il
confronto è lecito e non produce errori.
Quale istruzione salva soltanto gli oggetti
x e y nel file dati.RData?
save() salva gli oggetti elencati nel file indicato
dall'argomento file; save.image() salva invece
l'intero workspace, mentre load() serve a ricaricare in
memoria gli oggetti contenuti in un file .RData.
La seconda opzione usa la funzione di caricamento al posto di quella
di salvataggio. La terza è la più insidiosa ed è un esempio di passaggio
degli argomenti: gli oggetti da salvare sono raccolti dall'argomento
..., che accetta un numero qualunque di valori, per cui la
stringa "dati.RData", passata senza nome, viene
interpretata come il nome di un terzo oggetto da salvare; R restituisce
l'errore object 'dati.RData' not found. Dopo
... gli argomenti vanno sempre passati per nome. La quarta
non ha relazione con il salvataggio di oggetti R.
Che cosa restituisce la seguente istruzione?
x <- c(2, 5, 8)
x > 3 & x < 7
Gli operatori relazionali (>, <) e
l'operatore logico & (and) agiscono elemento
per elemento. x > 3 dà FALSE TRUE TRUE,
x < 7 dà TRUE TRUE FALSE; combinandoli con
&, il risultato è TRUE solo dove entrambe
le condizioni sono vere: FALSE TRUE FALSE.
La seconda opzione restituisce il valore che soddisfa la condizione:
si otterrebbe con x[x > 3 & x < 7], cioè usando
il vettore logico per il puntamento. La terza è il risultato di
x > 3 | x < 1, cioè confonde and
(&) con or (|), oppure considera
la sola prima condizione. La quarta tratta il confronto come se
restituisse un unico valore per l'intero vettore.
Che cosa restituisce la seguente istruzione?
sum(c(3, 8, 1, 9) > 5)
c(3, 8, 1, 9) > 5 produce il vettore logico
FALSE TRUE FALSE TRUE. Quando un valore logico è usato in
un'operazione aritmetica, R lo converte in numero: TRUE
diventa 1 e FALSE diventa 0. La
somma conta quindi quanti elementi soddisfano la condizione: 2. Allo
stesso modo, mean() applicata a un vettore logico
restituisce la proporzione di TRUE.
La seconda opzione ignora il confronto. La terza è la più insidiosa:
è la somma degli elementi maggiori di 5, che si ottiene con
sum(x[x > 5]), cioè usando il vettore logico per il
puntamento e non per la somma. La quarta è errata proprio a causa della
conversione automatica dei valori logici in numeri.
Che cosa restituisce la seguente istruzione?
c(17 %/% 5, 17 %% 5)
%/% è l'operatore di divisione intera:
restituisce la parte intera del quoziente, 17 %/% 5 è
3. %% è l'operatore modulo:
restituisce il resto della divisione intera, 17 %% 5 è
2 (infatti 17 = 3 × 5 + 2). L'operatore %% è
utile ad esempio per verificare se un numero è pari:
x %% 2 == 0.
La seconda opzione tratta entrambi gli operatori come la divisione
ordinaria 17 / 5. La terza è la più insidiosa: i valori
sono quelli giusti, ma attribuiti agli operatori sbagliati. La quarta
interpreta gli operatori come prodotto e somma.
Che cosa restituisce la seguente istruzione?
v <- c(4, 10, 6, 12)
v[v > mean(v)]
La media di v è 8. L'espressione
v > mean(v) produce il vettore logico
FALSE TRUE FALSE TRUE; usato tra parentesi quadre, questo
vettore seleziona gli elementi di v in corrispondenza dei
TRUE, cioè 10 e 12.
La seconda opzione restituisce la media stessa. La terza è la più
plausibile: è il risultato del solo confronto
v > mean(v), prima che venga usato per il puntamento. La
quarta restituisce le posizioni degli elementi che
soddisfano la condizione, che si otterrebbero con
which(v > mean(v)), non i loro valori.
Che cosa restituisce la seguente istruzione?
v <- c(4, 10, 6, 12)
v[c(TRUE, FALSE)]
Quando il vettore logico usato per il puntamento è più corto del
vettore da indicizzare, R lo ricicla: c(TRUE, FALSE)
diventa c(TRUE, FALSE, TRUE, FALSE). Vengono quindi
selezionati il primo e il terzo elemento, cioè gli elementi in posizione
dispari: 4 6.
La seconda opzione tratta il vettore logico come se indicasse un
numero di elementi. La terza è la più insidiosa: è il risultato che si
avrebbe se R non applicasse la regola del riciclo, cioè con
v[c(TRUE, FALSE, FALSE, FALSE)]. La quarta è errata: R non
segnala nemmeno un avvertimento in questo caso.