7  Utility functions

In questo capitolo imparerai a
  • conoscere e sapere utilizzare le principali funzioni di utilità di R;
  • sapere come importare un data set in R e esportare un data set in un file esterno;
  • usare i percorsi relativi rispetto alla radice del progetto con here::here().
Preparazione del Notebook
here::here("code", "_common.R") |> 
  source()

# Load packages
if (!requireNamespace("pacman")) install.packages("pacman")
pacman::p_load(tidyr)

7.1 Introduzione

In questo capitolo, esploreremo le principali funzioni di utilità in R per l’importazione di dati da file esterni e la raccolta di statistiche descrittive, fornendo una panoramica generale sui data frame.

7.2 Importare dati in R con rio::import()

Prima di analizzare i dati, è necessario importarli in R.

7.2.1 Il problema: Tanti Formati, un’Unica Soluzione

Nella ricerca psicologica i dati possono essere forniti in molti formati:

  • File Excel (.xlsx) da questionari compilati in laboratorio,
  • CSV (.csv) da piattaforme online come Qualtrics,
  • File SPSS (.sav) per confrontare studi precedenti,
  • Solo testo (.txt) da esperimenti comportamentali.

Invece di imparare funzioni diverse, una specifica per ciascun formato, il pacchetto rio offre un solo comando universale per le importazioni.

7.2.2 Come Funziona import()

# Carica il pacchetto (installalo prima con install.packages("rio"))
library(rio)

# Importa un file CSV da una cartella "dati" nel tuo progetto
risposte <- rio::import("dati/questionario.csv")

# Importa un foglio Excel con i tempi di reazione
tempi_reazione <- rio::import("dati/esperimento1.xlsx")

# Importa un file SPSS con dati demografici
dati_demografici <- rio::import("dati/partecipanti.sav")

Perché è utile:

  1. riconosce automaticamente il formato dal nome del file;
  2. traduce i dati in un formato R pronto per l’analisi (data.frame);
  3. conserva le etichette delle variabili (cruciale per questionari!).

7.2.3 Esportare Dati con rio::export()

Dopo aver pulito i dati, è possibile salvarli in qualsiasi formato usando rio::export():

rio::export(risposte, "dati/cleaned/dati_puliti.xlsx")
rio::export(tempi_reazione, "dati/cleaned/tempi_reazione.sav")

7.3 Utilizzare Percorsi Relativi con here::here()

Quando importiamo i dati da file esterni in R, succede spesso di commettere uno dei tre errori seguenti. Vediamo come eviarli.

  1. Percatori sbagliati

    # SBAGLIATO (il file non è nella cartella di lavoro)
    import("questionario.csv")  
    
    # CORRETTO: usa percorsi relativi o il pacchetto 'here'
    import("dati/raw/questionario.csv")  
  2. File aperti in altri programmi
    “Errore: non posso aprire il file” → Chiudi Excel/SPSS e riprova

  3. Codifica caratteri strani
    Se vedi � nei testi, specifica l’encoding:

    import("dati/testo.txt", encoding = "UTF-8")

7.3.1 Evitare Percorsi Assoluti

Come vedremo meglio nel Capitolo 14, il primo passo di un progetto di analisi dei dati è l’organizzazione dei file in cartelle con una struttura chiara:

tuo_progetto/
├── dati/
│   ├── raw/        # Dati originali
│   └── cleaned/    # Dati elaborati
├── script/
└── rapporti/

Tutti i file e le cartelle devono essere contenuti nella directory del progetto.

Il pacchetto here rende l’importazione dei dati più semplice, evitando problemi dovuti a percorsi assoluti che possono cambiare se si modifica la directory di lavoro o si sposta il progetto.

La funzione here() crea percorsi relativi a partire dalla radice del progetto (cioè dalla cartella che contiene il file .Rproj o da dove viene inizializzato il progetto RStudio).

Esempio di utilizzo combinato con rio::import():

library(rio)
library(here)

# Percorso robusto al file csv
dati <- import(here("data", "dati.csv"))

# Percorso robusto al file Excel
dati_excel <- import(here("data", "dati.xlsx"))

In questo modo, l’importazione diventa indipendente dalla cartella di lavoro attuale e il codice sarà più facilmente condivisibile e riproducibile.

Vantaggi:

  • Semplicità: rio::import() riconosce automaticamente il tipo di file.
  • Robustezza: here::here() garantisce che il percorso sia sempre corretto, indipendentemente da dove viene eseguito lo script.

Questa combinazione rende le analisi riproducibili e consente di collaborare facilmente con altri ricercatori o studenti.

7.4 Funzioni Principali e Loro Utilizzo

R offre una serie di funzioni per esplorare rapidamente i dati e comprenderne la struttura prima di passare a manipolazioni più avanzate.

Funzione Descrizione
summary() Restituisce statistiche descrittive di base per ogni colonna di un data frame. Per le colonne numeriche, calcola valori come il minimo, massimo, media, mediana, primo e terzo quartile, e il numero di valori mancanti (se presenti). Per le colonne non numeriche, restituisce il tipo di dati (carattere, logico) e il conteggio delle categorie. Esempio: summary(iris) restituisce una sintesi delle colonne del dataset iris.
str() e glimpse() Forniscono una rappresentazione sintetica delle informazioni di un data frame, come dimensione, nomi delle colonne, tipi di dati e valori iniziali. La funzione str() fa parte della configurazione base di R (pacchetto utils), mentre glimpse() è inclusa in dplyr (pacchetto tidyverse). Esempio: str(mtcars) o glimpse(mtcars).
head() e tail() Permettono di visualizzare rispettivamente le prime o ultime righe di un data frame. Utile per una rapida ispezione del contenuto. Si può specificare il numero di righe da mostrare (es. head(df, 10)), altrimenti il valore predefinito è sei righe. Esempio: head(iris) per vedere le prime righe del dataset iris.
View() e view() Visualizzano un data frame in una finestra grafica tipo foglio di calcolo all’interno di RStudio. La funzione View() è parte della configurazione base di R, mentre view() è un alias fornito da tibble (pacchetto tidyverse). Utile per piccoli data frame, ma poco pratico per dataset di grandi dimensioni. Esempio: View(iris) apre il dataset iris nel visualizzatore di RStudio.
unique() Restituisce i valori unici presenti in una colonna o in un vettore. Esempio: unique(iris$Species) restituisce le specie uniche nel dataset iris.
names() Restituisce i nomi delle colonne di un data frame. Esempio: names(mtcars) restituisce i nomi delle colonne del dataset mtcars.
class() Indica il tipo di dato di un oggetto in R, come numeric, character, logical, o data.frame. Esempio: class(iris) restituisce data.frame.
length() Restituisce il numero di elementi di un oggetto. Per i data frame, restituisce il numero di colonne. Esempio: length(iris) restituisce 5 (colonne).
nrow() e ncol() Restituiscono rispettivamente il numero di righe e colonne di un data frame. Esempio: nrow(iris) restituisce 150 (righe), mentre ncol(iris) restituisce 5 (colonne).

7.5 Illustrazione

Immagina di dover analizzare i dati del tuo esperimento sul sonno e la memoria, salvati nel file msleep.csv. La struttura del tuo progetto RStudio è organizzata così:

mio_esperimento/
├── mio_esperimento.Rproj
├── data/
│   └── msleep.csv
├── script/
│   └── analisi.R
└── output/

La prima cosa da fare è caricare i pacchetti necessari:

library(rio)    # Per importare i dati
library(here)   # Per gestire i percorsi in modo affidabile

A questo punto possiamo importare i dati:

msleep <- rio::import(
  here::here(  # Costruisce il percorso automaticamente
    "data",    # Cartella dei dati
    "msleep.csv"  # Nome del file
  )
)

Controlli post-importazione (fondamentali!)

head(msleep)
#>                         name      genus  vore        order conservation
#> 1                    Cheetah   Acinonyx carni    Carnivora           lc
#> 2                 Owl monkey      Aotus  omni     Primates             
#> 3            Mountain beaver Aplodontia herbi     Rodentia           nt
#> 4 Greater short-tailed shrew    Blarina  omni Soricomorpha           lc
#> 5                        Cow        Bos herbi Artiodactyla domesticated
#> 6           Three-toed sloth   Bradypus herbi       Pilosa             
#>   sleep_total sleep_rem sleep_cycle awake brainwt  bodywt
#> 1        12.1        NA          NA  11.9      NA  50.000
#> 2        17.0       1.8          NA   7.0 0.01550   0.480
#> 3        14.4       2.4          NA   9.6      NA   1.350
#> 4        14.9       2.3      0.1333   9.1 0.00029   0.019
#> 5         4.0       0.7      0.6667  20.0 0.42300 600.000
#> 6        14.4       2.2      0.7667   9.6      NA   3.850
str(msleep)
#> 'data.frame':    83 obs. of  11 variables:
#>  $ name        : chr  "Cheetah" "Owl monkey" "Mountain beaver" "Greater short-tailed shrew" ...
#>  $ genus       : chr  "Acinonyx" "Aotus" "Aplodontia" "Blarina" ...
#>  $ vore        : chr  "carni" "omni" "herbi" "omni" ...
#>  $ order       : chr  "Carnivora" "Primates" "Rodentia" "Soricomorpha" ...
#>  $ conservation: chr  "lc" "" "nt" "lc" ...
#>  $ sleep_total : num  12.1 17 14.4 14.9 4 14.4 8.7 7 10.1 3 ...
#>  $ sleep_rem   : num  NA 1.8 2.4 2.3 0.7 2.2 1.4 NA 2.9 NA ...
#>  $ sleep_cycle : num  NA NA NA 0.133 0.667 ...
#>  $ awake       : num  11.9 7 9.6 9.1 20 9.6 15.3 17 13.9 21 ...
#>  $ brainwt     : num  NA 0.0155 NA 0.00029 0.423 NA NA NA 0.07 0.0982 ...
#>  $ bodywt      : num  50 0.48 1.35 0.019 600 ...
glimpse(msleep)
#> Rows: 83
#> Columns: 11
#> $ name         <chr> "Cheetah", "Owl monkey", "Mountain beaver", "Greater …
#> $ genus        <chr> "Acinonyx", "Aotus", "Aplodontia", "Blarina", "Bos", …
#> $ vore         <chr> "carni", "omni", "herbi", "omni", "herbi", "herbi", "…
#> $ order        <chr> "Carnivora", "Primates", "Rodentia", "Soricomorpha", …
#> $ conservation <chr> "lc", "", "nt", "lc", "domesticated", "", "vu", "", "…
#> $ sleep_total  <dbl> 12.1, 17.0, 14.4, 14.9, 4.0, 14.4, 8.7, 7.0, 10.1, 3.…
#> $ sleep_rem    <dbl> NA, 1.8, 2.4, 2.3, 0.7, 2.2, 1.4, NA, 2.9, NA, 0.6, 0…
#> $ sleep_cycle  <dbl> NA, NA, NA, 0.1333, 0.6667, 0.7667, 0.3833, NA, 0.333…
#> $ awake        <dbl> 11.9, 7.0, 9.6, 9.1, 20.0, 9.6, 15.3, 17.0, 13.9, 21.…
#> $ brainwt      <dbl> NA, 0.01550, NA, 0.00029, 0.42300, NA, NA, NA, 0.0700…
#> $ bodywt       <dbl> 50.000, 0.480, 1.350, 0.019, 600.000, 3.850, 20.490, …
names(msleep)
#>  [1] "name"         "genus"        "vore"         "order"       
#>  [5] "conservation" "sleep_total"  "sleep_rem"    "sleep_cycle" 
#>  [9] "awake"        "brainwt"      "bodywt"
dim(msleep)
#> [1] 83 11

Errori comuni e soluzioni.

  1. “File not found”:

    • Verifica che:
      • il file sia realmente in data/;
      • il nome del file sia esatto (attenzione a .csv vs .CSV);
      • non ci siano spazi nel nome del file.
  2. Pacchetti non installati:

    # Esegui una volta
    install.packages("rio")
    install.packages("here")
  3. Progetto non aperto:

    • Assicurati di aver aperto il file .Rproj prima di iniziare.

Esaminiamo le modalità della variabile qualitativa vore:

unique(msleep$vore)
#> [1] "carni"   "omni"    "herbi"   ""        "insecti"

Se vogliamo la numerosità di ciascuna categoria, possiamo usare table():

table(msleep$vore)
#> 
#>           carni   herbi insecti    omni 
#>       7      19      32       5      20

Si noti che table() esclude i dati mancanti.

Stampiamo i nomi delle colonne del data frame:

names(msleep)
#>  [1] "name"         "genus"        "vore"         "order"       
#>  [5] "conservation" "sleep_total"  "sleep_rem"    "sleep_cycle" 
#>  [9] "awake"        "brainwt"      "bodywt"

Esaminiamo il tipo di variabile della colonna vore:

class(msleep$vore)
#> [1] "character"

Le dimensioni del data frame sono date da:

dim(msleep)
#> [1] 83 11

laddove il primo valore è il numero di righe e il secondo valore è il numero di colonne.

Il numero di elementi di un vettore è dato da:

length(msleep$vore)
#> [1] 83

In alternativa, possiamo usare nrow()

nrow(msleep)
#> [1] 83

per il numero di righe e ncol()

ncol(msleep)
#> [1] 11

per il numero di colonne. In maniera equivalente:

dim(msleep)[2]
#> [1] 11

7.6 Esercizi

In questo esercizio, utilizzerai R per esplorare i dati raccolti con il questionario Satisfaction With Life Scale (SWLS) dagli studenti del tuo gruppo TPV. L’obiettivo è familiarizzare con le funzioni di base di R per caricare, visualizzare e manipolare i dati.

Parte 1: Operazioni Manuali

  1. Creazione e gestione degli oggetti in R
    • Scrivi su carta i comandi R che creerebbero un oggetto chiamato swls_scores contenente i punteggi di 10 studenti.
    • Quali sono le regole per assegnare un nome a un oggetto in R?
  2. Visualizzazione dei dati
    • Scrivi il comando R per visualizzare il contenuto dell’oggetto swls_scores.
    • Come puoi visualizzare solo i primi 5 valori del vettore?
  3. Esplorazione della struttura dei dati
    • Scrivi i comandi R per verificare il tipo di dati contenuti in swls_scores.
    • Come puoi verificare quanti elementi contiene?

Parte 2: Esecuzione in R

  1. Creazione del dataset in R
    • Inserisci i dati in un oggetto chiamato swls_scores in R.
  2. Verifica della struttura dei dati
  3. Visualizzazione dei dati
    • Usa head() e tail() per esplorare i dati.
    • Qual è la differenza tra le due funzioni?
  4. Identificazione dei valori unici
    • Usa unique(swls_scores) per individuare i punteggi distinti.
  5. Creazione di una tabella con i dati
    • Trasforma swls_scores in un data frame con una colonna "Punteggio" e una colonna "Studente" (numerata da 1 a 10).
  6. Esportazione dei dati
    • Salva il data frame in un file CSV chiamato "swls_data.csv" usando write.csv().

Consegna

  • Scrivi le risposte della Parte 1 su carta.
  • Scrivi il codice e i risultati della Parte 2 in un file .R e invialo come consegna.

Parte 1: Operazioni Manuali

  1. Creazione e gestione degli oggetti in R
    • Consideriamo dei valori di risposta arbitrari. Il comando per creare l’oggetto swls_scores è:

      swls_scores <- c(20, 16, 23, 25, 11, 7, 20, 25, 15, 27)
    • Regole per assegnare un nome a un oggetto in R:

      • Non può iniziare con un numero.
      • Non può contenere spazi o caratteri speciali (tranne _ e .).
      • Non deve avere lo stesso nome di funzioni già esistenti.
  2. Visualizzazione dei dati
    • Per visualizzare il contenuto:

      swls_scores
    • Per visualizzare solo i primi 5 valori:

      head(swls_scores, 5)
  3. Esplorazione della struttura dei dati
    • Per verificare il tipo di dati:

      class(swls_scores)
    • Per verificare il numero di elementi:

      length(swls_scores)

Parte 2: Esecuzione in R

  1. Creazione del dataset in R

    swls_scores <- c(20, 16, 23, 25, 11, 7, 20, 25, 15, 27)
  2. Verifica della struttura dei dati

    str(swls_scores)
    class(swls_scores)
    length(swls_scores)
    • str() mostra che swls_scores è un vettore numerico.
    • class() conferma che è di tipo "numeric".
    • length() indica che il vettore ha 10 elementi.
  3. Visualizzazione dei dati

    head(swls_scores)
    tail(swls_scores)
  4. Identificazione dei valori unici

    unique(swls_scores)
    • Restituisce: 7, 11, 15, 16, 20, 23, 25, 27.
  5. Creazione di una tabella con i dati

    df_swls <- data.frame(Studente = 1:10, Punteggio = swls_scores)
    df_swls
  6. Esportazione dei dati

    write.csv(df_swls, "swls_data.csv", row.names=FALSE)

Conclusione

Questi esercizi hanno introdotto i comandi di base per creare, visualizzare e manipolare dati in R.

sessionInfo()
#> R version 4.4.2 (2024-10-31)
#> Platform: aarch64-apple-darwin20
#> Running under: macOS Sequoia 15.3.1
#> 
#> Matrix products: default
#> BLAS:   /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRblas.0.dylib 
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.0
#> 
#> locale:
#> [1] C/UTF-8/C/C/C/C
#> 
#> time zone: Europe/Rome
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#>  [1] thematic_0.1.6   MetBrewer_0.2.0  ggokabeito_0.1.0 see_0.10.0      
#>  [5] gridExtra_2.3    patchwork_1.3.0  bayesplot_1.11.1 psych_2.4.12    
#>  [9] scales_1.3.0     markdown_1.13    knitr_1.49       lubridate_1.9.4 
#> [13] forcats_1.0.0    stringr_1.5.1    dplyr_1.1.4      purrr_1.0.4     
#> [17] readr_2.1.5      tidyr_1.3.1      tibble_3.2.1     ggplot2_3.5.1   
#> [21] tidyverse_2.0.0  rio_1.2.3        here_1.0.1      
#> 
#> loaded via a namespace (and not attached):
#>  [1] generics_0.1.3    stringi_1.8.4     lattice_0.22-6    hms_1.1.3        
#>  [5] digest_0.6.37     magrittr_2.0.3    evaluate_1.0.3    grid_4.4.2       
#>  [9] timechange_0.3.0  fastmap_1.2.0     R.oo_1.27.0       rprojroot_2.0.4  
#> [13] jsonlite_1.9.1    R.utils_2.13.0    mnormt_2.1.1      cli_3.6.4        
#> [17] rlang_1.1.5       R.methodsS3_1.8.2 munsell_0.5.1     withr_3.0.2      
#> [21] tools_4.4.2       parallel_4.4.2    tzdb_0.4.0        colorspace_2.1-1 
#> [25] pacman_0.5.1      vctrs_0.6.5       R6_2.6.1          lifecycle_1.0.4  
#> [29] htmlwidgets_1.6.4 pkgconfig_2.0.3   pillar_1.10.1     gtable_0.3.6     
#> [33] data.table_1.17.0 glue_1.8.0        xfun_0.51         tidyselect_1.2.1 
#> [37] rstudioapi_0.17.1 farver_2.1.2      htmltools_0.5.8.1 nlme_3.1-167     
#> [41] rmarkdown_2.29    compiler_4.4.2

Bibliografia

Irizarry, R. A. (2024). Introduction to Data Science: Data Wrangling and Visualization with R. CRC Press.
Wickham, H., Çetinkaya-Rundel, M., & Grolemund, G. (2023). R for data science. " O’Reilly Media, Inc.".