Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Quante righe restituisce l'istruzione
filter(v, voto > 25)?
filter conserva solo le righe in cui la condizione è
TRUE. Per Luca il confronto NA > 25
restituisce NA, e filter tratta
NA come una condizione non soddisfatta: la riga viene
esclusa. Restano Anna e Sara.
4 è il numero totale di righe, come se il filtro non avesse effetto.
La terza opzione è la più insidiosa: è ciò che accade con il puntamento
di R base v[v$voto > 25, ], che restituisce una riga di
soli NA in corrispondenza del valore mancante. La quarta è
errata: filter gestisce i valori mancanti senza errori.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce l'istruzione
filter(v, corso == "A", voto > 28)?
In filter più condizioni separate da virgola devono
essere soddisfatte contemporaneamente: la virgola
equivale all'operatore & (and). L'unica
studentessa del corso A con voto maggiore di 28 è Sara.
La seconda opzione considera solo la prima condizione. La terza è la
più insidiosa: interpreta la virgola come un or, che invece va
scritto esplicitamente con |
(filter(v, corso == "A" | voto > 28)); il risultato
comprenderebbe comunque Anna e Sara, ma per la ragione sbagliata. La
quarta è errata: & e la virgola sono equivalenti, ed
entrambi sono ammessi.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa accade eseguendo l'istruzione
filter(v, corso = "A")?
Il confronto si scrive con l'operatore relazionale ==.
Con un solo = l'espressione viene letta come un argomento
passato per nome (corso) a filter, che non lo
prevede: dplyr riconosce l'errore tipico e restituisce il
messaggio We detected a named input. This usually means that you've
used = instead of ==. Did you mean
corso == "A"?
La seconda opzione è il risultato che si otterrebbe con
==. La terza è la più insidiosa: confonde
filter con mutate, in cui
corso = "A" crea o sovrascrive una colonna. La quarta
immagina un filtro che non trova corrispondenze.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Quante righe restituisce l'istruzione
filter(v, nome == c("Marco", "Anna"))?
L'operatore == confronta elemento per elemento,
riciclando il vettore più corto: c("Marco", "Anna") diventa
c("Marco", "Anna", "Marco", "Anna") e viene confrontato con
c("Anna", "Luca", "Sara", "Marco"). Nessuna posizione
coincide, e il risultato è una tabella vuota. Per verificare se ciascun
nome appartiene a un insieme di valori si usa l'operatore
%in%: filter(v, nome %in% c("Marco", "Anna"))
restituisce le 2 righe attese.
2 è la risposta più insidiosa: è il risultato che si vorrebbe
ottenere, ma che si ottiene con %in%. 1 non corrisponde a
nessun confronto. La quarta è errata: grazie alla regola del riciclo R
non segnala nulla, ed è proprio questo a rendere l'errore difficile da
individuare.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Quali colonne contiene il risultato di
select(v, -voto)?
In select il segno meno davanti al nome di una colonna
significa "tutte le colonne tranne questa". Il
risultato contiene quindi nome e corso.
La seconda opzione è il risultato di select(v, voto). La
terza è la più insidiosa: interpreta il segno meno come un'operazione
aritmetica sui valori, che si otterrebbe invece con
mutate(v, voto = -voto). La quarta è priva di
fondamento.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce l'istruzione
select(v, studente = nome, voto)?
select permette di selezionare e rinominare le colonne
nella stessa chiamata, con la sintassi
nuovo_nome = vecchio_nome (la stessa di
rename). Le colonne non indicate, qui corso,
vengono escluse.
La seconda opzione è la più insidiosa: è il risultato di
rename(v, studente = nome), che rinomina senza eliminare le
altre colonne. La terza interpreta = come un confronto. La
quarta è errata: la rinomina in select è ammessa.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Qual è la differenza tra select(v, voto) e
pull(v, voto)?
Tutti i verbi di dplyr che lavorano sulle tabelle,
select compreso, restituiscono una tabella:
select(v, voto) è una tibble con 4 righe e 1 colonna.
pull serve invece a estrarre una colonna
come vettore, ed equivale a v$voto o a
v[["voto"]]. La differenza conta quando il risultato deve
essere passato a una funzione che si aspetta un vettore, come
mean.
La seconda opzione nega una differenza che c'è. La terza è la più
insidiosa: inverte i due comportamenti. La quarta confonde l'estrazione
con l'eliminazione: v non viene modificata.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce l'istruzione
summarise(v, media = mean(voto))?
summarise riduce la tabella a una sola riga (per gruppo,
se la tabella è raggruppata), con una colonna per ogni sintesi
richiesta. Poiché voto contiene un valore mancante e non è
stato specificato na.rm = TRUE, la media è
NA.
La seconda opzione è la più insidiosa: è il risultato con
mean(voto, na.rm = TRUE). La terza descrive
mutate, che conserva tutte le righe. La quarta è errata:
come tutti i verbi di dplyr, summarise
restituisce una tabella, non un vettore.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce la seguente istruzione?
v |>
group_by(corso) |>
summarise(n = n(), media = mean(voto))
Dopo group_by(corso), summarise calcola le
sintesi separatamente per ciascun gruppo e restituisce una riga per
gruppo. n() conta le righe di ciascun gruppo (2 e 2). La
media del corso A è 29; quella del corso B è NA, perché il
gruppo contiene il voto mancante di Luca e non è stato indicato
na.rm = TRUE.
La seconda opzione è la più insidiosa: è il risultato con
mean(voto, na.rm = TRUE). Anche dopo il raggruppamento, il
valore mancante condiziona la sintesi del suo gruppo. La terza ignora il
raggruppamento. La quarta descrive il comportamento di
group_by seguito da mutate.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce l'istruzione
nrow(group_by(v, corso))?
group_by non modifica le righe né i valori della
tabella: aggiunge un'informazione di raggruppamento (visibile nella
stampa come # Groups: corso [2]) che cambia il
comportamento dei verbi successivi. Il numero di righe resta quindi
4.
2 è la risposta più insidiosa: è il numero di gruppi, che determinerà
il numero di righe di un eventuale summarise successivo. 1
confonde group_by con un summarise senza
raggruppamento. La quarta è errata: group_by può essere
seguita da qualunque verbo, ad esempio da mutate o da
filter.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Si sostituisce il voto mancante con l'istruzione seguente:
v |>
group_by(corso) |>
mutate(voto = if_else(is.na(voto), mean(voto, na.rm = TRUE), voto)) |>
ungroup()
Quale valore viene assegnato al voto di Luca?
Combinando group_by con mutate (invece che
con summarise), la tabella conserva tutte le righe, ma le
funzioni di sintesi come mean vengono calcolate all'interno
di ciascun gruppo. Per Luca, del corso B, la media dei voti disponibili
del suo gruppo è quella del solo Marco: 24. È un modo semplice di
imputare i valori mancanti con un valore differenziato per gruppi di
unità.
La seconda opzione non ha relazione con il codice. La terza è la più
insidiosa: è il valore che si otterrebbe senza group_by,
cioè imputando con la media dell'intera colonna. La quarta trascura
na.rm = TRUE, che esclude il valore mancante dal calcolo
della media.
La tibble w contiene il corso e il sesso di alcuni
studenti. Dopo l'istruzione seguente, la tabella s risulta
ancora raggruppata?
s <- w |>
group_by(corso, sesso) |>
summarise(n = n())
Quando la tabella è raggruppata per più colonne,
summarise elimina per default l'ultimo
livello di raggruppamento (sesso) e lascia la tabella
raggruppata per gli altri (corso), segnalandolo con il
messaggio summarise() has regrouped the output. Ne
segue che, ad esempio, una successiva
mutate(quota = n / sum(n)) calcola le quote all'interno di
ciascun corso. Per eliminare tutti i raggruppamenti si usa
ungroup() oppure l'argomento
.groups = "drop".
La seconda opzione è vera solo per un raggruppamento su una sola colonna. La terza è la più insidiosa: dopo la sintesi, ogni combinazione di corso e sesso corrisponde a una sola riga, e il raggruppamento per entrambe le colonne non avrebbe più senso. La quarta inverte l'ordine dei livelli.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce la seguente istruzione?
v |>
group_by(corso) |>
filter(voto == max(voto, na.rm = TRUE))
Su una tabella raggruppata, anche filter lavora gruppo
per gruppo: max(voto, na.rm = TRUE) viene calcolato
separatamente per ciascun corso (30 per A, 24 per B) e vengono
conservate le righe in cui il voto è uguale al massimo del proprio
gruppo.
La seconda opzione è la più insidiosa: è il risultato senza
group_by, in cui il massimo è calcolato sull'intera
colonna. La terza è errata: con na.rm = TRUE il valore
mancante non partecipa al calcolo, e la condizione NA == 24
non è vera. La quarta confonde filter con
summarise: filter conserva tutte le
colonne.
La tibble s contiene il numero di studenti per corso e
sesso ed è ancora raggruppata per corso:
# A tibble: 4 × 3
# Groups: corso [2]
corso sesso n
1 A F 1
2 A M 1
3 B F 2
4 B M 1
Quali valori assume la colonna quota dopo l'istruzione
mutate(s, quota = n / sum(n))?
Poiché la tabella è ancora raggruppata per corso,
sum(n) viene calcolata all'interno di ciascun corso (2 per
A, 3 per B): le quote rappresentano la composizione per sesso di
ciascun corso e sommano a 1 all'interno del corso.
La seconda opzione è la più insidiosa: è il risultato su una tabella
non raggruppata (ad esempio dopo ungroup()), in cui le
quote sono calcolate sul totale generale di 5 studenti. La terza riporta
i conteggi senza dividerli. La quarta attribuisce a ogni riga lo stesso
peso, ignorando i conteggi.
La tibble p ha 3 righe e 4 colonne:
p <- tibble(paese = c("Italia", "Francia", "Spagna"),
`2023` = c(1, 2, 3),
`2024` = c(4, 5, 6),
`2025` = c(7, 8, 9))
Quali sono le dimensioni e i nomi delle colonne del risultato di
pivot_longer(p, cols = -paese)?
pivot_longer trasforma la tabella dal formato largo al
formato lungo: ognuna delle 3 colonne indicate (tutte tranne
paese) diventa una riga per ciascun paese, per un totale di
3 × 3 = 9 righe. I nomi delle colonne originarie finiscono in una
colonna chiamata per default name, i valori in una colonna
chiamata value.
La seconda opzione suppone che la tabella non cambi. La terza è la
più insidiosa: anno e valore sono i nomi che
si otterrebbero indicando names_to = "anno" e
values_to = "valore", ma R non può indovinarli. La quarta
trasforma anche la colonna paese, che invece è stata
esclusa con -paese.
Si considerino le istruzioni seguenti:
p <- tibble(paese = c("Italia", "Francia", "Spagna"),
`2023` = c(1, 2, 3),
`2024` = c(4, 5, 6),
`2025` = c(7, 8, 9))
l <- pivot_longer(p, cols = -paese, names_to = "anno", values_to = "valore")
class(l$anno)
Che cosa restituisce l'ultima istruzione?
I valori della colonna anno provengono dai
nomi delle colonne della tabella di partenza, che sono
sempre stringhe di testo: la colonna è quindi di tipo
character, anche se contiene cifre. Per ottenere una
colonna numerica si può aggiungere l'argomento
names_transform = as.integer oppure convertire la colonna
con mutate(anno = as.integer(anno)).
La seconda opzione confonde la colonna con una lista. La terza è la più insidiosa: è ciò che ci si aspetta guardando i valori, ma R non converte automaticamente i nomi delle colonne in numeri. La quarta è priva di fondamento: un anno non è una data.
La tibble l in formato lungo contiene i valori di
Italia, Francia e Spagna per gli anni 2023, 2024 e 2025, ma manca la
riga relativa all'Italia nel 2024. Che cosa accade alla cella
corrispondente nel risultato di
pivot_wider(l, names_from = anno, values_from = valore)?
pivot_wider costruisce una colonna per ogni valore di
anno e una riga per ogni paese; le combinazioni assenti nel
formato lungo diventano NA nel formato largo. Per assegnare
un valore diverso alle celle vuote si usa l'argomento
values_fill, ad esempio values_fill = 0.
La seconda opzione immagina che pivot_wider scarti le
righe incomplete. La terza è la più insidiosa: è il risultato con
values_fill = 0, ma R non può sapere che un dato assente
equivalga a zero, e spesso non è così. La quarta è errata: la
combinazione mancante non impedisce la trasformazione.
La tibble d contiene due righe per la stessa
combinazione di paese e anno:
d <- tibble(paese = c("Italia", "Italia"),
anno = c(2023, 2023),
valore = c(1, 2))
Che cosa accade eseguendo
pivot_wider(d, names_from = anno, values_from = valore)?
In formato largo, ogni combinazione di paese e anno corrisponde a una
sola cella. Se nel formato lungo ci sono più righe per la stessa
combinazione, pivot_wider non sa quale valore scegliere:
segnala il problema con un avvertimento e conserva tutti i valori in una
colonna di tipo lista (<list>). Per sintetizzare i
duplicati si usa l'argomento values_fn, ad esempio
values_fn = sum, ma prima conviene capire perché i
duplicati ci sono.
La seconda opzione è la più insidiosa: è il risultato con
values_fn = sum, ma R non somma automaticamente. La terza
immagina che R scarti dei dati senza segnalarlo. La quarta è errata: una
tabella non può avere due colonne con lo stesso nome.
Si considerino le risposte di due persone a due domande di un questionario:
q <- tibble(id = 1:2, q1 = c(4, 5), q2 = c(3, NA))
pivot_longer(q, cols = starts_with("q"),
names_to = "domanda", values_to = "punteggio",
values_drop_na = TRUE)
Quante righe ha il risultato?
pivot_longer produce una riga per ogni combinazione di
persona e domanda (2 × 2 = 4 righe). Con
values_drop_na = TRUE vengono eliminate le righe in cui il
valore è mancante: qui la risposta della persona 2 alla domanda
q2. Restano 3 righe.
4 è la risposta più insidiosa: è il numero di righe senza
values_drop_na = TRUE, cioè con il valore mancante
conservato come NA. 2 è il numero di persone. 6 è il numero
di celle della tabella di partenza, compresa la colonna
id.
Una tabella riporta i visitatori di alcuni musei con una riga per
museo e una colonna per ogni mese (gen, feb,
..., dic). Perché, per molte analisi, conviene trasformarla
con pivot_longer?
In una tabella tidy ogni variabile è una colonna, ogni
osservazione è una riga e ogni valore è una cella. Nel formato largo il
mese è "nascosto" nei nomi delle colonne: per calcolare, ad esempio, i
visitatori medi per mese bisognerebbe lavorare colonna per colonna. Nel
formato lungo il mese è una colonna, e basta un
group_by(mese). Il formato largo resta comunque utile per
presentare i risultati in una tabella di sintesi, e si ottiene con
pivot_wider.
La seconda opzione è errata: le tabelle in formato largo si importano
senza problemi. La terza è la più insidiosa: il formato lungo spesso
occupa più spazio, perché ripete i valori delle colonne
identificative. La quarta attribuisce a pivot_longer una
funzione che non ha: la trasformazione cambia la forma della tabella,
non i valori.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce l'istruzione
nest(v, .by = corso)?
nest "annida" le righe: per ogni valore di
corso crea una sola riga, e le colonne restanti
(nome e voto) vengono raccolte in una tibble
memorizzata in una colonna di tipo lista (list-column),
chiamata per default data. L'operazione inversa è
unnest(tabella, data), che ricostruisce la tabella di
partenza.
La seconda opzione descrive arrange(v, corso). La terza
è la più insidiosa: il contenuto è proprio quello, ma il risultato resta
una tibble, con una riga per corso, e non una semplice lista. La quarta
descrive group_by seguito da summarise.
La tibble y ha una colonna di tipo lista che contiene,
per ogni museo, i nomi delle sue sale:
y <- tibble(museo = c("M1", "M2"),
sale = list(c("Egizia", "Greca"),
c("Romana", "Etrusca", "Medievale")))
Quale istruzione restituisce una tabella con una riga per ogni sala
(5 righe) e le colonne museo e sale?
Le operazioni di rectangling trasformano dati annidati
(liste) in tabelle rettangolari. unnest_longer "allunga" la
tabella: ogni elemento della lista diventa una riga, e i valori delle
altre colonne (museo) vengono ripetuti.
pivot_wider cambia la forma di una tabella già
rettangolare e non estrae gli elementi di una lista. La terza è la più
insidiosa: unnest_wider "allarga" la tabella, trasformando
ogni elemento della lista in una colonna; è adatta
quando gli elementi hanno un nome (ad esempio citta e
anno), non per un elenco di lunghezza variabile. La quarta
compie l'operazione opposta, cioè annida le righe.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce l'istruzione di R base
v[v$voto > 25, ]?
Il vettore logico v$voto > 25 vale
TRUE NA TRUE FALSE. Nel puntamento con le parentesi quadre,
un indice NA non viene scartato ma produce una riga di
valori mancanti. filter (e la funzione di R base
subset) scartano invece le righe in cui la condizione è
NA. Con le parentesi quadre bisognerebbe scrivere
v[which(v$voto > 25), ] oppure
v[!is.na(v$voto) & v$voto > 25, ].
La seconda opzione è la più insidiosa: è il risultato di
filter e di subset(v, voto > 25), ma non
del puntamento con le parentesi quadre. La terza ignora la condizione.
La quarta è errata: il puntamento con condizioni è stato uno dei primi
strumenti visti nel corso.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce l'istruzione di R base
tapply(v$voto, v$corso, mean, na.rm = TRUE)?
tapply applica una funzione (mean) ai
valori di un vettore (v$voto) suddivisi secondo i gruppi
indicati da un secondo vettore (v$corso). Gli argomenti
successivi, come na.rm = TRUE, vengono passati alla
funzione. Il risultato è un array con nomi, uno per gruppo.
L'equivalente nel tidyverse è
v |> group_by(corso) |> summarise(media = mean(voto, na.rm = TRUE)),
che restituisce invece una tibble.
La seconda opzione è la più insidiosa: il contenuto è lo stesso, ma
le funzioni di R base non restituiscono tibble. La terza ignora la
suddivisione in gruppi. La quarta descrive ave o
group_by seguito da mutate.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Che cosa restituisce l'istruzione di R base
aggregate(voto ~ corso, data = v, FUN = mean)?
aggregate è la funzione di R base per calcolare sintesi
per gruppi. Con la sintassi a formula (variabile ~ gruppo),
il suo argomento na.action vale per default
na.omit: le righe con valori mancanti vengono eliminate
prima del calcolo, senza alcun avvertimento. Il
risultato coincide quindi con quello di
summarise(media = mean(voto, na.rm = TRUE)), ma per una
ragione diversa.
La seconda opzione è la più insidiosa: è il comportamento di
summarise senza na.rm = TRUE, che segnala il
problema restituendo NA. Le due funzioni trattano dunque i
valori mancanti in modo diverso, ed è bene saperlo quando si confrontano
risultati ottenuti con R base e con il tidyverse. La terza
ignora la suddivisione in gruppi. La quarta è errata.
Si consideri la tibble seguente:
v <- tibble(nome = c("Anna", "Luca", "Sara", "Marco"),
corso = c("A", "B", "A", "B"),
voto = c(28, NA, 30, 24))
Quale istruzione di R base ordina le righe di v per voto
decrescente, come arrange(v, desc(voto))?
order restituisce le posizioni degli
elementi nell'ordine richiesto (qui 3 1 4 2); usato come
indice di riga, riordina l'intera tabella. Come arrange,
colloca il valore mancante in fondo.
sort ordina un vettore, non le righe di una tabella. La
terza è la più insidiosa: sort restituisce i
valori ordinati (30 28 24), non le
posizioni, e usarli come indici di riga produce un risultato privo di
senso. La quarta usa order con la sintassi dei verbi di
dplyr, che non è valida per una funzione di R base.
Si considerino i data frame:
a <- data.frame(id = 1:3, x = c("a", "b", "c"))
b <- data.frame(id = c(2, 3, 4), y = c("B", "C", "D"))
A quale join di dplyr corrisponde l'istruzione di R base
merge(a, b, by = "id")?
merge è la funzione di R base per unire due tabelle. Con
i valori di default restituisce solo le righe con id
presente in entrambe (2 e 3), come inner_join. Gli altri
tipi di join si ottengono con gli argomenti all.x = TRUE
(come left_join), all.y = TRUE (come
right_join) e all = TRUE (come
full_join).
La seconda opzione restituirebbe solo le colonne di a.
La terza è la più insidiosa: è il comportamento di merge
con all.x = TRUE, non quello di default. La quarta confonde
l'unione per chiave con l'accodamento delle righe.
La tibble t ha le colonne numeriche altezza
e peso, entrambe con alcuni valori mancanti. Quale
istruzione calcola la media di entrambe le colonne, escludendo i valori
mancanti?
across applica la stessa funzione a più colonne
all'interno di summarise (o di mutate). Per
passare l'argomento na.rm = TRUE si usa una funzione
anonima, \(x) mean(x, na.rm = TRUE), che viene applicata a
ciascuna colonna. Il risultato è una tibble con una riga e le colonne
altezza e peso.
La seconda opzione combina le due colonne in un unico vettore e
calcola una sola media (che sarebbe comunque NA). La terza
è la più insidiosa: la sintassi è corretta, ma senza
na.rm = TRUE le medie sono NA. La quarta
applica mean a un'intera tabella: R restituisce
NA con un avvertimento, perché mean richiede
un vettore numerico.