Esercitazione 01 - Il sistema bibliotecario cittadino

Lavoro di gruppo in aula

Introduzione

Il Comune ha chiesto al vostro gruppo di analizzare i dati del 2025 del sistema bibliotecario cittadino, composto da quattro biblioteche. I dati (fittizi) provengono da fonti diverse, sono in formati diversi e, come spesso accade con i dati reali, contengono alcune imprecisioni.

L’esercitazione si svolge in due fasi:

  • una parte comune, uguale per tutti i gruppi, in cui importerete, pulirete e unirete le tabelle dei dati
  • una missione, diversa per ogni gruppo, in cui risponderete ad alcune domande concrete sui dati

Al termine ogni gruppo presenterà alla classe i risultati della propria missione.

Obiettivi di apprendimento

Lo svolgimento dell’esercitazione vi permetterà di:

  • ripercorrere in un’unica analisi tutte le fasi viste finora: importazione, pulizia, codifica e incrocio delle tabelle
  • usare i verbi di dplyr per rispondere a domande concrete, compresi select, filter, group_by e summarise
  • scegliere la tabella e il tipo di join adatti alla domanda
  • spiegare ad altri il proprio codice e i propri risultati

Organizzazione

  • Lavorate in gruppi di 2 o 3 persone, con un solo computer su cui scrivere lo script. Alternatevi alla tastiera: chi non scrive consulta l’help, controlla i risultati e propone le soluzioni.

  • Avete a disposizione circa un’ora: indicativamente 20 minuti per la parte comune e 40 minuti per la missione. Se la parte comune vi richiede più tempo, non preoccupatevi: nella missione affrontate per primi i punti obbligatori.

  • Create un progetto RStudio di nome es01 con una sottocartella dati, in cui salvare i cinque file dei dati che trovate su Teams.

  • Scrivete le risposte in un unico script es01_gruppoN.R, dove N è il numero del vostro gruppo. Inserite all’inizio i nomi dei componenti del gruppo e usate un’etichetta di sezione per ogni punto (ad esempio # COMUNE 3 ---- oppure # MISSIONE B2 ----).

  • Commentate brevemente ogni risultato: la risposta alla domanda e, quando è il caso, le difficoltà incontrate.

  • Potete consultare l’help, i materiali del corso e un assistente AI, ma ogni istruzione presente nello script deve essere compresa dal gruppo e spiegabile durante la presentazione.

  • Al termine, uno dei componenti carica lo script su Teams per tutto il gruppo.

I dati

I file da salvare nella cartella dati sono i seguenti.

utenti.csv: anagrafe degli iscritti al sistema bibliotecario (una riga per utente, campi separati da ;)

Colonna Contenuto
ID Utente codice dell’utente
Genere F o M
Anno di nascita anno di nascita
Categoria STU studente, LAV lavoratore, PEN pensionato, DOC docente, ALT altro
Biblioteca di iscrizione codice della biblioteca presso cui l’utente si è iscritto
Anno iscrizione anno di iscrizione

prestiti.xlsx: due fogli. Il foglio Prestiti 2025 contiene il registro dei prestiti (una riga per prestito); il foglio Biblioteche le informazioni sulle quattro biblioteche

Colonna (foglio Prestiti 2025) Contenuto
N. prestito numero progressivo del prestito
Cod. utente codice dell’utente
Inventario codice di inventario del libro
Biblioteca codice della biblioteca in cui è avvenuto il prestito
Data prestito data del prestito
Data restituzione data della restituzione (vuota se il libro non è stato ancora restituito)
Proroga SI se il prestito è stato prorogato, NO altrimenti
Colonna (foglio Biblioteche) Contenuto
Codice codice della biblioteca
Nome nome della biblioteca
Quartiere quartiere in cui si trova
Ore apertura settimanali ore di apertura al pubblico in una settimana
Posti a sedere posti a sedere nelle sale di lettura

catalogo.txt: catalogo dei libri (una riga per libro, campi separati da tabulazione)

Colonna Contenuto
Inventario codice di inventario del libro
Titolo, Autore titolo e autore
Genere genere letterario: Narrativa, Saggistica, Poesia, Ragazzi, Fumetti
Anno pubblicazione anno della prima pubblicazione dell’opera

gruppo_lettura.csv e laboratorio_scrittura.csv: codici degli utenti iscritti alle due attività culturali organizzate nel 2025 (una sola colonna, ID utente)

NoteLe regole del prestito

Un prestito dura 30 giorni; con la proroga la durata sale a 60 giorni. I dati sono aggiornati al 31 dicembre 2025. Nel mese di agosto le biblioteche chiudono per la pausa estiva.

Parte comune (tutti i gruppi)

  1. Carica i package tidyverse, readxl e janitor

  2. Importa i cinque file (e i due fogli del file Excel) in sei tabelle chiamate utenti, prestiti, biblioteche, catalogo, gruppo_lettura e laboratorio_scrittura, pulendo sempre i nomi delle colonne con clean_names. Stampa a video le dimensioni di ciascuna tabella

TipSuggerimento
  • Prima di importare un file, osservatelo: quale separatore usa? Ci sono righe da saltare prima dell’intestazione?
  • Per i file di testo potete usare read_delim (indicando il separatore), read_csv o read_tsv; per il file Excel read_excel, indicando il foglio con l’argomento sheet.
  1. Controlla i valori distinti delle colonne categoria e genere di utenti e correggi i problemi di codifica che trovi. Poi, con un’unica chiamata di mutate:

    • ricodifica la categoria con le etichette estese (Studente, Lavoratore, Pensionato, Docente, Altro)
    • trasforma il genere in un factor con etichette Femmina e Maschio
    • aggiungi una colonna eta con l’età degli utenti nel 2025
TipSuggerimento

Ricorda le differenze tra le due funzioni:

  • replace_values sostituisce solo i valori indicati e lascia invariati gli altri; il risultato ha sempre lo stesso tipo del vettore di partenza, per cui i nuovi valori devono essere compatibili con esso (replace_values(c(1, 2), 1 ~ "si") restituisce un errore)
  • recode_values costruisce un vettore nuovo: i valori non previsti diventano NA e il tipo del risultato dipende dai nuovi valori, per cui permette ad esempio di passare da codici numerici a etichette testuali
  1. Sia utenti sia catalogo contengono una colonna chiamata genere, ma con un significato diverso. Cosa accadrebbe unendo le due tabelle in un’unica tabella? Rinomina la colonna di catalogo in genere_letterario

  2. Costruisci la tabella prestiti_completo che contenga, per ogni prestito effettuato da un utente presente in anagrafe, le informazioni sull’utente e sul libro. Confronta il numero di righe di prestiti e di prestiti_completo e conta le righe di prestiti_completo senza titolo del libro: cosa è successo?

ImportantPrima di passare alla missione

Verificate che prestiti_completo abbia lo stesso numero di righe ottenuto dagli altri gruppi: se ci sono differenze, confrontatevi prima di procedere.

Le missioni

Ogni gruppo svolge una sola missione, assegnata dal docente. I punti contrassegnati da ★ sono facoltativi: affrontateli solo se vi resta tempo.

TipVerbi utili per le missioni
  • filter(tabella, condizione) conserva solo le righe che soddisfano la condizione
  • select(tabella, colonne) conserva solo le colonne indicate
  • group_by(tabella, colonne) raggruppa le righe secondo i valori delle colonne indicate; i verbi successivi lavorano gruppo per gruppo
  • summarise(tabella, nome = funzione(colonna)) calcola una sintesi (per ogni gruppo, se la tabella è raggruppata); all’interno di summarise, n() restituisce il numero di righe del gruppo e n_distinct(colonna) il numero di valori distinti
  • arrange(tabella, desc(colonna)) ordina le righe in senso decrescente; head(tabella, 10) restituisce le prime 10 righe
  • x %in% y restituisce TRUE per gli elementi di x presenti nel vettore y

Missione A: Chi sono i lettori?

L’assessorato alla cultura vuole sapere quali gruppi di cittadini usano di più le biblioteche.

A1. Quanti utenti appartengono a ciascuna categoria? Ordina il risultato dalla categoria più numerosa alla meno numerosa

A2. Aggiungi a utenti una colonna classe_eta con le classi meno di 18, 18-29, 30-49, 50-64, 65 e oltre, trasformata in un ordered factor. Quanti utenti ci sono in ciascuna classe? Cosa accade agli utenti di cui non è noto l’anno di nascita?

A3. Calcola il numero di prestiti di ciascun utente e aggiungilo alla tabella utenti, in modo che anche gli utenti senza prestiti compaiano con il valore 0. Quanti sono gli utenti che nel 2025 non hanno preso in prestito nessun libro?

TipSuggerimento

Partite da prestiti_completo e usate group_by e summarise per ottenere una tabella con una riga per utente; poi unitela a utenti con il join adatto. Quale valore assumono gli utenti senza prestiti dopo il join? Come potete trasformarlo in 0?

A4. Per ciascuna categoria calcola il numero di utenti, il numero medio di prestiti per utente e la quota di utenti che hanno preso in prestito almeno un libro. Quale categoria legge di più? Ripeti il calcolo per classe di età

A5. ★ Calcola il numero medio di prestiti per utente in due modi: su tutti gli utenti e solo sugli utenti con almeno un prestito. Quale dei due valori è corretto per rispondere alla domanda “quanti libri prende in prestito in media un iscritto”?

Per la discussione: quale tipo di join avete usato al punto A3, e cosa sarebbe cambiato nei risultati del punto A4 usando un inner_join?

Missione B: Le biblioteche

Il Comune deve decidere come distribuire tra le quattro biblioteche le risorse del prossimo anno e vuole confrontarne l’attività.

B1. Per ciascuna biblioteca calcola il numero di prestiti e il numero di utenti distinti che vi hanno preso libri in prestito. Quale tabella è più corretto usare, prestiti o prestiti_completo? Perché?

B2. Aggiungi al risultato del punto B1 il nome e le ore di apertura settimanali di ciascuna biblioteca e calcola il numero di prestiti per ora di apertura. Ordina le biblioteche dalla più “produttiva” alla meno produttiva, con la colonna del nome subito dopo quella del codice

B3. Gli utenti prendono libri in prestito soprattutto nella biblioteca in cui si sono iscritti? Per ciascuna biblioteca calcola la quota di prestiti effettuati da utenti iscritti in quella stessa biblioteca

TipSuggerimento

Il confronto biblioteca == biblioteca_di_iscrizione restituisce un valore logico per ogni prestito: cosa rappresenta la sua media?

B4. Calcola il numero di prestiti per mese. In quale mese i prestiti sono stati meno numerosi, e perché?

TipSuggerimento

La funzione month del package lubridate (caricato con il tidyverse) estrae il mese da una data.

B5. ★ Ripeti il conteggio del punto B4 separatamente per ciascuna biblioteca. Ci sono biblioteche con un andamento diverso dalle altre?

Per la discussione: quale biblioteca è la più attiva? La risposta cambia a seconda dell’indicatore usato (prestiti, utenti, prestiti per ora di apertura)?

Missione C: Restituzioni e ritardi

Il servizio prestiti vuole capire quanto spesso i libri vengono restituiti in ritardo.

C1. Aggiungi a prestiti_completo una colonna durata con il numero di giorni trascorsi tra il prestito e la restituzione. Calcola la durata media e mediana dei prestiti, separatamente per i prestiti con e senza proroga

TipSuggerimento

La differenza tra due date si calcola con la funzione difftime; per ottenere un numero di giorni usate as.numeric(difftime(data_fine, data_inizio, units = "days")).

C2. Quanti prestiti non risultano ancora restituiti al 31 dicembre 2025? Come si distribuiscono tra le biblioteche?

C3. Classifica ogni prestito in una delle seguenti situazioni, in una nuova colonna stato: restituito in tempo, restituito in ritardo, non restituito, in ritardo (il termine è già scaduto al 31 dicembre 2025), in corso (il termine non è ancora scaduto). Quanti prestiti ricadono in ciascuna situazione?

TipSuggerimento

Create prima una colonna con il limite di durata del prestito (30 o 60 giorni) usando if_else. Per i prestiti non restituiti, i giorni trascorsi si calcolano rispetto alla data as.POSIXct("2025-12-31", tz = "UTC"). Ricordate che case_when usa la prima condizione vera.

C4. Calcola per ciascuna categoria di utenti la quota di prestiti in ritardo (restituiti in ritardo o non restituiti con termine scaduto). Quale categoria è la meno puntuale?

C5. ★ Esegui mean(prestiti_completo$durata) e commenta il risultato. Come va corretto il calcolo? Quali prestiti vengono esclusi dalla media corretta?

Per la discussione: la durata media calcolata sui soli prestiti restituiti rischia di sottostimare la durata reale dei prestiti. Perché?

Missione D: Cosa si legge?

La commissione acquisti vuole orientare l’acquisto dei nuovi libri.

D1. Quali sono i 10 libri più prestati nel 2025? Riporta titolo, autore e numero di prestiti. Cosa rappresenta l’eventuale riga senza titolo, e come potete escluderla?

D2. Per ciascuna categoria di utenti calcola il numero di prestiti di ciascun genere letterario e la quota di ciascun genere sul totale dei prestiti della categoria. Quali sono le differenze più evidenti tra le categorie?

TipSuggerimento

Dopo group_by(categoria, genere_letterario) e summarise, la tabella resta raggruppata per categoria (R lo segnala con un messaggio): una successiva mutate(quota = n / sum(n)) calcola quindi la somma all’interno di ciascuna categoria.

D3. Quali libri del catalogo non sono mai stati presi in prestito nel 2025?

D4. Aggiungi al catalogo una colonna epoca che classifichi gli anni di pubblicazione in prima del 1900, 1900-1945, 1946-1999, dal 2000. Per ciascuna epoca calcola il numero di titoli presenti in catalogo e il numero di prestiti. I libri più recenti sono più richiesti? Per rispondere, rapportate i prestiti al numero di titoli

D5. ★ Chi sono gli autori più prestati? Il risultato è diverso dalla classifica dei libri del punto D1?

Per la discussione: per confrontare la popolarità delle epoche, perché non basta confrontare il numero di prestiti?

Missione E: Qualità dei dati e attività culturali

Il responsabile del sistema informativo vuole verificare la qualità dei dati; l’ufficio eventi vuole sapere chi partecipa alle attività culturali.

E1. Quali prestiti del registro riguardano utenti che non compaiono nell’anagrafe? Quali riguardano libri che non compaiono nel catalogo? Osservando i codici, formulate un’ipotesi sull’origine di questi casi

E2. Quanti iscritti non hanno preso in prestito nessun libro nel 2025? Come si distribuiscono per categoria?

E3. Usando le operazioni su insiemi, rispondi alle seguenti domande:

  • quanti utenti partecipano a entrambe le attività?
  • quanti partecipano ad almeno una attività?
  • quanti partecipano a una sola attività?
  • quanti partecipano solo al gruppo di lettura?

E4. Descrivi i partecipanti alle due attività: come si distribuiscono per categoria gli iscritti al gruppo di lettura e quelli al laboratorio di scrittura?

E5. ★ I partecipanti alle attività culturali prendono in prestito più libri degli altri utenti? Confronta il numero medio di prestiti per utente tra partecipanti e non partecipanti (attenzione agli utenti senza prestiti!)

Per la discussione: nella parte comune, quanti prestiti sono stati esclusi da prestiti_completo e perché? In quali missioni questa esclusione è corretta, e in quali invece potrebbe portare a risultati sbagliati?

La presentazione

Ogni gruppo ha a disposizione 5 minuti, mostrando lo script in RStudio. Organizzate la presentazione così:

  1. La domanda e la risposta: qual era la vostra missione e cosa avete scoperto? Partite dai risultati, non dal codice
  2. Il codice: mostrate e spiegate uno o due passaggi chiave (ad esempio un join o una sintesi per gruppi)
  3. Una difficoltà: un errore o un risultato inatteso che avete incontrato, e come lo avete risolto (o perché non ci siete riusciti)
  4. La domanda per la discussione: la vostra risposta, da discutere con la classe
Note

Non è necessario aver completato tutti i punti: un errore spiegato bene è utile alla discussione quanto un risultato corretto.