knitr::opts_chunk$set(
    echo=TRUE, warning=FALSE, message=FALSE,
    fig.width=12, fig.height=6, fig.align='center'
)

:rewind: Torna all'indice

library("testing")

Tabulazione di riferimenti normativi

Un test standardizzato include un sistema di tabelle normative che riportano la corrispondenza fra punteggi grezzi e standardizzati, permettendo così di convertire un punteggio grezzo in uno standardizzato. Una parte importante del processo di messa a punto di un test psicometrico riguarda proprio la costruzione di queste tabelle.

Nel costruire una tabella normativa si devono sempre tenere ben presenti alcuni aspetti.

  1. Una tabella normativa deve fornire la conversione di tutti i possibili punteggi grezzi che il test può produrre e non solo di quelli osservati nel campione di standardizzazione.

  2. Una tabella normativa deve essere univoca, per cui a ogni punteggio grezzo deve corrispondere uno e un solo punteggio standardizzato (al contrario, uno stesso punteggio standardizzato può corrispondere a più punteggi grezzi).

  3. I punteggi che si trovano sulle estremità delle code della distribuzione normale sono così rari da osservare che risulterebbero poco informativi dal punto di vista pratico. Generalmente, punteggi standardizzati localizzati oltre le 3 deviazioni standard dalla media non vengono considerati; qualora a un punteggio grezzo dovesse corrispondere un punteggio standardizzato che eccede questi limiti prestabiliti, il punteggio verrà appiattito sul limite dell'intervallo.

  4. Se la scalatura dei punteggi standardizzati è abbastanza ampia, l'interpretazione "clinica" viene effettuata arrotondando i valori all'intero più vicino, tralasciando la parte decimale.

  5. Spesso le tabelle normative sono disposte in senso discendente, ponendo i punteggi alti in testa e i punteggi bassi ai piedi.

Norme basate sulla distribuzione normale

Consideriamo un ipotetico test dedicato alla misura di un'abilità cognitiva in età scolare, che può produrre un punteggio grezzo compreso fra 0 e 30. Supponiamo che il costrutto sottoposto a esame si sviluppi con il progredire dell'età.

Vorremmo costruire dei riferimenti normativi per questo test. Dato che il costrutto varia in funzione dell'età, sarebbe opportuno che questi riferimenti normativi siano differenti per ogni anno d'età compiuto.

Immaginiamo di avere a disposizione un campione di osservazioni e di aver calcolato la media e la deviazione standard dei punteggi grezzi per ogni fascia d'età, salvando queste informazioni rispettivamente nei due vettori m e s.

m <- c("6" = 7.66, "7" = 12.07, "8" = 16.96, "9" = 20.53, "10" = 22.49)
s <- c("6" = 4.28, "7" =  4.54, "8" =  4.13, "9" =  4.28, "10" =  3.71)

Decidiamo di utilizzare come punteggio standardizzato il punto $z$, riscalato in modo tale che la media dellle osservazioni corrisponda a 10 (invece che a 0) e la deviazione standard a 3 (invece che a 1). Questo tipo di scalatura, utilizzato nei test Wechsler con il nome di Scaled Score, è diventato piuttosto celebre nella pratica psicometrica.

I Wechsler Scaled Scores (WSS) sono punteggi che nella pratica clinica vengono utilizzati come valori interi che variano fra 1 e 19 (valori esterni a questo intervallo sono rarissimi e quindi poco informativi).

Per costruire la tabella normativa possiamo far uso della funzione raw_score. Partendo dai parametri normativi di media e deviazione standard, raw_score converte una sequenza di punteggi standardizzati nel corrispettivo punteggio grezzo. Per effettuare questa operazione è necessario fornire alla funzione:

tab <- raw_score(19:1, m=m, s=s, scale="WSS")
show(tab)

La funzione tabula i punteggi grezzi corrispondenti a ogni possibile punteggio standardizzato. Si noti che al punteggio standardizzato 10 corrisponde esattamente il punteggio grezzo medio contenuto nel vettore m:

tab["10",]

Questa tabella presenta però alcuni problemi. Oltre alla presenza di valori decimali, impossibili da osservare (il test produce solo punteggi grezzi interi), la gamma di valori tabulati eccede la gamma di valori che possono effettivamente essere osservati (0-30).

A entrambi i problemi possiamo far fronte applicando a ogni vettore colonna la funzione score_rollup, che consente di racchiudere i punteggi in intervalli.

Intervalli di punteggi

Partendo dall'assunto che i punteggi grezzi prodotti da un test possono appartenere esclusivamente all'insieme dei numeri naturali, la funzione score_rollup associa univocamente ogni punteggio standardizzato a un intervallo di punteggi grezzi. La funzione individua entro quali valori grezzi interi sono racchiusi i punteggi tabulati, "arrotolandoli" entro classi di punteggio. La classificazione può essere effettuata arrotolando in senso ascendente (forward direction), ovvero partendo dal basso, oppure discendente (backward direction), ovvero partendo dall'alto.

Costruiamo una nuova tabella, contenente, per l'età di 6 anni, i punteggi originali e i punteggi classificati, sia in senso ascendente che discendente:

data.frame(
    row.names = 19:1,
    estimated = tab[,"6"],
      forward = score_rollup(tab[,"6"], x.min=0, x.max=30, direction="forward"),
     backward = score_rollup(tab[,"6"], x.min=0, x.max=30, direction="backward")
)

Si presti molta attenzione a due aspetti. Il primo è che non a tutti i punteggi standardizzati è associato un punteggio grezzo, ma si possono verificare dei salti (identificati dai valori mancanti). Il secondo è che sia il metodo forward che quello backward, nonostante portino a risultati leggermente differenti, sono da considerarsi entrambi validi: la scelta del metodo dovrebbe essere guidata da ragionati fondamenti teorici.

Possiamo applicare la funzione score_rollup a tutte le colonne della tabella normativa facendo uso del comando sapply:

normTab <- sapply(tab, score_rollup, x.min=0, x.max=30, direction="forward")
normTab <- data.frame(normTab, row.names = rownames(tab), check.names=FALSE)
show(normTab)

Nella tabella normativa costruita, le ultime due fasce d'età non possono mai ottenere il punteggio standardizzato massimo, perché in entrambi i casi già il punteggio standardizzato 17 è associato al punteggio grezzo massimo. Per ovviare a questo problema, qualora di problema dovesse trattarsi, è possibile impostare a TRUE l'argomento extremes:

normTab[,] <- sapply(tab, score_rollup, x.min=0, x.max=30, direction="forward", extremes=TRUE)

L'argomento extremes, quando attivato, fa in modo che gli estremi del vettore risultino sempre valorizzati.

show(normTab)

Esplosione e implosione della tabella

All'occorrenza, i punteggi contenuti nella tabella normativa prodotta possono essere "srotolati" tramite esplosione o implosione dei vettori colonna.

La funzione score_explode espande ogni intervallo di punteggi estraendo ogni singolo punteggio in esso contenuto.

score_explode(normTab[,"6"])

Possiamo anche eseguire l'operazione tenendo traccia del punteggio standardizzato corrispondente a ogni punteggio grezzo:

score_explode(normTab[,"6"], out.names=rownames(normTab))

La funzione score_implode individua, per ogni intervallo, un valore unico riassuntivo da associare al punteggio standardizzato. Come impostazione predefinita, tale valore è calcolato come media dei due estremi dell'intervallo.

score_implode(normTab[,"6"])

Anche in questo caso, possiamo tenere traccia del punteggio standardizzato corrispondente a ogni punteggio grezzo:

score_implode(normTab[,"6"], out.names=rownames(normTab))

Norme basate sui ranghi percentili

Affrontiamo infine il caso di sistemi di norme basati sui ranghi percentili. Prendiamo come esempio il dataset abilityTest, che contiene i punteggi ottenuti al test da un ipotetico campione di 30 bambini di 8 anni:

data("abilityTest")
head(abilityTest)

La prova di abilità richiede di eseguire un compito entro un intervallo di tempo prestabilito. L'esaminatore valuta l'esecuzione della prova attribuendole un punteggio compreso fra 0 e 30 (colonna score). Il bambino deve eseguire la prova evitando di commettere errori (il numero di errori è registrato nella colonna errors).

Vogliamo costruire una tabella normativa basata sui ranghi percentili, che consenta dunque all'utilizzatore del test di conoscere il rango percentile corrispondente a ogni punteggio grezzo ottenibile.

Partiamo dalla variabile score. Dato un vettore di punteggi grezzi osservati, la funzione perc_rank calcola il rango percentile corrispondente a ogni valore che gli viene passato nell'argomento breaks, individuando la percentuale di osservazioni minori o uguali a ogni breakpoint.

perc_rank(abilityTest$score, breaks=0:30)

Passiamo ora alla colonna errors. Questa variabile ha una caratteristica particolare: diversamente da score, all'aumentare del valore, la prestazione del soggetto peggiora, perché la variabile rappresenta un conteggio di errori. In casi come questo, per facilitare l'interpretazione dei punteggi prodotti dal test, spesso si preferisce invertire i ranghi percentili, calcolando la percentuale di osservazioni maggiori o uguali a ogni breakpoint.

Questo può essere fatto sfruttando l'argomento fun:

perc_rank(abilityTest$errors, breaks=0:5, fun=">=")

Si ricorda che, spesso, variabili che quantificano errori o tempi non sono limitate superiormente, ed è bene tenere a mente questo aspetto nella tabulazione dei valori.

Corrispondenza fra ranghi e punti z

testing dispone di funzioni che permettono di convertire un rango percentile nel corrispettivo punto z (o altro punteggio derivato), e viceversa di conoscere quale rango percentile corrisponde a un certo punto z.

Utilizzando la funzione perc2std possiamo per esempio sapere quale Wechsler Scaled Score corrisponde al rango percentile 75:

perc2std(75, scale="WSS")

All'opposto, utilizzando la funzione std2perc possiamo sapere quale rango percentile corrisponde a uno scaled score di 12:

std2perc(12, scale="WSS")

I valori restituiti rappresentano, chiaramente, un calcolo puramente teorico basato sulle proprietà della distribuzione normale. Più i dati osservati si avvicinano alla normalità distributiva, più i valori restituiti dalle due funzioni di conversione saranno rappresentativi della situazione reale.



DavideMassidda/testing documentation built on Oct. 12, 2023, 4:32 p.m.