4  ✏ Esercizi

source("../../code/_common.R")
library("rio")
library("psych")

4.1 Scaling Psicologico

Lo scaling psicologico si propone di affrontare il problema della misurazione di fenomeni soggettivi e latenti, quali percezioni, giudizi e preferenze, che non sono direttamente osservabili. L’obiettivo è trasformare dati qualitativi o discreti (come ranking o scelte) in stime quantitative che rappresentino in modo coerente la “distanza” o la differenza tra stimoli lungo un continuum psicologico. Storicamente, approcci come quello di Fechner – basato sull’accumulo di unità di percezione (JND) – e il modello Thurstoniano – che assume distribuzioni normali per le utilità latenti – hanno fornito strumenti fondamentali per tradurre il “misurare l’immisurabile” in misurazioni numeriche. Queste metodologie, pur partendo da presupposti differenti, condividono l’obiettivo di rendere comparabili e analizzabili fenomeni psicologici complessi, permettendo così una valutazione più precisa dei processi decisionali e delle percezioni individuali.

4.2 Scaling Fechneriano

Un esempio di scaling psicologico riguarda lo scaling fechneriano. Faccio qui riferimento ad uno studio condotto un po’ di tempo fa nell’ambito delle Vision Sciences.

Nello studio di Domini & Caudek (2009), abbiamo utilizzato il modello Intrinsic Constraints per correlare la profondità visiva percepita di un oggetto tridimensionale con i principi teorici dello scaling sensoriale Fechneriano. Quest’ultimo, basato sulle teorie psicofisiche di Fechner, prevede la costruzione di una scala psicofisica per attributi sensoriali mediante l’integrazione cumulativa di incrementi psicometrici, in particolare delle Just Noticeable Differences (JNDs). L’obiettivo della ricerca era progettare stimoli visivi caratterizzati da diversi indizi di profondità (stereopsi, parallasse di movimento, ecc.) in modo da indurre una percezione soggettiva equivalente della profondità 3D. Secondo questa logica, oggetti definiti da cue visivi distinti dovrebbero risultare percettivamente equiparabili in termini di profondità qualora fossero associati a un numero identico di JNDs. In altre parole, l’uniformità percettiva emerge quando gli stimoli, pur differendo negli indizi di profondità, raggiungono la stessa soglia di discriminabilità psicofisica.

4.3 Il Modello Thurstoniano

Il modello Thurstoniano fornisce un quadro statistico per analizzare e interpretare preferenze o ranking di oggetti (o stimoli) da parte di singoli individui. L’idea di base è che, dietro i ranking osservati, esista una scala latente continua, non direttamente misurabile, dove ogni individuo assegna un punteggio personale a ciascun oggetto. Tali punteggi individuali, sebbene soggettivi, possono essere descritti complessivamente su una dimensione unica, grazie a ipotesi specifiche sulle distribuzioni di questi punteggi.

Più in dettaglio, il modello ipotizza che:

  • Le utilità (o punteggi) latenti siano distribuite normalmente. Ogni oggetto possiede una distribuzione gaussiana dei propri punteggi latenti nella popolazione.
  • Le distribuzioni differiscano nelle medie, ma abbiano la stessa varianza. Nel Caso V di Thurstone, tutte le distribuzioni hanno una varianza comune, mentre le medie possono variare da un oggetto all’altro (alcuni oggetti sono mediamente più apprezzati di altri).

Sulla base di questi presupposti, si procede così:

  • Si calcola, per ciascuna coppia di oggetti, la proporzione di individui che preferisce un oggetto all’altro.
  • Tali proporzioni vengono convertite in z-score (percentili della distribuzione normale cumulativa) per stimare quanto un oggetto supera un altro in termini di deviazioni standard.
  • Sommando o mediando opportunamente questi z-score, si ottiene una stima dell’utilità media (ovvero la media della distribuzione normale latente) di ogni oggetto. Di solito, per identificare il modello, si fissa a zero la media di un oggetto (ad esempio, quello meno desiderato).

Questa procedura consente di trasformare i dati di ranking discreti in stime numeriche di utilità psicologica, evidenziando le differenze relative di importanza fra gli oggetti analizzati.

4.3.1 Tutorial

Nel seguente esercizio vedremo come eseguire uno scaling thurstoniano su dati di preferenze (o scelte) e ottenere delle stime delle utilità psicologiche di una serie di oggetti o caratteristiche confrontate fra loro. In altre parole, date le classifiche (rank) osservate, vogliamo inferire quali possano essere le distribuzioni di “valore psicologico” che hanno generato tali preferenze. Per stimare le utilità non osservate a partire dalle preferenze osservate, si ipotizza che le utilità siano distribuite normalmente con la stessa varianza (ipotesi del “Caso V” di Thurstone).

4.3.1.1 Studio delle preferenze per alcune caratteristiche lavorative

I dati di questo esempio provengono (in forma semplificata) da uno studio sulla motivazione al lavoro, condotto su \(N=1100\) partecipanti. A ogni partecipante è stato chiesto di ordinare in base all’importanza nove possibili caratteristiche di un lavoro ideale (assegnando il rank 1 alla più importante e il rank 9 alla meno importante). Le nove caratteristiche, qui elencate con i nomi delle colonne corrispondenti, sono:

  1. Ambiente di Sostegno (Support)
  2. Lavoro Stimolante (Challenge)
  3. Prospettive di Carriera (Career)
  4. Integrità Etica (Ethics)
  5. Autonomia e Impatto Personale (Autonomy)
  6. Opportunità di Crescita (Development)
  7. Interazione Sociale (Interaction)
  8. Competizione (Competition)
  9. Ambiente e Sicurezza (Safety)

Di seguito, illustriamo passo dopo passo l’analisi con il pacchetto psych di R.

4.3.1.2 Passo 1. Lettura e ispezione dei dati

Il file di dati (ad esempio, JobFeatures.txt) contiene le classifiche di 1100 partecipanti, ciascuno con i ranghi per le 9 caratteristiche. Per leggere il file in RStudio si può usare la funzione read.delim():

JobFeatures <- rio::import("../../data/JobFeatures.txt")
glimpse(JobFeatures)
#> Rows: 1,079
#> Columns: 9
#> $ Support     <int> 8, 7, 5, 7, 1, 6, 5, 1, 1, 7, 6, 8, 5, 9, 8, 1, 6, 7, …
#> $ Challenge   <int> 3, 5, 8, 6, 4, 1, 4, 9, 3, 4, 2, 1, 4, 8, 6, 7, 4, 4, …
#> $ Career      <int> 4, 1, 1, 8, 8, 3, 7, 2, 7, 6, 3, 4, 6, 1, 3, 5, 8, 3, …
#> $ Ethics      <int> 5, 6, 9, 9, 3, 7, 2, 8, 4, 1, 9, 3, 7, 5, 9, 6, 7, 5, …
#> $ Autonomy    <int> 2, 2, 6, 3, 9, 8, 3, 7, 9, 8, 4, 6, 3, 7, 5, 2, 3, 8, …
#> $ Development <int> 6, 8, 2, 4, 2, 5, 6, 5, 2, 5, 1, 2, 2, 6, 1, 3, 1, 2, …
#> $ Interaction <int> 1, 3, 3, 2, 6, 2, 1, 4, 6, 9, 5, 5, 1, 4, 2, 8, 2, 6, …
#> $ Competition <int> 7, 9, 4, 5, 7, 4, 9, 6, 8, 3, 7, 7, 9, 2, 7, 9, 9, 1, …
#> $ Safety      <int> 9, 4, 7, 1, 5, 9, 8, 3, 5, 2, 8, 9, 8, 3, 4, 4, 5, 9, …

Possiamo controllare i nomi delle variabili con:

names(JobFeatures)
#> [1] "Support"     "Challenge"   "Career"      "Ethics"      "Autonomy"   
#> [6] "Development" "Interaction" "Competition" "Safety"

La funzione head(JobFeatures) mostra le prime righe del data frame:

head(JobFeatures)
#>   Support Challenge Career Ethics Autonomy Development Interaction
#> 1       8         3      4      5        2           6           1
#> 2       7         5      1      6        2           8           3
#> 3       5         8      1      9        6           2           3
#> 4       7         6      8      9        3           4           2
#> 5       1         4      8      3        9           2           6
#> 6       6         1      3      7        8           5           2
#>   Competition Safety
#> 1           7      9
#> 2           9      4
#> 3           4      7
#> 4           5      1
#> 5           7      5
#> 6           4      9

4.3.1.3 Passo 2. Esecuzione dello scaling thurstoniano

Per poter eseguire l’analisi, caricando il pacchetto psych. La funzione che ci interessa è thurstone(). Se cerchiamo informazioni:

help("thurstone")

scopriamo che la funzione ha la forma generale:

thurstone(x, ranks = FALSE, digits = 2)
  • x: il set di dati su cui eseguire lo scaling.
  • ranks: se TRUE, i dati forniti sono ranghi raw; se FALSE, ci si aspetta una matrice di proporzioni di scelta (di default è FALSE).
  • digits: numero di cifre decimali per l’indice di bontà di adattamento (default 2).

Dal momento che abbiamo dati grezzi di ranking, impostiamo ranks = TRUE. Il comando:

thurstone(JobFeatures, ranks = TRUE)
#> Thurstonian scale (case 5) scale values 
#> Call: thurstone(x = JobFeatures, ranks = TRUE)
#> [1] 0.97 0.93 0.91 0.92 0.60 1.04 0.63 0.00 0.23
#> 
#>  Goodness of fit of model   1

restituirà in Console un output simile al seguente:

Thurstonian scale (case 5) scale values 
Call: thurstone(x = JobFeatures, ranks = TRUE)
[1] 0.97 0.93 0.91 0.92 0.60 1.04 0.63 0.00 0.23

Goodness of fit of model   1
  • I valori dopo la riga Call: sono le medie stimate delle utilità psicologiche.
  • Sono ordinate nello stesso modo in cui le caratteristiche compaiono nel data frame.
  • Una di queste medie è fissata a 0 (tipicamente, la caratteristica meno preferita viene posta a 0 per identificare il modello).

4.3.1.4 Passo 3. Calcolo delle proporzioni di preferenza a coppie

Se assegniamo i risultati della funzione a un oggetto, ad esempio:

scaling <- thurstone(JobFeatures, ranks = TRUE)

non vediamo nulla stampato in Console, ma l’analisi è stata eseguita. Ora ls(scaling) mostra i componenti:

ls(scaling)
#> [1] "Call"     "GF"       "choice"   "residual" "scale"
  • scaling$scale contiene i valori medi di utilità, già visti.
  • scaling$choice contiene la matrice delle proporzioni di scelta (9×9). Ogni cella \((i, j)\) indica la proporzione di partecipanti che preferiscono la caratteristica j rispetto alla caratteristica i.
scaling$choice |> 
  round(2)
#>       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#>  [1,] 0.50 0.47 0.47 0.47 0.36 0.51 0.36 0.20 0.23
#>  [2,] 0.53 0.50 0.47 0.49 0.38 0.53 0.36 0.17 0.28
#>  [3,] 0.53 0.53 0.50 0.50 0.38 0.52 0.39 0.19 0.26
#>  [4,] 0.53 0.51 0.50 0.50 0.36 0.52 0.38 0.19 0.26
#>  [5,] 0.64 0.62 0.62 0.64 0.50 0.67 0.51 0.29 0.34
#>  [6,] 0.49 0.47 0.48 0.48 0.33 0.50 0.29 0.15 0.20
#>  [7,] 0.64 0.64 0.61 0.62 0.49 0.71 0.50 0.22 0.30
#>  [8,] 0.80 0.83 0.81 0.81 0.71 0.85 0.78 0.50 0.61
#>  [9,] 0.77 0.72 0.74 0.74 0.66 0.80 0.70 0.39 0.50

Se, per esempio, la cella \((8,6)\) vale 0.853, significa che l’8ª caratteristica è preferita alla dall’85.3% del campione (o dei ranghi aggregati).

4.3.1.5 Passo 4. Valutazione dell’adattamento del modello

Possiamo esaminare gli scarti (residui) confrontando le proporzioni osservate con quelle predette dal modello:

scaling$residual |> 
  round(3)
#>         [,1]   [,2]   [,3]   [,4]   [,5]   [,6]   [,7]   [,8]   [,9]
#>  [1,]  0.000  0.013  0.002  0.008 -0.006  0.020  0.008 -0.037  0.007
#>  [2,] -0.013  0.000  0.022  0.000 -0.006  0.011  0.019  0.010 -0.040
#>  [3,] -0.002 -0.022  0.000  0.007  0.005  0.028  0.001 -0.005 -0.009
#>  [4,] -0.008  0.000 -0.007  0.000  0.011  0.028  0.007 -0.012 -0.011
#>  [5,]  0.006  0.006 -0.005 -0.011  0.000 -0.005  0.007 -0.013  0.017
#>  [6,] -0.020 -0.011 -0.028 -0.028  0.005  0.000  0.049  0.003  0.016
#>  [7,] -0.008 -0.019 -0.001 -0.007 -0.007 -0.049  0.000  0.042  0.041
#>  [8,]  0.037 -0.010  0.005  0.012  0.013 -0.003 -0.042  0.000 -0.021
#>  [9,] -0.007  0.040  0.009  0.011 -0.017 -0.016 -0.041  0.021  0.000
  • Residui vicini a zero indicano che il modello di Thurstone (utilità normali) riproduce bene i dati osservati.

Infine, con:

scaling$GF
#> [1] 0.999

otteniamo un indice di bontà di adattamento prossimo a 1, segno che il modello fornisce una buona descrizione dei dati (più il valore è vicino a 1, meglio il modello si adatta).

In sintesi

  • Thurstonian scaling (Caso V): presuppone che le utilità latenti degli oggetti abbiano distribuzioni normali con varianza uguale.
  • Procedura:
    1. Lettura dei ranking e ispezione dei dati.
    2. Calcolo dello scaling con la funzione thurstone().
    3. Interpretazione delle scale (medie di utilità).
    4. Analisi delle proporzioni di preferenza a coppie.
    5. Verifica dei residui e dell’indice Goodness of Fit (GF).
  • Conclusione interpretativa:
    • Un oggetto con media più alta risulta, in media, più desiderato.
    • L’oggetto con media zero (fissata) è quello meno preferito o funge da riferimento.
    • Residui bassi e un GF vicino a 1 indicano che il modello spiega bene i dati.

4.4 Riflessioni Conclusive

Lo scaling thurstoniano (Caso V) trasforma i ranking discreti in stime continue di utilità, consentendo di evidenziare differenze relative fra le caratteristiche analizzate e di quantificare la “distanza” tra gli oggetti su una scala latente comune. Quando il numero di oggetti è elevato, si procede al calcolo di tutte le proporzioni di preferenza pairwise, applicando la stessa logica, eventualmente integrata con metodi di stima più sofisticati.

Questa metodologia, introdotta da Louis Leon Thurstone negli anni Venti, è una delle prime forme di scaling psicologico. Con il termine scaling si indica il processo di collocare stimoli (o concetti) su un continuum, in base al grado in cui essi possiedono una certa proprietà psicologica. Nel Caso V, si assume che tutte le distribuzioni di punteggi latenti abbiano la stessa varianza, ipotesi che semplifica il modello ma può risultare limitante nella pratica, poiché la coerenza dei giudizi e la natura degli stimoli possono variare notevolmente.

Prima di Thurstone, Gustav Theodor Fechner (1801-1887) pose le basi della psicofisica proponendo l’idea che la relazione fra l’intensità fisica di uno stimolo e la sua percezione psicologica seguisse una legge logaritmica. Al centro del metodo di Fechner vi è il concetto di JND (Just Noticeable Difference, o “differenza appena percepibile”): la più piccola variazione dello stimolo che un individuo è in grado di distinguere da un riferimento. Accumulando queste unità di percezione – le JND – Fechner ipotizzò che si potesse costruire una scala psicologica che misurasse l’intensità soggettiva delle sensazioni in funzione dello stimolo fisico.

Dal punto di vista concettuale, lo scaling di Fechner precede e ispira quello di Thurstone in quanto entrambi i metodi assumono l’esistenza di variabili latenti alla base dei giudizi individuali. Nel caso di Fechner, l’obiettivo principale era correlare la misura fisica di uno stimolo (ad esempio, il peso o la luminosità) alla sensazione percepita dal soggetto, segmentando la scala fisica in unità psicologicamente equipollenti (le JND). Thurstone, invece, ha esteso questo paradigma al contesto dei giudizi di preferenza e classificazione, introducendo la nozione di distribuzioni normali per i punteggi latenti e di varianza costante tra gli oggetti.

4.4.1 Limiti e prospettive

Una criticità rilevante nello scaling thurstoniano è la mancanza di procedure consolidate per la falsificazione interna del modello: a differenza, ad esempio, di quanto avviene nello scaling di Mokken, dove si può testare la monotonicità delle risposte. Se i dati violano l’assunzione di varianza costante o di un unico continuum psicologico condiviso, il modello di Thurstone non fornisce criteri immediati per identificare o risolvere tali problemi.

Nel panorama odierno, molti studiosi preferiscono approcci basati sulla Teoria della Risposta all’Item (IRT), che offre una rappresentazione più flessibile: la probabilità di risposta a un item dipende sia dalle sue caratteristiche, sia dal livello latente dell’individuo. L’IRT permette di testare in modo più rigoroso le assunzioni del modello (p. es. la monotonicità e l’indipendenza locale) e di stimare con maggiore precisione sia le proprietà degli item, sia i parametri delle persone.

In conclusione, lo scaling thurstoniano è stato un passo fondamentale nello sviluppo degli strumenti di misurazione in psicologia, ereditando la tensione di Fechner nel voler “misurare l’immisurabile”. Nonostante la sua eleganza e semplicità introduttiva, diverse questioni tecniche (come l’ipotesi di varianza costante) e l’assenza di metodi di falsificazione robusti hanno portato, nel tempo, allo sviluppo di approcci più potenti e flessibili, tra cui la Teoria della Risposta all’Item. Rimane comunque un importante riferimento storico e didattico per comprendere la logica dello scaling psicologico e il percorso che ha condotto agli strumenti sofisticati oggi disponibili.

4.5 Sesssion Info

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] rio_1.2.3         ggokabeito_0.1.0  see_0.10.0        MASS_7.3-65      
#>  [5] viridis_0.6.5     viridisLite_0.4.2 ggpubr_0.6.0      ggExtra_0.10.1   
#>  [9] gridExtra_2.3     patchwork_1.3.0   bayesplot_1.11.1  semTools_0.5-6   
#> [13] semPlot_1.1.6     lavaan_0.6-19     psych_2.4.12      scales_1.3.0     
#> [17] markdown_1.13     knitr_1.49        lubridate_1.9.4   forcats_1.0.0    
#> [21] stringr_1.5.1     dplyr_1.1.4       purrr_1.0.4       readr_2.1.5      
#> [25] tidyr_1.3.1       tibble_3.2.1      ggplot2_3.5.1     tidyverse_2.0.0  
#> [29] here_1.0.1       
#> 
#> loaded via a namespace (and not attached):
#>   [1] rstudioapi_0.17.1   jsonlite_1.9.1      magrittr_2.0.3     
#>   [4] TH.data_1.1-3       estimability_1.5.1  farver_2.1.2       
#>   [7] nloptr_2.1.1        rmarkdown_2.29      vctrs_0.6.5        
#>  [10] minqa_1.2.8         base64enc_0.1-3     rstatix_0.7.2      
#>  [13] htmltools_0.5.8.1   broom_1.0.7         Formula_1.2-5      
#>  [16] htmlwidgets_1.6.4   plyr_1.8.9          sandwich_3.1-1     
#>  [19] emmeans_1.10.7      zoo_1.8-13          igraph_2.1.4       
#>  [22] mime_0.12           lifecycle_1.0.4     pkgconfig_2.0.3    
#>  [25] Matrix_1.7-2        R6_2.6.1            fastmap_1.2.0      
#>  [28] rbibutils_2.3       shiny_1.10.0        digest_0.6.37      
#>  [31] OpenMx_2.21.13      fdrtool_1.2.18      colorspace_2.1-1   
#>  [34] rprojroot_2.0.4     Hmisc_5.2-2         timechange_0.3.0   
#>  [37] abind_1.4-8         compiler_4.4.2      withr_3.0.2        
#>  [40] glasso_1.11         htmlTable_2.4.3     backports_1.5.0    
#>  [43] carData_3.0-5       R.utils_2.13.0      ggsignif_0.6.4     
#>  [46] corpcor_1.6.10      gtools_3.9.5        tools_4.4.2        
#>  [49] pbivnorm_0.6.0      foreign_0.8-88      zip_2.3.2          
#>  [52] httpuv_1.6.15       nnet_7.3-20         R.oo_1.27.0        
#>  [55] glue_1.8.0          quadprog_1.5-8      nlme_3.1-167       
#>  [58] promises_1.3.2      lisrelToR_0.3       grid_4.4.2         
#>  [61] checkmate_2.3.2     cluster_2.1.8       reshape2_1.4.4     
#>  [64] generics_0.1.3      gtable_0.3.6        tzdb_0.4.0         
#>  [67] R.methodsS3_1.8.2   data.table_1.17.0   hms_1.1.3          
#>  [70] car_3.1-3           sem_3.1-16          pillar_1.10.1      
#>  [73] rockchalk_1.8.157   later_1.4.1         splines_4.4.2      
#>  [76] lattice_0.22-6      survival_3.8-3      kutils_1.73        
#>  [79] tidyselect_1.2.1    miniUI_0.1.1.1      pbapply_1.7-2      
#>  [82] reformulas_0.4.0    stats4_4.4.2        xfun_0.51          
#>  [85] qgraph_1.9.8        arm_1.14-4          stringi_1.8.4      
#>  [88] pacman_0.5.1        boot_1.3-31         evaluate_1.0.3     
#>  [91] codetools_0.2-20    mi_1.1              cli_3.6.4          
#>  [94] RcppParallel_5.1.10 rpart_4.1.24        xtable_1.8-4       
#>  [97] Rdpack_2.6.2        munsell_0.5.1       Rcpp_1.0.14        
#> [100] coda_0.19-4.1       png_0.1-8           XML_3.99-0.18      
#> [103] parallel_4.4.2      jpeg_0.1-10         lme4_1.1-36        
#> [106] mvtnorm_1.3-3       openxlsx_4.2.8      rlang_1.1.5        
#> [109] multcomp_1.4-28     mnormt_2.1.1