Il file dati.csv è stato esportato da un foglio
elettronico in italiano: le colonne sono separate dal punto e virgola e
i numeri decimali usano la virgola (ad esempio 1500,50).
Quale delle seguenti istruzioni lo importa correttamente?
read_delim del package readr permette di
indicare il separatore delle colonne (delim) e, attraverso
l'argomento locale, il separatore decimale. Lo stesso
risultato si ottiene con le funzioni pensate per i CSV "all'italiana":
read_csv2 di readr oppure
read.csv2 di base.
read_excel serve per i file in formato Excel
(.xls, .xlsx), non per i file di testo.
read.csv è la più insidiosa: è una funzione di importazione
per file CSV, ma per default usa la virgola come separatore delle
colonne e il punto come separatore decimale, per cui l'intero contenuto
di ogni riga finirebbe in un'unica colonna. La quarta confonde
l'importazione di un file con l'installazione di un package.
Il file t.csv contiene le righe seguenti:
nome;eta;reddito
Anna;23;1500,50
Luca;25;1200,00
Che cosa si ottiene con l'istruzione
read.table("t.csv", sep = ";")?
In read.table l'argomento header vale
FALSE per default: la prima riga del file viene trattata
come una riga di dati e le colonne ricevono i nomi V1,
V2, V3. Poiché ogni colonna contiene anche il
testo dell'intestazione, tutte le colonne sono di tipo
character. Per un risultato corretto servono
header = TRUE e dec = "," (oppure si usa
read.csv2).
La seconda opzione è errata: read.table legge qualunque
file di testo delimitato, indipendentemente dall'estensione. La terza è
la più insidiosa: è il risultato che si otterrebbe specificando
header = TRUE e dec = ",", ma non con i valori
di default. La quarta non ha fondamento: read.table
restituisce sempre un data frame.
Il file n.csv ha come intestazione la riga
Anno di nascita;Voto (su 30);Codice Fiscale. Quali nomi
delle colonne si ottengono con
names(read.csv2("n.csv"))?
Per default le funzioni di importazione di base
(read.table, read.csv, read.csv2)
usano check.names = TRUE: i nomi delle colonne vengono
trasformati in nomi validi sostituendo con un punto ogni carattere non
ammesso, come spazi e parentesi.
"V1" "V2" "V3" sono i nomi assegnati quando la prima
riga non viene letta come intestazione, ma read.csv2 usa
header = TRUE per default. La terza opzione è il risultato
che si ottiene con le funzioni di readr (ad esempio
read_csv2), che conservano i nomi originali anche se non
validi. La quarta è il risultato di clean_names del package
janitor, non di read.csv2.
Il file t.csv contiene le righe seguenti:
nome;eta;reddito
Anna;23;1500,50
Luca;25;1200,00
Il file viene importato con l'istruzione seguente:
read_delim("t.csv", delim = ";")$reddito
Che cosa si ottiene?
Con il locale di default readr usa il punto come
separatore decimale e la virgola come separatore delle
migliaia. I valori 1500,50 e
1200,00 vengono interpretati come numeri in cui la virgola
separa le migliaia, e diventano 150050 e 120000. R non segnala nulla: il
messaggio Column specification indica soltanto che la colonna è
stata letta come numero. È un errore silenzioso, che si evita indicando
locale = locale(decimal_mark = ",") oppure usando
read_csv2.
La seconda opzione descrive un comportamento ragionevole, che si verifica quando almeno un valore non è interpretabile come numero, ma non è il caso di questi valori. La terza è il risultato corretto che si otterrebbe specificando il separatore decimale. La quarta è errata: proprio l'assenza di un errore rende questo comportamento pericoloso.
Qual è la differenza tra gli oggetti restituiti da
read.csv2("t.csv") e da
read_csv2("t.csv")?
Le funzioni di readr restituiscono una tibble:
class() riporta
"spec_tbl_df" "tbl_df" "tbl" "data.frame", a indicare che
la tibble è un data frame con alcuni comportamenti diversi (stampa più
compatta, nessuna modifica dei nomi delle colonne, nessuna
semplificazione con [ , ]). Le funzioni di
base restituiscono un semplice data.frame.
La seconda opzione è errata: nessuna delle due restituisce una
matrice. La terza è la più insidiosa: le due funzioni hanno nomi quasi
identici e argomenti di default simili (; come separatore e
, come decimale), ma appartengono a package diversi e
producono oggetti di classe diversa. La quarta confonde la lettura con
la scrittura, che si fa con funzioni come write_csv2.
Quale funzione del package readxl restituisce i nomi dei
fogli contenuti in un file Excel?
excel_sheets() restituisce un vettore di stringhe con i
nomi dei fogli del file. Il foglio da importare si indica poi
nell'argomento sheet di read_excel, per nome
(sheet = "Esami") o per posizione
(sheet = 2).
read_csv è pensata per i file di testo delimitati e non
legge il formato Excel. La terza opzione è la più insidiosa:
read_excel importa un solo foglio alla volta (per default
il primo) e restituisce una tibble, non l'elenco dei fogli. La quarta
richiama una funzione che non esiste.
Nel foglio Esami del file esami.xlsx la
prima riga contiene un titolo, la seconda è vuota e l'intestazione delle
colonne si trova nella terza riga. Quale istruzione importa
correttamente i dati?
L'argomento skip indica quante righe saltare prima di
iniziare la lettura: saltando le prime due, la terza riga viene letta
come intestazione. Senza skip, il titolo diventerebbe il
nome della prima colonna e tutte le colonne sarebbero di tipo
character.
Con col_names = FALSE la lettura parte comunque dalla
prima riga e il titolo e l'intestazione vengono trattati come dati. La
terza opzione è la più insidiosa: saltando tre righe si salta anche
l'intestazione, per cui la prima riga di dati verrebbe usata come nomi
delle colonne. La quarta legge al massimo due righe di dati, senza
risolvere il problema.
Una tibble ha le colonne Anno di nascita,
Voto (su 30), CodiceFiscale e
% Presenze. Quali nomi si ottengono dopo l'applicazione
della funzione clean_names() del package
janitor?
clean_names() trasforma i nomi in snake case:
lettere minuscole, parole separate da _, nessuno spazio né
carattere speciale. Le parentesi vengono eliminate, le parole unite in
CamelCase vengono separate (CodiceFiscale diventa
codice_fiscale) e alcuni simboli vengono tradotti in parole
(% diventa percent).
La seconda opzione corrisponde alla trasformazione fatta da
make.names(), cioè da check.names = TRUE nelle
funzioni di importazione di base. La terza è la più
insidiosa: applica alcune regole (minuscole, _) ma non le
altre, mentre le parentesi non sono ammesse in un nome valido e la
separazione del CamelCase è automatica. La quarta descrive i
nomi di default di read.table senza intestazione.
Si considerino le due tibble seguenti:
studenti <- tibble(id = c(1, 2, 3), nome = c("Anna", "Luca", "Sara"))
esami <- tibble(id = c(1, 1, 2, 4), voto = c(28, 30, 24, 27))
Quante righe ha il risultato di
inner_join(studenti, esami, by = "id")?
inner_join conserva solo le righe con corrispondenza in
entrambe le tabelle. Anna (id 1) ha due esami e compare due volte, Luca
(id 2) ne ha uno, mentre Sara (id 3) e l'esame con id 4 non hanno
corrispondenza e vengono esclusi: 2 + 1 = 3 righe.
7 è la somma delle righe delle due tabelle, come se il join le
accodasse. 2 è la risposta più insidiosa: è il numero di
studenti con corrispondenza, ma il join produce una
riga per ogni coppia studente-esame, e Anna ha due esami. 4 è il numero
di righe di esami, cioè di
left_join(esami, studenti).
Si considerino le due tibble seguenti:
studenti <- tibble(id = c(1, 2, 3), nome = c("Anna", "Luca", "Sara"))
esami <- tibble(id = c(1, 1, 2, 4), voto = c(28, 30, 24, 27))
Quante righe ha il risultato di
left_join(studenti, esami, by = "id"), e cosa contiene la
riga di Sara?
left_join conserva tutte le righe della
prima tabella (studenti) e vi aggiunge le colonne della
seconda. Anna ha due esami e compare due volte, Luca una volta, Sara non
ha esami e compare una volta con voto pari a
NA: 4 righe in totale. L'esame con id 4 viene escluso
perché non corrisponde a nessuno studente.
La seconda opzione descrive inner_join. La terza è la
più insidiosa: left_join conserva tutte le righe della
prima tabella, ma non ne conserva il numero quando la
relazione è "uno a molti", perché ogni studente viene ripetuto per
ciascun esame. La quarta confonde il join con l'accodamento delle righe
(union_all o bind_rows).
Si considerino le due tibble seguenti:
studenti <- tibble(id = c(1, 2, 3), nome = c("Anna", "Luca", "Sara"))
esami <- tibble(id = c(1, 1, 2, 4), voto = c(28, 30, 24, 27))
Quante righe ha il risultato di
full_join(studenti, esami, by = "id")?
full_join conserva tutte le righe di entrambe le
tabelle: le 3 righe con corrispondenza (due per Anna e una per Luca), la
riga di Sara senza esami (con voto pari a NA)
e la riga dell'esame con id 4 senza studente (con nome pari
a NA): 3 + 1 + 1 = 5.
4 è il numero di righe di left_join (o di
right_join): si dimentica uno dei due gruppi di righe senza
corrispondenza. 3 è il numero di righe di inner_join. 12 è
il prodotto del numero di righe delle due tabelle, cioè il risultato di
un cross_join, che abbina ogni riga della prima tabella a
ogni riga della seconda.
Si considerino le due tibble seguenti:
studenti <- tibble(id = c(1, 2, 3), nome = c("Anna", "Luca", "Sara"))
esami <- tibble(id = c(1, 1, 2, 4), voto = c(28, 30, 24, 27))
Quale delle seguenti istruzioni produce le stesse righe di
left_join(studenti, esami, by = "id"), a meno dell'ordine
delle colonne?
right_join(x, y) conserva tutte le righe di
y, cioè della seconda tabella. Scambiando
l'ordine delle tabelle, right_join(esami, studenti)
conserva tutte le righe di studenti, esattamente come
left_join(studenti, esami). Cambia solo l'ordine delle
colonne: prima quelle di esami, poi quelle di
studenti.
inner_join esclude Sara, che non ha esami. La terza è la
più insidiosa: lascia le tabelle nello stesso ordine e conserva quindi
tutte le righe di esami, includendo l'esame con id 4 ed
escludendo Sara. La quarta è una chiamata incompleta, perché manca la
seconda tabella.
Si considerino le due tibble seguenti:
studenti <- tibble(id = c(1, 2, 3), nome = c("Anna", "Luca", "Sara"))
esami <- tibble(id = c(1, 1, 2, 4), voto = c(28, 30, 24, 27))
Che differenza c'è tra
semi_join(studenti, esami, by = "id") e
inner_join(studenti, esami, by = "id")?
semi_join è un filtering join: filtra le righe
della prima tabella tenendo quelle che hanno almeno una
corrispondenza nella seconda, senza aggiungere colonne e senza duplicare
righe. Anna e Luca compaiono una sola volta ciascuno: 2 righe.
inner_join è un mutating join: aggiunge le colonne
di esami e ripete Anna per ciascuno dei suoi due esami: 3
righe.
La seconda opzione nega una differenza che c'è. La terza è la più
insidiosa: è corretto che semi_join non aggiunga colonne,
ma non duplica nemmeno le righe. La quarta descrive
anti_join.
Si considerino le due tibble seguenti:
studenti <- tibble(id = c(1, 2, 3), nome = c("Anna", "Luca", "Sara"))
esami <- tibble(id = c(1, 1, 2, 4), voto = c(28, 30, 24, 27))
Che cosa restituisce l'istruzione
anti_join(studenti, esami, by = "id")?
anti_join(x, y) restituisce le righe della
prima tabella che non hanno
corrispondenza nella seconda: lo studente con id 3, Sara. È utile per
individuare dati mancanti o incoerenti, come gli iscritti che non hanno
ancora sostenuto esami.
La seconda opzione descrive semi_join. La terza è la più
insidiosa: anti_join non è simmetrico e considera solo le
righe della prima tabella; l'esame con id 4 si individua con
anti_join(esami, studenti, by = "id"). La quarta non ha
fondamento.
Nella tabella esami la matricola si trova nella colonna
matr, nella tabella anagrafica nella colonna
matricola. Quale istruzione unisce correttamente le due
tabelle?
Quando le colonne chiave hanno nomi diversi, la corrispondenza si
indica con join_by(): a sinistra di == la
colonna della prima tabella, a destra quella della seconda. Una sintassi
equivalente è by = c("matr" = "matricola"), cioè un vettore
con nomi.
Senza by, il join usa le colonne con lo stesso nome
nelle due tabelle; qui non ce ne sono e R restituisce l'errore
`by` must be supplied when `x` and `y` have no common variables.
La terza è la più insidiosa: un vettore senza nomi
chiede di usare come chiavi due colonne, matr e
matricola, che dovrebbero esistere entrambe in entrambe le
tabelle. La quarta passa due vettori al posto di due tabelle.
Le tibble lab_r e lab_python hanno entrambe
le colonne matricola, cognome e
nome. Che cosa accade eseguendo
inner_join(lab_r, lab_python) senza specificare l'argomento
by?
Se by non è specificato, dplyr esegue un
cosiddetto natural join, usando come chiave tutte le colonne
presenti con lo stesso nome in entrambe le tabelle, e stampa un
messaggio con la chiave utilizzata. Due righe vengono abbinate solo se
coincidono in tutte e tre le colonne: basta un errore di battitura nel
nome per perdere la corrispondenza. Per questo è buona pratica indicare
sempre la chiave in modo esplicito.
L'errore si ha solo quando le tabelle non hanno colonne in comune. La
terza è la più insidiosa: matricola sarebbe la chiave più
sensata, ma R non può saperlo e usa tutte le colonne comuni. La quarta
descrive union_all, non un join.
Le tibble lab_r e lab_python hanno entrambe
le colonne matricola, cognome e
nome. Quali sono i nomi delle colonne del risultato di
inner_join(lab_r, lab_python, by = "matricola")?
Le colonne con lo stesso nome che non sono usate
come chiave compaiono in entrambe le tabelle: per distinguerle,
dplyr aggiunge per default il suffisso .x a
quelle della prima tabella e .y a quelle della seconda. I
suffissi si possono scegliere con l'argomento suffix, ad
esempio suffix = c("_r", "_python").
La seconda opzione è il risultato del join su tutte e tre le colonne. La terza è la più insidiosa: una tabella non può avere due colonne con lo stesso nome, ed è proprio per questo che servono i suffissi. La quarta applica i suffissi alla chiave, che invece compare una sola volta.
Si considerino le tibble:
x <- tibble(id = 1:2, nome = c("Nicolò", "Luca"))
y <- tibble(id = 1:2, nome = c("Nicolo", "Luca"))
Quante righe ha il risultato di intersect(x, y)?
Le operazioni su insiemi di dplyr confrontano le
righe intere: due righe sono considerate uguali solo se
coincidono in tutte le colonne. La riga con id 2 è identica nelle due
tabelle, mentre quella con id 1 differisce per l'accento sul nome: il
risultato contiene solo la riga di Luca.
0 trascura che la riga di Luca è identica. 2 è la risposta più
insidiosa: è il risultato che si otterrebbe confrontando solo la colonna
id, ad esempio con semi_join(x, y, by = "id").
4 è la somma delle righe delle due tabelle, cioè
union_all.
Le tibble a e b hanno le stesse colonne;
a ha 12 righe, b ne ha 9, e 3 righe sono
presenti (identiche) in entrambe. Quante righe hanno, nell'ordine,
union(a, b) e union_all(a, b)?
union restituisce le righe presenti in almeno una delle
due tabelle, senza duplicati: 12 + 9 − 3 = 18.
union_all accoda semplicemente le righe della seconda
tabella a quelle della prima, conservando i duplicati: 12 + 9 = 21.
La seconda opzione inverte i due risultati. La terza è la più
insidiosa: trascura che union, come l'unione insiemistica,
conta una sola volta gli elementi comuni. La quarta attribuisce a
union il risultato dell'intersezione.
Si considerino le tibble
a <- tibble(n = c("A", "B", "C")) e
b <- tibble(n = c("B", "C", "D", "E")). Che cosa
restituisce setdiff(b, a)?
setdiff(x, y) restituisce le righe di x che
non compaiono in y. Con b come prima tabella
si ottengono le righe di b assenti in a, cioè
D ed E. L'operazione non è simmetrica:
setdiff(a, b) restituirebbe invece la sola riga
A.
La seconda opzione è il risultato di setdiff(a, b), cioè
con le tabelle in ordine inverso. La terza è la più insidiosa: contiene
le righe presenti in una sola delle due tabelle, ed è il risultato di
symdiff(a, b). La quarta è l'intersezione.
Le tibble lab_r e lab_python contengono gli
iscritti a due laboratori, con le stesse colonne. Quale operazione
restituisce gli studenti iscritti a uno solo dei due
laboratori?
symdiff (differenza simmetrica) restituisce le righe
presenti in una sola delle due tabelle, cioè in lab_r ma
non in lab_python oppure in lab_python ma non
in lab_r. Il numero di righe del risultato è pari a quello
di union meno quello di intersect.
union_all accoda le righe delle due tabelle, conservando
anche i duplicati. La terza è la più insidiosa: setdiff
restituisce solo gli iscritti al laboratorio di R che non frequentano
quello di Python, e trascura chi è iscritto soltanto a Python. La quarta
restituisce l'esatto contrario, cioè gli iscritti a entrambi i
laboratori.
Si considerino le istruzioni:
a <- tibble(n = c("A", "B", "C"))
setequal(a, arrange(a, desc(n)))
identical(a, arrange(a, desc(n)))
Che cosa restituiscono le ultime due istruzioni, nell'ordine?
arrange(a, desc(n)) contiene le stesse righe di
a in ordine inverso. setequal verifica se due
tabelle contengono le stesse righe, indipendentemente
dall'ordine: restituisce TRUE.
identical verifica che i due oggetti siano esattamente
uguali, ordine compreso: restituisce FALSE.
La seconda opzione inverte i due comportamenti. La terza è la più insidiosa: le due tabelle sono uguali come insiemi di righe, ma non come oggetti. La quarta è errata: il risultato di una funzione può sempre essere passato come argomento a un'altra.
Che cosa restituisce la seguente istruzione?
levels(factor(c("medio", "alto", "basso", "alto")))
Per default factor() usa come livelli i valori distinti
del vettore in ordine alfabetico. Per ottenere un
ordine diverso, ad esempio quello naturale
"basso" "medio" "alto", bisogna indicarlo esplicitamente
con l'argomento levels.
La seconda opzione riporta i valori del vettore, non i livelli: i
livelli sono i valori distinti. La terza è la più insidiosa: è l'ordine
"naturale" che un lettore si aspetta, ma R non può conoscerlo e usa
l'ordine alfabetico. La quarta è il numero di livelli, che si ottiene
con nlevels().
Che cosa restituisce la seguente istruzione?
factor(c("medio", "alto", "Basso"), levels = c("basso", "medio", "alto"))
Quando si specifica l'argomento levels, i valori che non
corrispondono esattamente a nessuno dei livelli indicati diventano
NA, senza alcun errore né avvertimento. Poiché R distingue
tra maiuscole e minuscole, "Basso" non corrisponde al
livello "basso".
La seconda opzione immagina che R aggiunga automaticamente i valori
mancanti ai livelli. La terza è la più insidiosa: suppone che R ignori
la differenza tra maiuscole e minuscole e corregga il valore. La quarta
è errata: la conversione avviene in silenzio, ed è proprio per questo
che conviene controllare il numero di NA dopo aver creato
un factor.
Che cosa restituisce la seguente istruzione?
factor(c("F", "M", "F"), levels = c("F", "M"), labels = c("Femmina", "Maschio"))
L'argomento levels indica quali valori sono presenti nei
dati e in quale ordine; labels indica le etichette con cui
quei livelli verranno mostrati, nello stesso ordine. Il risultato è un
factor con i valori Femmina Maschio Femmina e i livelli
Femmina e Maschio: i codici originali
F e M non sono più visibili.
La seconda opzione combina valori e livelli in modo incoerente: i valori di un factor sono sempre etichette dei suoi livelli. La terza è la più insidiosa: le etichette sostituiscono i livelli e non vengono conservate a parte. La quarta riporta solo i livelli, non i valori del vettore, che ha lunghezza 3.
Che cosa restituisce l'ultima delle seguenti istruzioni?
o <- factor(c("basso", "alto", "medio"),
levels = c("basso", "medio", "alto"),
ordered = TRUE)
o > "medio"
In un ordered factor i livelli hanno un ordine
(basso < medio < alto) e gli operatori relazionali
confrontano le posizioni dei livelli. Solo
"alto" segue "medio", quindi il risultato è
FALSE TRUE FALSE.
La seconda opzione è il risultato del confronto tra stringhe in
ordine alfabetico, cioè di as.character(o) > "medio": né
"basso" né "alto" seguono "medio"
nell'alfabeto. La terza è la più insidiosa: è ciò che accade con un
factor non ordinato (creato senza
ordered = TRUE), per il quale il confronto non ha
significato. La quarta restituisce l'elemento che soddisfa la
condizione, che si otterrebbe con o[o > "medio"].
Il data frame df ha una colonna genere di
tipo character. Si esegue l'istruzione seguente, senza
alcuna assegnazione:
mutate(df, genere = factor(genere))
Che cosa restituisce poi class(df$genere)?
mutate restituisce una nuova tabella
con la colonna modificata, senza alterare l'oggetto di partenza: il
risultato viene stampato in console e poi perso. Per rendere permanente
la conversione bisogna assegnare il risultato, ad esempio
df <- mutate(df, genere = factor(genere)), che equivale
a df$genere <- factor(df$genere).
La seconda opzione confonde la classe della colonna con quella della
tabella. La terza è l'errore più frequente: in R le funzioni non
modificano gli oggetti ricevuti come argomento, e anche le funzioni di
dplyr seguono questa regola. La quarta è priva di
fondamento: mutate sostituisce la colonna con lo stesso
nome, non la elimina.
Che cosa restituisce la seguente istruzione?
df <- tibble(prezzo = c(10, 4), quantita = c(3, 5))
mutate(df, totale = prezzo * quantita, iva = totale * 0.22)
All'interno di mutate le colonne della tabella si
indicano direttamente con il loro nome. Le operazioni sono vettoriali,
cioè eseguite riga per riga: totale vale 10 × 3 = 30 e 4 ×
5 = 20. Le nuove colonne vengono create nell'ordine in cui sono scritte,
per cui iva può già usare totale.
La seconda opzione è errata: df$prezzo funzionerebbe, ma
non è necessario, perché mutate cerca i nomi tra le colonne
della tabella. La terza è la più insidiosa: le colonne create da
mutate sono subito disponibili per le espressioni
successive nella stessa chiamata. La quarta confonde il prodotto riga
per riga con un prodotto scalare.
Si aggiunge a una tabella la colonna
log_reddito = log(reddito) all'interno di
mutate(). La colonna reddito contiene, tra gli
altri, i valori 1, 0 e -1. Quali
valori assume log_reddito in corrispondenza di questi tre
valori?
log(1) vale 0. Il logaritmo di 0 tende a meno infinito e
R restituisce -Inf. Il logaritmo di un numero negativo non
è definito nei reali e R restituisce NaN, con un
avvertimento. Prima di applicare una trasformazione logaritmica conviene
quindi verificare il campo di variazione della variabile: valori nulli o
negativi producono -Inf o NaN, che si
propagano poi in calcoli come la media.
La seconda opzione immagina che R lasci invariati i valori
problematici. La terza è la più insidiosa: -Inf e
NaN sono valori riservati diversi da NA (anche
se is.na() restituisce TRUE per
NaN). La quarta è errata: il calcolo viene comunque
eseguito.
Che cosa restituisce la seguente istruzione?
if_else(c(30, 25) > 28, "alto", 0)
if_else di dplyr è "stretta" sui tipi: i
valori per il caso vero (true) e per il caso falso
(false) devono avere lo stesso tipo, e qui sono
character e double. R restituisce l'errore
Can't combine `true` <character> and `false` <double>.
Il controllo serve a evitare conversioni silenziose: per un risultato di
tipo carattere bisogna scrivere "0".
La seconda opzione restituisce il risultato della sola condizione. La
terza è la più insidiosa: è il comportamento della funzione
ifelse di base, che converte silenziosamente
il numero in stringa. La quarta restituisce un solo valore, mentre
if_else restituisce un valore per ogni elemento della
condizione.
Che cosa restituisce la seguente istruzione?
if_else(c(5, NA, 1) > 3, "alto", "basso")
Il confronto NA > 3 restituisce NA: per
quell'elemento non si sa se la condizione sia vera o falsa, e
if_else restituisce NA. Per assegnare un
valore specifico ai casi con condizione mancante si usa l'argomento
missing, ad esempio missing = "n.d.".
La seconda opzione restituisce un solo valore. La terza è la più
insidiosa: tratta il valore mancante come se la condizione fosse falsa,
ma per R una condizione NA non è né vera né falsa. La
quarta è il risultato che si otterrebbe con
missing = "n.d.", argomento che qui non è stato
specificato.
Che cosa restituisce la seguente istruzione?
v <- c(30, 25, 18)
case_when(
v >= 18 ~ "sufficiente",
v >= 26 ~ "buono",
v >= 29 ~ "ottimo"
)
case_when valuta le condizioni nell'ordine in
cui sono scritte e, per ogni elemento, usa la prima condizione
vera. Tutti e tre i voti soddisfano già la prima condizione
(v >= 18), quindi le successive non vengono mai
applicate. Le condizioni vanno scritte dalla più restrittiva alla meno
restrittiva: prima v >= 29, poi v >= 26,
infine v >= 18.
La seconda opzione è il risultato corretto con le condizioni nell'ordine giusto: 25 è minore di 26 e quindi "sufficiente". La terza è la più insidiosa: corrisponde a ciò che si "intende" scrivendo le condizioni, ma ignora la regola della prima condizione vera e attribuisce anche a 25 il giudizio "buono". La quarta associa le etichette alle posizioni.
Che cosa restituisce la seguente istruzione?
case_when(c(30, 15) >= 18 ~ "superato")
Agli elementi che non soddisfano nessuna condizione
case_when assegna NA. Per assegnare un valore
a tutti i casi rimanenti si usa l'argomento .default, ad
esempio .default = "non superato".
La seconda opzione restituisce un solo valore, mentre
case_when restituisce un valore per ogni elemento. La terza
è la più insidiosa: è il risultato con
.default = "non superato", ma R non può indovinare
l'etichetta da assegnare. La quarta è errata: non è necessario coprire
tutti i casi.
Si considerino le istruzioni:
s <- c("TP", "PT", "XX")
recode_values(s, "TP" ~ "Tempo pieno", "PT" ~ "Part-time")
replace_values(s, "TP" ~ "Tempo pieno", "PT" ~ "Part-time")
In che cosa differiscono i due risultati?
recode_values costruisce un vettore
nuovo a partire dalle regole indicate: i valori non
previsti diventano NA, a meno di specificare l'argomento
default. replace_values
sostituisce solo i valori indicati e lascia invariati
tutti gli altri. Si usa quindi recode_values per
ricodificare completamente una variabile e replace_values
per correggere alcuni valori, ad esempio un errore di battitura.
La seconda opzione è errata: nessuna delle due modifica
s; per conservare il risultato bisogna assegnarlo. La terza
è la più insidiosa: per i valori previsti dalle regole le due funzioni
producono lo stesso risultato, e la differenza emerge solo per i valori
non previsti. La quarta è errata: entrambe restituiscono un vettore di
caratteri.
Che cosa restituisce la seguente istruzione?
cut(c(0, 5, 10), breaks = c(0, 5, 10))
Per default cut crea intervalli chiusi a
destra e aperti a sinistra (right = TRUE):
(0,5] e (5,10]. Il valore 0 coincide con
l'estremo sinistro del primo intervallo, che è escluso, e diventa quindi
NA, senza alcun avvertimento. Per includerlo si usa
include.lowest = TRUE, che produce
[0,5] [0,5] (5,10].
La seconda opzione è il risultato con right = FALSE
(intervalli chiusi a sinistra), in cui a restare escluso è il valore 10.
La terza è la più insidiosa: è il risultato con
include.lowest = TRUE, ma non con i valori di default. La
quarta restituisce i valori originali, ignorando la classificazione.
Il vettore z <- c(1, 2, 3, 4, 5, 6, 7, 8, 100) deve
essere suddiviso in 3 classi contenenti lo stesso numero di
osservazioni. Quale funzione del package ggplot2 è adatta
allo scopo?
cut_number costruisce n classi che
contengono (approssimativamente) lo stesso numero di osservazioni,
usando come estremi i quantili: qui 3 osservazioni per classe. È utile
con variabili asimmetriche o con valori anomali.
cut_width costruisce classi di ampiezza fissa, 3 in
questo caso, quindi molte classi quasi tutte vuote. La terza è la più
insidiosa: cut_interval costruisce n classi
della stessa ampiezza, non con lo stesso numero di
osservazioni; a causa del valore 100 restituisce classi con 8, 0 e 1
osservazioni. La quarta usa una funzione che ordina le righe di una
tabella e non accetta un vettore.
La tibble t3 ha le colonne a,
b, c e d, in quest'ordine. Quale
ordine delle colonne si ottiene con
relocate(t3, d, .after = a)?
relocate sposta le colonne indicate senza eliminare le
altre: con .after = a la colonna d viene
collocata subito dopo a, e le altre colonne mantengono il
loro ordine relativo.
La seconda opzione è il risultato di relocate(t3, d),
senza .after: per default le colonne indicate vengono
spostate all'inizio. La terza è la più insidiosa, perché suppone che
l'operazione lasci la tabella invariata. La quarta confonde
relocate con la selezione di una colonna, che elimina le
altre.
Che cosa restituisce la seguente istruzione?
arrange(tibble(x = c(3, NA, 7)), desc(x))$x
desc() ordina in senso decrescente. arrange
colloca sempre i valori mancanti in fondo, sia
nell'ordinamento crescente sia in quello decrescente.
La seconda opzione è la più insidiosa: ragiona come se l'ordine
decrescente fosse l'esatto contrario di quello crescente, e quindi porta
in testa i valori mancanti. La terza tratta NA come il
valore più piccolo e ignora desc. La quarta lascia la
tabella nell'ordine originale.
Quale istruzione rinomina la colonna voto_laurea_su_110
della tibble anagrafica in voto_triennale?
In rename la sintassi è
nuovo_nome = vecchio_nome, come in un'assegnazione: a
sinistra il nome che si vuole ottenere, a destra quello attuale. Il
risultato va poi assegnato per rendere permanente la modifica.
La seconda opzione non indica quale colonna rinominare. La terza è la
più insidiosa: inverte i due nomi, e R restituisce l'errore Can't
rename columns that don't exist, perché cerca una colonna
voto_triennale che non esiste. La quarta assegna un unico
nome a tutta la tabella: la prima colonna verrebbe rinominata
voto_triennale e le altre resterebbero senza nome.
Si vuole usare un assistente AI per ottenere il codice R che aggiunge una colonna a una tabella. Quale dei seguenti modi di procedere è il più appropriato?
Un assistente AI è più utile quanto più è preciso il contesto: nomi reali delle tabelle e delle colonne, tipi di dato, package e funzioni da preferire. Il codice ottenuto va sempre eseguito e controllato sui dati, ad esempio contando i valori mancanti o verificando alcune righe "a mano". Chi lo inserisce nello script ne è responsabile e deve essere in grado di spiegarlo.
La seconda opzione è una generalizzazione infondata: il codice
generato è spesso utile come punto di partenza. La terza è la più
insidiosa: l'assenza di errori non garantisce la correttezza; un codice
può funzionare e produrre un risultato sbagliato, ad esempio
classificando male alcuni casi o trasformando silenziosamente dei valori
in NA. La quarta confonde l'aiuto nella scrittura del
codice con l'analisi dei dati, che va eseguita e controllata da chi la
svolge.