HW 04 - Manipolazione, sintesi e pivoting dei dati

Data di consegna: giovedì 22 ottobre 2026

Introduzione

In questo compito lavorerai sui dati (fittizi) di una rete di dodici musei di una provincia: le informazioni sui musei, il numero mensile di visitatori nel 2024 e nel 2025 e le risposte a un questionario di gradimento compilato dai visitatori nel 2025.

In questo compito utilizzerai i comandi utili per:

  • selezionare colonne e filtrare righe con select e filter
  • trasformare una tabella dal formato largo al formato lungo e viceversa con pivot_longer e pivot_wider
  • calcolare sintesi per gruppi con group_by e summarise
  • imputare i valori mancanti con group_by e mutate
  • trasformare dati annidati in tabelle (rectangling) e annidare le righe di una tabella (nesting)
  • confrontare le funzioni di R base con quelle del tidyverse

Obiettivi di apprendimento

Lo svolgimento di questo compito ti permetterà di:

  • riconoscere quando una tabella è in formato tidy e trasformarla nel formato più adatto all’analisi o alla presentazione
  • scegliere il livello di raggruppamento adatto a una domanda
  • valutare le conseguenze dei valori mancanti sulle sintesi e scegliere un metodo di imputazione ragionevole
  • leggere codice scritto in R base e tradurlo con i verbi del tidyverse, e viceversa

Istruzioni per l’uso

  • Crea un progetto RStudio di nome hw04 (in Positron: crea una cartella hw04 e aprila con File → Open Folder) e lavora all’interno del progetto per tutto il compito.

  • All’interno della cartella del progetto crea una sottocartella dati e salva al suo interno i tre file dei dati che trovi su Teams, allegati al compito:

    • musei.csv
    • visitatori.csv
    • questionario.xlsx
  • Nello script indica i file sempre con un percorso relativo alla cartella del progetto, ad esempio "dati/musei.csv".

  • Rispondi ai vari punti salvando le risposte in un file R con il nome “hw04_cognome_nome.R”: ad esempio nel mio caso il nome del file sarebbe “hw04_vistocco_domenico.R”. Salva lo script nella cartella del progetto.

  • Inizia lo script con un commento che riporti titolo del compito, nome, cognome e data.

  • Per rispondere ad ogni punto inserisci un’etichetta di sezione (che puoi inserire nello script usando la combinazione di tasti CTRL/CMD + SHIFT + R) utilizzando il punto cui stai rispondendo. Ad esempio, per rispondere al punto 1 del compito, usa un’etichetta di sezione:

    # PUNTO 1 ------------------------------------------------
  • Utilizza i commenti per rispondere alle domande in cui viene chiesta un’interpretazione da parte tua: nei commenti concentrati sul comportamento di R e sul significato dei risultati, con parole tue.

  • Lo script deve essere funzionante quando si eseguono tutti i comandi con il pulsante Source. I comandi che restituiscono un errore vanno lasciati nello script ma commentati, riportando subito sotto, sempre come commento, il messaggio di errore ottenuto.

  • Rispetta le regole di stile viste in aula: nomi degli oggetti in snake case, <- per l’assegnazione, spazi attorno agli operatori e dopo le virgole, una istruzione per riga, un a capo dopo ogni pipe.

  • Lo script viene valutato sia in base alla correttezza del codice che in base alla qualità (stile utilizzato per rendere lo script leggibile ed ordinato).

I dati

musei.csv (campi separati da ;): una riga per museo, con codice, nome, tipologia (Archeologia, Arte, Scienza, Storia), tipo di gestione (Statale, Comunale, Privato), comune e prezzo del biglietto intero in euro.

visitatori.csv (campi separati da ,): una riga per museo e anno, con il codice del museo, l’anno e una colonna per ciascun mese (gen, feb, …, dic) con il numero di visitatori. Le celle vuote corrispondono a dati che il museo non ha trasmesso.

questionario.xlsx: il foglio Risposte contiene una riga per ogni questionario compilato, con il codice del museo, la fascia di età e la provenienza del visitatore e i punteggi (da 1 a 5) assegnati a cinque aspetti della visita, nelle colonne D1, …, D5; il foglio Domande contiene il testo delle cinque domande.

NoteNota

Nel 2025 il Museo del Risorgimento è rimasto chiuso da marzo a giugno per lavori di restauro.

Esercizi

NoteNota

Ricordati di utilizzare i commenti per le risposte aperte e di commentare i comandi che restituiscono un errore. Quando una domanda chiede “quanti” o “quali”, rispondi con il codice che produce il risultato e riporta la risposta anche in un commento.

Parte 1: Importazione dei dati

  1. Carica i package tidyverse, readxl e janitor

  2. Importa il file musei.csv in un oggetto musei e pulisci i nomi delle colonne. Verifica che la colonna del prezzo del biglietto sia numerica

TipSuggerimento

Prima di scegliere la funzione di importazione, apri il file come testo e osserva il separatore delle colonne e il separatore decimale.

  1. Importa il file visitatori.csv in un oggetto visitatori e pulisci i nomi delle colonne. Stampa a video le dimensioni della tabella e spiega perché non è in formato tidy
NotePer approfondire: il formato tidy

Per i dettagli su cosa si intenda per formato tidy e sui principi che lo definiscono, fai riferimento a:

  1. Importa i due fogli del file questionario.xlsx in due oggetti risposte e domande, pulendo i nomi delle colonne

  2. Stampa a video le dimensioni delle quattro tabelle importate. Quanti musei diversi compaiono nella tabella risposte?

  3. Quali musei non hanno partecipato al questionario di gradimento?

Parte 2: Selezione di colonne e filtro di righe

  1. Seleziona dalla tabella musei le colonne del nome, della tipologia e del prezzo del biglietto, rinominando quest’ultima prezzo nella stessa istruzione

  2. Seleziona dalla tabella musei tutte le colonne tranne la gestione e il comune. Seleziona poi dalla tabella visitatori il museo, l’anno e i soli mesi estivi (giugno, luglio e agosto)

TipSuggerimento

In select l’operatore : permette di indicare un intervallo di colonne contigue, ad esempio giu:ago.

  1. Quali musei d’arte hanno un biglietto intero che costa al massimo 8 euro?

  2. Quali musei si trovano nei comuni di Marina o di Borgo Antico? Usa l’operatore %in%

  3. Quali musei sono gratuiti oppure a gestione statale?

  4. Quali musei hanno avuto più di 5000 visitatori nel luglio 2025?

  5. Usando un’unica sequenza di istruzioni collegate dalla pipe, ottieni l’elenco dei musei d’arte con il solo nome e il prezzo del biglietto, ordinati dal più caro al più economico

Parte 3: Pivoting

  1. Trasforma la tabella visitatori in formato lungo, in un oggetto visitatori_long con le colonne museo, anno, mese e visitatori. Stampa a video le dimensioni della nuova tabella e spiega come si ottiene il numero di righe. Quanti valori mancanti contiene la colonna visitatori?

  2. Stampa a video la classe della colonna mese e ordina visitatori_long per museo, anno e mese: in che ordine compaiono i mesi? Trasforma poi la colonna mese in un factor con i livelli nell’ordine del calendario, ripeti l’ordinamento e commenta la differenza

TipSuggerimento

Per non riscrivere più volte l’elenco dei mesi, salvalo in un vettore: mesi <- c("gen", "feb", "mar", "apr", "mag", "giu", "lug", "ago", "set", "ott", "nov", "dic").

  1. Mostra le righe di visitatori_long in cui i visitatori sono pari a 0 e quelle in cui il valore è mancante. Commenta la differenza tra i due casi alla luce delle informazioni sui dati

  2. Trasforma visitatori_long in un oggetto visitatori_anni con una riga per museo e mese e una colonna per ciascun anno, e stampa a video i nomi delle colonne. Aggiungi poi una colonna var_perc con la variazione percentuale dei visitatori tra il 2024 e il 2025, risolvendo il problema dei nomi delle colonne in entrambi i modi descritti nel suggerimento. Prova infine a calcolare la variazione scrivendo i nomi delle colonne senza apici inversi, cioè (2025 - 2024) / 2024 * 100, e commenta il risultato: R segnala un errore?

TipSuggerimento

Con names_from = anno le nuove colonne prendono come nome i valori della colonna anno, cioè 2024 e 2025. Poiché iniziano con una cifra, non sono nomi validi secondo le regole di nomenclatura viste nella prima settimana. Ci sono due modi per gestirli:

  • lasciare i nomi così come sono e richiamarli racchiudendoli tra apici inversi, ad esempio `2025` - `2024`
  • ottenere direttamente nomi validi con l’argomento names_prefix di pivot_wider, che aggiunge un prefisso ai nomi delle nuove colonne: con names_prefix = "anno_" le colonne si chiamano anno_2024 e anno_2025
  1. Quali sono le cinque combinazioni museo-mese con la crescita percentuale più alta? E le cinque con il calo più forte? Commenta il risultato

  2. Riporta visitatori_long in formato largo, con una colonna per mese, e verifica con setequal che il risultato contenga le stesse righe della tabella visitatori di partenza

  3. Commenta brevemente: per quali operazioni è più comodo il formato lungo, e per quali il formato largo?

Parte 4: Sintesi per gruppi

  1. Calcola il totale annuo dei visitatori per ciascun museo e anno in tre modi: con sum(visitatori), con sum(visitatori, na.rm = TRUE) e contando il numero di mesi mancanti. Mostra solo le combinazioni museo-anno con almeno un mese mancante e commenta: quale dei due totali è più affidabile?

  2. Unisci a visitatori_long le informazioni sui musei, salvando il risultato in un oggetto visitatori_completo. Stampa a video le dimensioni della tabella ottenuta

  3. Per ciascuna tipologia di museo e per ciascun anno, calcola il numero di musei e il totale dei visitatori. Commenta l’andamento della tipologia Storia

  4. Per ciascuna tipologia, qual è stato nel 2025 il mese con più visitatori? Commenta il risultato

TipSuggerimento

Dopo aver calcolato il totale per tipologia e mese, la tabella resta raggruppata per tipologia: un successivo filter(totale == max(totale)) lavora quindi all’interno di ciascuna tipologia.

  1. Per il 2025, calcola il totale dei visitatori di ciascun museo e la sua quota sul totale dei visitatori della propria tipologia. Spiega perché le quote sommano a 1 all’interno di ciascuna tipologia

  2. Supponendo che tutti i visitatori abbiano pagato il biglietto intero, calcola l’incasso stimato del 2025 per ciascun museo e ordina i musei dall’incasso più alto al più basso. Commenta i limiti di questa stima

  3. Per ciascun tipo di gestione, calcola il numero di musei, il prezzo medio e il prezzo massimo del biglietto

Parte 5: Imputazione dei valori mancanti

In questa parte confronterai tre modi di sostituire i valori mancanti della colonna visitatori di visitatori_long. Salva i risultati in un oggetto visitatori_imp, aggiungendo una nuova colonna per ciascun metodo.

  1. Aggiungi una colonna imp_generale in cui i valori mancanti sono sostituiti con la media di tutti i valori disponibili della colonna. Mostra le righe con valore originale mancante e commenta: il valore imputato è plausibile per tutti i musei?

  2. Aggiungi una colonna imp_museo in cui i valori mancanti sono sostituiti con la media dei valori disponibili dello stesso museo. Mostra di nuovo le righe con valore originale mancante e confronta i due metodi

  3. Aggiungi una colonna imp_mese in cui i valori mancanti sono sostituiti con la media dei valori disponibili dello stesso museo nello stesso mese. Dato che i dati coprono due anni, a cosa corrisponde in pratica il valore imputato? Perché questo metodo è più adatto dei precedenti per i musei con forte stagionalità?

TipSuggerimento

Usa group_by seguito da mutate (e non da summarise), in modo da conservare tutte le righe. Ricorda di chiudere la sequenza con ungroup().

  1. Per le sole combinazioni museo-anno con almeno un mese mancante, confronta in un’unica tabella il totale annuo senza imputazione (con na.rm = TRUE) e i totali ottenuti con i tre metodi. Commenta le differenze

  2. Perché gli zeri del Museo del Risorgimento non vanno trattati come valori mancanti? Cosa accadrebbe se li trasformassi in NA e li imputassi con il metodo del punto 30?

  3. Usando i valori imputati con il metodo del punto 30, calcola il totale annuo dei visitatori di ciascun museo nel 2024 e nel 2025, con una colonna per anno, e la variazione percentuale tra i due anni. Aggiungi il nome del museo subito dopo il codice e ordina i musei dalla crescita più alta alla più bassa. Commenta il risultato del Museo del Risorgimento

Parte 6: Il questionario di gradimento

  1. Trasforma la tabella risposte in formato lungo, in un oggetto risposte_long con una riga per ogni risposta e le colonne codice (codice della domanda) e punteggio, eliminando le risposte mancanti. Quante risposte mancanti sono state eliminate?

  2. Unisci a risposte_long il testo delle domande contenuto nella tabella domande. Conta le righe in cui il testo della domanda è mancante, spiega il problema e correggilo

TipSuggerimento

Confronta i valori della colonna codice nelle due tabelle. La funzione toupper trasforma le lettere di una stringa in maiuscole.

  1. Per ciascuna domanda calcola il numero di risposte e il punteggio medio. Quale aspetto della visita è valutato peggio? E quale meglio?

  2. Costruisci una tabella con una riga per museo e una colonna per ciascuna domanda, contenente il punteggio medio. Aggiungi il nome del museo subito dopo il codice e ordina i musei per soddisfazione complessiva (D5) decrescente

  3. Il giudizio sul rapporto qualità/prezzo (D4) cambia a seconda della provenienza dei visitatori? E la soddisfazione complessiva (D5) a seconda della fascia di età?

  4. Affianca, per ciascun museo che ha partecipato al questionario, il prezzo del biglietto e il punteggio medio sul rapporto qualità/prezzo. Ordinando per prezzo, osservi una relazione tra le due variabili?

  5. Quanti questionari sono stati raccolti in ciascun museo? Ordina il risultato in senso decrescente

TipSuggerimento

La funzione count(tabella, colonna, sort = TRUE) equivale a group_by(colonna) seguito da summarise(n = n()) e da un ordinamento decrescente.

Parte 7 (facoltativa): Rectangling e nesting

NoteParte facoltativa

Questa parte riguarda argomenti accennati solo brevemente in aula. È facoltativa: provala dopo aver completato le altre parti, partendo dall’esempio che segue.

Finora abbiamo lavorato con tabelle in cui ogni cella contiene un singolo valore. Una colonna di una tibble può però essere anche una lista (list-column), in cui ogni cella contiene un oggetto più complesso: un vettore, una lista o perfino un’altra tabella. Dati di questo tipo sono frequenti quando si scaricano informazioni dal web o da un database, e vengono detti annidati.

Il rectangling consiste nel trasformare dati annidati in una tabella rettangolare, con un valore per cella. Si procede di solito in due passi:

  • unnest_longer “allunga” la tabella: ogni elemento della lista diventa una riga, e i valori delle altre colonne vengono ripetuti
  • unnest_wider “allarga” la tabella: ogni elemento con nome diventa una colonna

Nel seguente esempio, per ciascuno studente la colonna esami contiene una lista di esami, e ogni esame è a sua volta una lista con due elementi, corso e voto:

library(tidyverse)
studenti <- tibble(
  nome = c("Anna", "Luca"),
  esami = list(
    list(list(corso = "Statistica", voto = 28),
         list(corso = "R Lab", voto = 30)),
    list(list(corso = "Statistica", voto = 25))
  )
)
studenti
# A tibble: 2 × 2
  nome  esami     
  <chr> <list>    
1 Anna  <list [2]>
2 Luca  <list [1]>
# primo passo: una riga per esame
esami_righe <- unnest_longer(studenti, esami)
esami_righe
# A tibble: 3 × 2
  nome  esami           
  <chr> <list>          
1 Anna  <named list [2]>
2 Anna  <named list [2]>
3 Luca  <named list [2]>
# secondo passo: una colonna per ciascun elemento dell'esame
unnest_wider(esami_righe, esami)
# A tibble: 3 × 3
  nome  corso       voto
  <chr> <chr>      <dbl>
1 Anna  Statistica    28
2 Anna  R Lab         30
3 Luca  Statistica    25

Il nesting è l’operazione inversa: nest raccoglie le righe di una tabella per gruppi, memorizzando ciascun gruppo in una tabella contenuta in una list-column (chiamata per default data); unnest ricostruisce la tabella di partenza:

voti <- tibble(nome = c("Anna", "Luca", "Sara"),
               corso = c("A", "B", "A"),
               voto = c(28, 24, 30))
voti_annidati <- nest(voti, .by = corso)
voti_annidati
# A tibble: 2 × 2
  corso data            
  <chr> <list>          
1 A     <tibble [2 × 2]>
2 B     <tibble [1 × 2]>
voti_annidati$data[[1]]
# A tibble: 2 × 2
  nome   voto
  <chr> <dbl>
1 Anna     28
2 Sara     30
unnest(voti_annidati, data)
# A tibble: 3 × 3
  corso nome   voto
  <chr> <chr> <dbl>
1 A     Anna     28
2 A     Sara     30
3 B     Luca     24
  1. Copia ed esegui nello script il seguente codice, che crea una tibble con le mostre temporanee organizzate nel 2025 da alcuni musei. Stampa a video la tabella e la classe della colonna mostre, e descrivine la struttura
mostre <- tibble(
  codice_museo = c("M02", "M03", "M05", "M12"),
  mostre = list(
    list(list(titolo = "Il paesaggio nell'Ottocento", mesi = 4, visitatori = 8200),
         list(titolo = "Ritratti di famiglia", mesi = 3, visitatori = 3100)),
    list(list(titolo = "Dinosauri in città", mesi = 6, visitatori = 9800)),
    list(list(titolo = "Astrattismo italiano", mesi = 5, visitatori = 12400)),
    list(list(titolo = "Il cielo d'inverno", mesi = 2, visitatori = 5600),
         list(titolo = "Robot e intelligenza artificiale", mesi = 4, visitatori = 15300))
  )
)
  1. Trasforma mostre in una tabella rettangolare con una riga per mostra e le colonne codice_museo, titolo, mesi e visitatori, procedendo in due passi: prima con unnest_longer e poi con unnest_wider. Stampa a video il risultato intermedio e quello finale e commenta cosa fa ciascuna delle due funzioni

  2. Per ciascun museo calcola il numero di mostre, il totale dei visitatori delle mostre e il numero medio di visitatori per mese di apertura delle mostre; aggiungi il nome del museo

  3. Annida la tabella musei per tipologia con la funzione nest. Stampa a video il risultato e il contenuto del primo elemento della colonna data. Verifica poi con setequal che, riportando la tabella annidata alla forma originale con unnest, si ottengano le stesse righe di musei

Parte 8: R base e tidyverse a confronto

  1. Ottieni il risultato del punto 9 (con il solo nome e il prezzo dei musei) usando R base, in due modi: con il puntamento con le parentesi quadre e con la funzione subset
TipSuggerimento

La funzione subset(tabella, condizione, select = colonne) di R base filtra le righe e seleziona le colonne in un’unica chiamata.

  1. Seleziona da visitatori_long le righe con più di 10000 visitatori, una volta con il puntamento con le parentesi quadre e una volta con filter. Confronta i due risultati e spiega la differenza

  2. Calcola il numero medio di visitatori per mese (su tutti i musei e gli anni) con la funzione tapply di R base e con group_by e summarise. Confronta la forma dei due risultati

TipSuggerimento

tapply(vettore, gruppi, funzione, ...) applica la funzione ai valori del vettore separatamente per ciascun gruppo; gli argomenti successivi (ad esempio na.rm = TRUE) vengono passati alla funzione.

  1. Calcola il totale annuo dei visitatori per museo e anno con l’istruzione aggregate(visitatori ~ museo + anno, data = visitatori_long, FUN = sum). Confronta i totali dei musei con mesi mancanti con quelli ottenuti al punto 21: come tratta aggregate i valori mancanti?

  2. Ripeti il join del punto 22 con la funzione merge di R base. Confronta dimensioni, classe e ordine delle righe del risultato con quelli di visitatori_completo

TipSuggerimento

Quando le colonne chiave hanno nomi diversi, in merge si indicano con gli argomenti by.x e by.y.

  1. Mostra le sei righe di visitatori_long con il maggior numero di visitatori, una volta con la funzione order di R base e una volta con arrange. Alla luce dei punti 45-50, commenta brevemente vantaggi e svantaggi dei due approcci

Consegna

Per inviare la tua soluzione:

  • Carica il file hw04_cognome_nome.R su Teams, in risposta al compito assegnato

Valutazione

Totale punti disponibili: 110 punti

Component Punti
Es 1 - 40 e 45 - 50 100
Es 41 - 44 (facoltativi) -
Workflow & formattazione 101

Footnotes

  1. La valutazione al “Workflow & formattazione” tiene conto del rispetto delle regole di stile e del principio di riproducibilità del codice: lo script caricato deve funzionare senza errori su qualunque PC, eseguendolo con Source in una sessione con workspace vuoto e con i file dei dati nella sottocartella dati del progetto, dando gli stessi risultati↩︎