Analisi multivariate con RStudio – parte 1
EPG1 di Metodologia della ricerca e tecniche multivariate di analisi dei dati
Avviso a cura dell’autore: si avvisa che il materiale contenuto in questa dispensa è destinato solo
agli studenti frequentanti l’EPG di Metodologia della ricerca tecniche multivariate di analisi dei dati
del corso di Laurea Magistrale in Psicologia dell’Università G. D’Annunzio di Chieti-Pescara. Ogni
utilizzo del presente materiale per fini diversi oppure ogni utilizzo per fini commerciali verrà
perseguito a norma di legge. Ogni utente di questa dispensa si fa carico del suo corretto utilizzo e
quindi deve evitarne ogni uso improprio.
Sommario Introduzione alla programmazione in R ............................................................................................................ 1
Creazione di uno script .................................................................................................................................. 1
La funzione “for” ........................................................................................................................................... 4
La funzione “if” ............................................................................................................................................. 5
Rendere interattivo uno script........................................................................................................................ 8
Costruzione di un database elettronico (dataset) ............................................................................................. 12
Cos’è un dataset e tipi di dataset ................................................................................................................. 12
Struttura ed organizzazione di un dataset .................................................................................................... 14
Importazione di un dataset ........................................................................................................................... 17
Controllo dei valori anomali .................................................................................................................... 17
Rilevazione dei dati anomali ................................................................................................................... 18
Esempio di ricerca di valori anomali o mancanti in un dataset ............................................................... 21
Cosa fare in caso di dati anomali o mancanti presenti nel dataset ............................................................... 22
Analisi descrittive con RStudio ....................................................................................................................... 25
Analisi descrittive di base ............................................................................................................................ 26
Rappresentazione grafica dei dati ................................................................................................................ 30
Il comando “pairs.panel” ......................................................................................................................... 30
Il comando “boxplot” .............................................................................................................................. 32
Il comando “barplot” ............................................................................................................................... 33
Stima dell’attendibilità ................................................................................................................................ 34
1
Introduzione alla programmazione in R
Un programma elettronico non è altro che una sequenza di algoritmi1 che, in seguito a dei dati in
entrata (input) fornisce un determinato output. L’algoritmo è una sequenza di comandi o di passi
che sono necessari per raggiungere un determinato obiettivo. Ad esempio, le istruzioni riportate in
una ricetta per, partendo da alcuni ingredienti, creare una pietanza sono degli algoritmi, in quanto
descrivono tutti i passi da quelli iniziali a quelli finali per raggiungere il risultato finale. In R il
programma contenente i diversi algoritmi viene definito script. Lo script, in realtà, è una funzione
complessa all’interno della quale vengono inserite diverse operazioni o funzioni. È addirittura
possibile creare script che attivano script esterni a loro volta attivanti altri script. Per attivare uno
script occorre usare il comando “source()”. All’interno delle parentesi tonde va scritto il percorso
delle directory (path) dove si trova il file. Un altro metodo è cliccare sul comando nel
riquadro degli script e automaticamente sulla console di R compare il comando source con tutto il
path del file. Per usare tale comando, però, occorre aver aperto nella finestra degli script lo script
che si vuole caricare.
Creazione di uno script
Supponiamo di voler creare uno script iniziale, ad esempio uno script che identifichi i numeri pari e
dispari all’interno di un array di dati, per prima cosa si deve cliccare sul comando della
finestra di RStudio. Subito comparirà un menù a tendina
Cliccando sul primo comando in alto, R Script, si genera nel riquadro degli script una nuova tab
window, come nella figura qui sotto
1 Il termine algoritmo deriva dall’arabo “al-Khwarizmi”, nome di un importante matematico arabo vissuto nel IX
secolo. Egli divenne famoso in quanto importò in arabia la notazione numerica indiana, che prevedeva l’uso dello zero.
2
Per prima cosa, dato che la finestra ha come nome “Untitled 1”, occorre salvarla nella nostra
directory di lavoro, ossia nella directory che abbiamo creato agli inizi e che serve per mettere i
dataset, gli script ed altri eventuali file ,come i file di testo che contengono gli output delle nostre
analisi. Cliccando sul tasto possiamo aprire la finestra per salvare il nostro script (che nel
nostro caso chiameremo “script1”). Nota bene: attenti a non usare il carattere punto “.” all’interno
del nome del file di script, perché il programma automaticamente assegna l’estensione “.R” allo
script, qualificandolo come file di script. Se ci fosse già un punto all’interno del nome, il
programma non assegna tale estensione e, quindi, il file non viene riconosciuto come script. Se
chiamiamo il file con il nome “script1”, mai scrivere, ad esempio, “script.1”.
Una volta slavato il file di script, dovremmo poterlo osservare anche nella finestra “Files” nel
riquadro delle finestre di servizio
Come si vede, il programma ha automaticamente assegnato l’estensione “.R” al file appena salvato.
3
Lo script è costituito da una funzione che ha un nome, un’assegnazione ed un suo corpo. Ogni
funzione deve avere un nome per poter essere chiamata al momento opportuno. Inoltre, deve avere
un’assegnazione, ossia occorre definire delle variabili che rappresentano i valori in entrata,
solitamente array, matrici o data frame. Chiamiamo, nel nostro esempio, la funzione con il nome di
“paridispari” (conviene assegnare nomi brevi alle funzioni, evitando nomi composti perché si riduce
il rischio di errore dovuto ad un’errata scrittura del nome della funzione”). Nella finestra seguente si
vede la forma generale della funzione
Nella prima riga abbiamo il nome, il comando “<-“ e “function” seguito da una parentesi tonda in
cui si definiscono le variabili di assegnazione, ossia le variabili con i valori di input. Il corpo della
funzione è definito dalle parentesi graffe “{” e “}”. Occorre notare che dopo la parentesi graffa
compare il simbolo di cancelletto “#” e dopo una serie di caratteri in verde. Il tasto “#” consente di
aggiungere dei commenti all’interno dello script, nel senso che il programma interpreta tutto quello
che si trova a destra del cancelletto come materiale trascurabile (non come comando o variabile).
Usando il cancelletto è possibile, pertanto, inserire dei commenti o delle frasi che sono utili per
spiegare a cosa servono i comandi o un quale punto dello script è stato inserito un certo comando.
In questo caso il commento “#end function” serve per ribadire che quella parentesi graffa
costituisce la fine della funzione. Tutto ciò che viene scritto dopo quella parentesi viene trascurato
dal programma. Pertanto occorre stare attenti a fare in modo che i comandi siano inclusi tra le
parentesi graffe. È buona norma inserire dei commenti negli script, soprattutto se si tratta di script
complessi, perché se si devono riutilizzare occorre ricordare a cosa servono i comandi e come sono
disposti, per evitare un uso improprio dello script. Il tasto “#” è utile anche per disattivare i
comandi, quando non si rendono più necessari.
Nella funzione abbiamo dato il nome “a” alla variabile di assegnazione. Solitamente si seguono
degli stili nella scelta dei nomi delle variabili. L’ideale è dare nomi semplici alle variabili, ad
esempio “x” o “a” quando le variabili di assegnazioni sono variabili semplici od array, oppure “X”
ed “M” quando le variabili di assegnazione sono più complesse, come matrici o data frame.
Il problema, ora, è il seguente: come fare a distinguere i numeri pari da quelli dispari e inserirli in
due array separati? Un modo è quello di creare una variabile list che si articola in due array, uno per
i numeri pari ed uno per quelli dispari. Questo è fattibile, ma rimane sempre il problema di
distinguere i pari dai dispari. Un modo è quello di usare la funzione modulo. La funzione modulo
restituisce un valore che corrisponde al resto che si ottiene dividendo un numero per un altro. Dati
due numeri x ed y, la funzione x mod y (x dividendo e y divisore) restituisce un valore che è zero se
il divisore è contenuto un numero intero di volte nel dividendo (ossia x = ny, dove n è u numero
Corpo della funzione nome della funzione Assegnazione della
funzione
4
intero), mentre restituisce un valore diversi da zero se y non è contenuto un numero intero di volte
in x (x ≠ ny). Ad esempio, 4 mod 2 da 0, 5 mod 2 da 1 e 5 mod 3 da 2 mentre 5 mod 2,5 da 0.
Dato che i numeri pari contengono tutti il numero 2 un numero intero di volte, ossia sono multipli di
2 (il 2 è il numero pari più piccolo) allora si può usare la funzione modulo per distinguere i pari dai
dispari. Dato un numero qualsiasi x, x è pari se x mod 2 = 0; x è dispari se x mod 2 ≠ 0.
La figura successiva riporta lo script completo che permette di distinguere i valori pari e dispari di
un array numerico e di riportarli in due variabili distinte.
paridispari<-function(a){
par<-vector()#creazione dell'array di numeri pari
dis<-vector()#creazione dell'array di numeri dispari
j.par<-1 #variabile contatore per numeri pari
j.dis<-1 #variabile contatore per numeri dispari
for(i in 1:length(a)){#ciclo for per verificare se il singolo valore
#pari o dispari modulo<-a[i]%%2
if (modulo==0){ #funzione if per creare array con numeri pari
par[j.par]<-a[i] #o array con numeri dispari
j.par<-j.par+1
}else if (modulo!=0){
dis[j.dis]<-a[i]
j.dis<-j.dis+1
}#end if
}#end for
ris<-list(pari = par, dispari = dis)
return(ris) #comando per stampare l'output dello script
}#end function
Per distinguere i numeri pari dai dispari occorre creare due nuovi array con il comando “vector()”,
l’array “par”, per i numeri pari, e l’array “dis” per i numeri dispari. Oltre a questi due array occorre
creare due variabili “j.par” e “j.dis”, che servono per contare le posizioni nei due array par e dis
man mano che si inseriscono i numeri che il programma trova nell’array in entrata a.
Ma come fa il programma a identificare i pari ed i dispari e ad inserirli separatamente nei due array?
Il programma utilizza due funzioni particolari, la funzione “for” e la funzione “if”. Queste due
funzioni sono alla base di qualsiasi tipo di script in R.
La funzione “for”
La funzione for serve per attivare operazioni cicliche o ripetute all’interno del programma. Molto
spesso le operazioni da eseguire devono essere ripetute più volte, soprattutto se i dati in entrata sono
array, matrici o data frame che contengono tantissimi dati. Se, ad esempio, inseriamo un array con
5
100 numero e per ciascuno dobbiamo usare la funzione modulo per capire se è pari o dispari,
dovremmo scrivere 100 volte tale funzione, il che è assurdo. Il ciclo for, per impedire di scrivere
inutilmente migliaia di linee di programma, consente di scrivere in poche righe i comandi ciclici,
ossia quelli che vano ripetuti. La funzione for è composta da diverse parti, che sono la parte che
stabilisce la lunghezza del ciclo (definita dentro due parentesi tonde) ed il corpo della funzione for,
(definita da due parentesi graffe), che contiene tutti i comandi da eseguire ciclicamente.
Lo schema della struttura della funzione for è:
for (lunghezza del ciclo){ corpo della funzione }
La lunghezza del ciclo si stabilisce definendo una variabile indicatore, di solito indicata con “i”2.
Ad esempio, se il ciclo deve avere lunghezza 100 cicli, allora si scrive:
for (i in 1:100){corpo della funzione}
In questo caso il ciclo for ha una lunghezza fissa, ossia un numero di cicli sempre costante. Però
non conviene fissare sempre ad un valore fisso il numero di cicli, soprattutto quando i dati in input
sono contenuti in array di diversa lunghezza. Nel nostro esempio, l’array a è definito in modo
generico, nel senso che può essere un array con 10, 100, 1000 o più dati. Quindi possiamo usare la
lunghezza effettiva dell’array a per determinare la lunghezza del ciclo for. La lunghezza dell’array a
è stimata con la funzione length(). Pertanto il ciclo for diventa
for (i in 1:length(a)){corpo della funzione}
All’interno del ciclo for abbiamo inserito, nel nostro esempio, la funzione modulo “%%” per
calcolare il modulo della divisione dei singoli valori di a, indicati con a[i], dove la variabile “i” tra
le parentesi quadre indica il valore di a alla i-esima posizione (le posizioni vanno da 1 alla
lunghezza massima di a). La variabile “modulo” può assumere il valore 0, se a[i] è pari, dato che
viene diviso per 2, e assume un valore diverso da zero se a[i] è dispari.
All’interno del ciclo for è stata inserita un’altra funzione speciale, la funzione if, che,
fondamentalmente, è una funzione che serve per eseguire operazioni logiche.
La funzione “if”
La funzione if è la funzione che serve per inserire comandi logici all’interno del programma. La
funzione if serve per dire al programma quando ci sono i requisiti per eseguire un determinato
comando. Nel nostro esempio, il problema era assegnare i valori pari dell’array “a” ad un altro
array, l’array “par”, e di assegnare i valori dispari all’array “dis”. L’unica soluzione era quella di
creare una funzione if la cui struttura è:
if (operatore logico){corpo della funzione}
2 Il fatto che nei cicli for si usi spesso indicare con “i” la variabile indicatore è dovuto alla pratica comune di definire
tale variabile “index”, o più semplicemente con la prima lettera.
6
Nelle parentesi tonde vanno definiti gli operatori aritmetici che sono
1) “==” per uguale a;
2) “!=” per diverso da;
3) “<” per minore di;
4) “>” per maggiore di;
5) “<=” per minore o uguale a;
6) “>=” per maggiore o uguale a.
Si possono anche definire gli operatori logici che sono
1) “!” per non (negazione logica);
2) “&” ed “&&” per e (congiunzione logica);
3) “|” ed “||” per o (disgiunzione logica).
Nel nostro esempio abbiamo usato gli operatori aritmetici “==” e “!=”. Se il modulo è uguale a
zero, allora il valori di a[i] viene inserito nell’array par[j] e poi si aumenta di uno la posizione di j
per inserire il valore successivo. Se il modulo è diverso da zero, allora il valore a[i] è inserito in
dis[j].
La variabile “ris” (che sta per risultato) è la variabile che deve essere restituita dalla funzione
“return()”. Se non scriviamo return, nella console non viene stampato alcun output, ossia l’esito
finale dello script rimane all’interno della funzione. Questo impedisce non solo la stampa del
risultato ma anche la sua eventuale assegnazione ad un variabile. Occorre far ricordare che le
variabili definite nel corpo dello script rimangono all’interno dell’ambiente dello script. Ad esempio
le variabili par, dis, j e ris create nello script esistono solamente all’interno della funzione. Se si
vuole che l’output della funzione sia utilizzabile all’interno della console è necessario creare una
nuova variabile nell’ambiente della console e assegnare ad essa l’output dello script inviato tramite
il comando return. Ora se creiamo un array con una serie di valori numerici pari e dispari, come nel
seguente esempio
> x<-c(2,3,1,4,3,7,5,6,6,8,4,3,7,3,5,2,4,9,5,3,2)
Per poter usare lo script pari dispari per la prima volta occorre prima caricare lo script nella console
tramite il comando source(). Per caricare lo script basta cliccare sul comando nella
strisci dei comandi sopra lo script, come evidenziato nella figura seguente
Dopo aver cliccato su source compare nella console il comando
> source('D:/MT documents 2/R works/meto 2018/script1.R')
7
Ora lo script è caricato e possiamo usarlo per le elaborazioni. Infatti, se scriviamo il nome dello
script e assegnamo l’array che abbiamo prima creato, ossia l’array x, otteniamo
> paridispari(x)
$`pari`
[1] 2 4 6 6 8 4 2 4 2
$dispari
[1] 3 1 3 7 5 3 7 3 5 9 5 3
Se scriviamo solo la funzione otteniamo direttamente l’output che consiste in una variabile list che
si articola in due array, il primo composto solo da numeri pari, il secondo solo da numeri dispari. In
questo modo, tuttavia, il risultato stampato non viene conservato nell’ambiente della console di
RStudio. Per fare in modo che il risultato rimanga nell’ambiente e possa essere riutilizzato
successivamente, dobbiamo creare una nuova variabile, ad esempio la variabile “apd” (array con
pari e dispari), come si vede nell’esempio riportato qui di seguito
> apd<-paridispari(x)
Se vogliamo vedere il contenuto della variabile apd, dato che è una variabile lista, allora per
visualizzare i numeri pari scriviamo apd$pari
> apd$pari
[1] 2 4 6 6 8 4 2 4 2
Se vogliamo vedere i numeri dispari scriviamo apd$dispari
> apd$dispari
[1] 3 1 3 7 5 3 7 3 5 9 5 3
Se, per esempio, vogliamo sapere la somma dei numeri pari e la somma dei numeri dispari, allora
scriviamo
> sum(apd$pari)
[1] 38
> sum(apd$dispari)
[1] 54
Quindi 38 è la somma di tutti i numeri pari e 54 è la somma di tutti i numeri dispari. Se vogliamo
preservare i risultati di tutte le operazione effettuate sui dati contenuti in apd, basta creare nuove
variabili al quale assegnare i risultati delle operazioni. Ad esempio, la somma dei numeri pari può
essere assegnata alla variabile “somma.pari” e la somma dei dispari alla variabile “somma.dispari”.
8
Rendere interattivo uno script
Nell’esempio precedente abbiamo creato uno script non interattivo, nel senso che una volta
chiamata la funzione ed assegnatole dei valori in input, la funzione da uno specifico output. Niente
e nessuno può intervenire per modificare la serie di calcoli effettuati dallo script.
Tuttavia, spesso si rende necessaria una programmazione che permetta di rendere interattivo lo
script, ossia l’utente magari si trova nella condizione di dover istruire lo script o di indicargli
l’operazione, la funzione o il tipo di analisi da eseguire.
Ad esempio, il test della correlazione tra due variabili implica che la formula per il calcolo della
correlazione sia diversa a seconda del tipo di dati. Se i dati sono su scala a intervallo o a rapporto, si
usa la formula di Pearson per calcolare la correlazione. Sei i dati sono su scala ordinale, si usa la
formula di Spearman. Se i dati sono i giudizi o osservazioni di due giudici indipendenti, e i giudizi
sono ranghi ossia dati su una scala ordinale, allora si usa il Tau di Kendall.
La funzione “cor.test()” in R permette di eseguire il test della correlazione, ossia di calcolare il
coefficiente di correlazione e stabilire il livello di probabilità o significatività. A questo punto, se si
vuole usare uno script che calcoli la correlazione bivariata per vari tipi di dati e misure, è possibile
creare uno script che esegui la correlazione ma che, prima di effettuare l’operazione, chiede
all’utente quale tipo di correlazione intende eseguire (correlazione di Pearson, di Spearman o di
Kendall).
Occorre un comando che chieda all’utente di fare una scelta, premendo un tasto della tastiera, in
modo che il programma, poi, esegua l’operazione giusta. Il comando apposito per fare questo tipo di
operazioni è il comando “readline()”, che stampa una scritta sulla console, dopo la quale l’utente
deve pigiare un tasto o scrivere dei numeri o dei caratteri che verranno assegnati ad una variabile
che verrà usata per indicare al programma l’operazione che deve eseguire. La struttura del comando
readline è
qq<- readline(“testo scritto”)
la variabile “qq” è la variabile a cui viene assegnato il valore scritto dall’utente sulla console. Ad
esempio, se si vuole semplicemente bloccare o chiudere una serie di operazioni dello script, basta
scrivere
qq<-readline(“vuoi interrompere lo script? (digita ‘y’ per sì o ‘n’ per no): “)
Se l’utente digita il tasto y la variabile qq assumerà il valore “y”; se digita il tasto n, assumerà il
valore “n”. Utilizzando la funzione if è possibile stabilire quale operazione il programma deve fare
in seguito alla scelta dell’utente.
Ora riportiamo come esempio una script per fare correlazioni bivariate che permetta all’utente di
scegliere il tipo o metodo di correlazione in base al tipo di dati. In R la funzione cor.test esegue, per
default, la correlazione di Pearson che, però è indicata solo per dati quantitativi.
9
Supponiamo di avere un gruppo di 6 soggetti di cui abbiamo misurato l’età ed il livello di glucosio
nel sangue. Vogliamo sapere se esiste una correlazione tra il livello di età ed il livello di glucosio.
Lo script per eseguire il test della correlazione è
biv_cor<-function(x,y){
qq<-readline("che tipo di correlazione vuoi eseguire? ('p' per Pearson;
's' per Spearman; 'k' per Kendall): ")
if (qq=="p"){
type<-"pearson"
}else if (qq=="s"){
type<-"spearman"
}else if (qq=="k"){
type<-"kendall"
}#end if
ris<-cor.test(x,y,method = type)
return(ris)
}#end function
Il nome dello script è “biv_cor” e le variabili di assegnazione sono x ed y. La variabile risultato
“ris” è il risultato del test della correlazione eseguito con la funzione “cor.test()”. Come argomenti
la funzione cor.test ha x, y e poi la funzione “method=” che serve per specificare il tipo di test. La
variabile “type” serve per stabilire il tipo di test. Essa assume il valore “pearson”, “spearman” o
“Kendall” a seconda della scelta dell’utente. Con la funzione “readline” l’utente può fare la sua
scelta e comunicarla al programma. readline stampa una scritta sulla console, l’utente pigia il tasto
“p”, “s” o “k” per indicare la sua scelta e la funzione if decide il valore di type a seconda della
scelta dell’utente.
Quindi, creiamo il dataset per la correlazione ed usiamo lo script “biv_cor” per fare la correlazione.
Prima di poter usare lo script si ricorda che occorre usare il comando “source()” per richiamare lo
script all’interno dell’ambiente della console.
> data<-c(43, 21, 25, 42, 57, 59, 99, 65, 79, 75, 87, 81)
> cond<-rep(c("age","glucose"),each=6)
> D<-cbind.data.frame(data,cond) > source('D:/MT documents 2/R works/meto 2018/biv_cor.R')
Dopo il commando source è possibile scrivere il nome della funzione. Attenzione
a come si assegnano i valori in input allo script. Ricordiamo che la variabile
D è un data frame, per cui occorre scrivere
> biv_cor(D$data[D[,2]=="age"],D$data[D[,2]=="glucose"])
che tipo di correlazione vuoi eseguire? ('p' per Pearson;
's' per Spearman; 'k' per Kendall): p
Pearson's product-moment correlation
data: x and y
t = 1.2494, df = 4, p-value = 0.2796
10
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.4942785 0.9380392
sample estimates:
cor
0.5298089
Nella funzione biv_cor specifichiamo che il primo array (x) è composto dai valori della colonna
data di D che corrispondono alla variabile “age” (D$data[D[,2]=="age"]) nella seconda
colonna di D, mentre i valori del secondo array (y) è composto dai valori della colonna data che
corrispondono alla variabile “glucose” (D$data[D[,2]=="glucose"]) nella seconda colonna.
Prima di dare l’output lo script stampa la scritta delle istruzioni sulla console e l’utente digita il
tasto della risposta. Avendo digitato il tasto “p” il test della correlazione è quello di Pearson.
Nell’output compare il coefficiente di correlazione r paria a 0,5298, compare il t test ed il relativo
valore di probabilità, che sono t = 1,2494 e p = 0,2796. Essendo p maggiore di 0,05, la correlazione
non é significativa. Viene dato, inoltre, anche l’intervallo di confidenza (95%) della correlazione i
cui estremi sono -0,494 e 0,938. Tale intervallo include il valore zero della correlazione per cui
viene confermata la non significatività della correlazione. I gradi di libertà (df) sono pari a 4
essendo n-2, ossia 6-2 = 4. n indica il numero di coppie (in questo caso 6 coppie di valori, età e
glucosio, per ciascun soggetto)
Supponiamo di voler confrontare i risultati di due esaminatori che hanno redatto, tramite
un’intervista, una graduatoria degli individui più adatti a svolgere un determinato lavoro. Vogliamo
sapere se i due esaminatori hanno assegnato le stesse posizioni in graduatoria agli esaminandi. Se
esiste una correlazione significativa tra le due graduatorie, significa che i giudizi dei due
esaminatori sono concordi e, perciò, validi. Essendo 12 i soggetti intervistati la graduatoria va dalla
posizione 1 alla posizione 12, in cui 1 indica la posizione più alta in classifica. I dati del nostro
esempio sono
> data<-c(1,2,3,4,5,6,7,8,9,10,11,12, 1,2,4,3,6,5,8,7,10,9,12,11)
> esam<-rep(c("esam1","esam2"),each=12)
> D2<-cbind.data.frame(data,esam)
Non c’è bisogno di ripetere il comando source, dato che basta caricare la funzione una volta sola, a
meno che non sia stata effettuata una modifica all’interno dello script. In questo caso occorre
ricaricare lo script, altrimenti continuerà ad eseguire le operazioni che aveva prima della modifica.
> biv_cor(D2$data[D2[,2]=="esam1"],D2$data[D2[,2]=="esam2"])
che tipo di correlazione vuoi eseguire? ('p' per Pearson;
's' per Spearman; 'k' per Kendall): k
Kendall's rank correlation tau
data: x and y
T = 61, p-value = 1.634e-05
alternative hypothesis: true tau is not equal to 0
sample estimates:
tau
11
0.8484848
L’utente, scegliendo “k”, ha eseguito il test Tau di Kendall. Il valore del coefficiente Tau è 0,848,
molto alto, ed il valore di probabilità p è 1,643e-05, in notazione scientifica, che nella notazione
numerica normale corrisponde a 0,00001634. Il valore di probabilità è inferiore a 0,05, per cui
esiste concordanza tra le graduatorie dei due esaminatori e le loro classifiche risultano valide.
Se si vuole abolire la notazione scientifica negli output di R, si può usare il comando “options()”.
Infatti scrivendo:
> options(scipen=999)
Ora eseguendo di nuovo l’analisi di prima, si ottiene
Kendall's rank correlation tau
data: x and y
T = 61, p-value = 0.00001634
alternative hypothesis: true tau is not equal to 0
sample estimates:
tau
0.8484848
Da ora in poi nell’output tutti i numeri avranno una notazione decimale normale. Se volete
ripristinare la notazione scientifica nel formato dei numeri, scrivete:
> options(scipen=0)
12
Costruzione di un database elettronico (dataset)
I file dati o dataset servono a contenere i dati sui quali è necessario poi eseguire calcoli od
operazioni logico-matematiche. Con l’avvento dei micro-computer, nei quali si possono usare i
programmi di calcolo statistico-matematici, le operazioni di calcolo, anche di una notevole mole di
dati, sono diventati accessibili più o meno a tutti, a soggetti esperti che meno esperti. I primi micro-
computer vennero introdotti sul mercato verso la fine degli anni ’60. Prima di allora i computer
erano macchine ingombranti e piuttosto difficili da usare, dato che non esistevano sistemi di
interfaccia user-friendly, per cui solo persone con competenze tecniche elevate potevano usarli.
Infatti, i primi computer usavano solo il linguaggio macchina, che è un codice binario e per indurre
il computer ad eseguire qualsiasi operazione, anche una semplice somma come 2 + 2 = 4, occorreva
tradurla in un codice binario3. Adesso, invece è possibile creare dataset ampi e con una notevole
varietà di dati.
Cos’è un dataset e tipi di dataset
Un dataset è solitamente un file di test o un foglio elettronico che può contenere informazioni
relativi alle caratteristiche dell’oggetto di osservazione dello psicologo ricercatore. L’oggetto di
osservazione dello psicologo di solito è un essere umano. Lo psicologo nei suoi esperimenti o
ricerche sottopone gli esseri umani a prove o stimolazione per osservarne gli effetti sul suo
comportamento. In questo caso si parla di ricerca sperimentale, perché lo psicologo cerca di capire i
meccanismi di funzionamento dei processi di pensiero o del comportamento attraverso le creazioni
di situazioni o setting sperimentali. In altri casi lo psicologo effettua delle raccolte dati tramite
somministrazioni di questionari, interviste o semplicemente osservando il comportamento della
persone in contesti naturali o più strutturati (come un una stanza con specchio monodirezionale, ad
esempio). In questo tipo di ricerche lo psicologo cerca di capire se la presenza di determinate
caratteristiche nei soggetti li induce a sviluppare altre caratteristiche dal punto di vista
comportamentale, emozionale, percettivo o attitudinale.
Esistono pertanto due gradi modelli di ricerca a disposizione dello psicologo ricercatore:
1. La ricerca in ambienti controllati con soggetti selezionati: in questo tipo di ricerca lo
psicologo usa ambienti controllati, come i laboratori, in cui può controllare e manipolare gli
stimoli o le condizioni ambientali per indurre modifiche nel comportamento umano. Gli
esseri umani vengono scelti e selezionati dallo sperimentatore in modo da incrementare il
più possibile la validità e generalizzabilità dei risultati sperimentali.
2. La ricerca su campo o su vasti campioni di soggetti: in questo tipo di ricerca lo psicologo
cerca di studiare le caratteristiche degli esseri umani e vedere se certe caratteristiche si
abbinano con più frequenza con altre caratteristiche (correlazione tra tratti o capacità
psicologiche) oppure vede se certe caratteristiche in individui che vivono in certi contesti o
3 Il numero 2 del sistema decimale corrisponde al numero 10 del sistema binario. Quindi la somma 2 + 2 equivale a 10
+ 10 = 100. Il numero 100 nel sistema binario equivale al numero 4 nel sistema decimale.
13
in certi ambienti sono frequenti o no (ad es. verificare se la frequenza del ritardo mentale è
maggiore in soggetti che vivono in ambienti inquinati o no).
Lo psicologo può eseguire una ricerca in laboratorio, una ricerca su campo oppure sia in laboratorio
che su campo. Alla fine, comunque, il ricercatore raccoglierà una serie di dati con i quali costruisce
i suoi dataset.
I dati più comunemente rilevati nella ricerca in laboratorio sono i tempi di risposta, l’accuratezza
delle risposte (contando il numero di risposte giuste o di errori), misure fisiologiche, come la
frequenza ed il battito cardiaco, oppure risposte verbali o non verbali dei soggetti che descrivono i
loro stati interni come sensazioni, percezioni, stati emotivi, ecc. I dati più comunemente rilevati
nella ricerca su campo sono dati ottenuti con test, questionari, interviste od osservazioni.
Ovviamente la modalità di raccolta dei dati, pur essendo più frequente in un tipo di ricerca rispetto
ad un altro, non implica che possa essere usata anche in altri contesti sperimentali. Ad esempio, il
questionario o l’osservazione può essere usata in una ricerca in laboratorio ed i tempi di risposta e
l’accuratezza delle risposte in una ricerca su campo. L’unico requisito è che i dati raccolti risultino,
poi, validi per le analisi statistiche.
La validità statistica dei dati raccolti dipende dalla scala di misura, dal tipo di disegno sperimentale
adottato (disegno con campioni indipendenti o a misure ripetute) e dal tipo di ipotesi sperimentale.
Se l’ipotesi cerca di verificare l’esistenza di una relazione causa-effetto tra le variabili, allora le
analisi statistiche si basano sul confronto tra le statistiche dei singoli gruppi, ad esempio sul
confronto tra medie. Il confronto tra medi viene effettuato tramite il t di Student o l’ANOVA. Se
l’ipotesi cerca solo di stabilire l’esistenza di un nesso o legame tra le variabili, allora si effettuano
analisi correlazionali, di regressione o fattoriali.
Le analisi statistiche, qualunque tipo siano, si effettuano su dati registrati all’interno di un dataset
elettronico. Esistono altri tipi di analisi, come le analisi del testo, che, però, richiedono una forma
particolare di dataset e programmi specifici di analisi. In questo contesto ci limitiamo
all’applicazione delle tre fondamentali tecniche di analisi multivariate dei dati su un dataset.
Le tre tecniche di analisi multivariate che considereremo sono:
1. L’analisi di regressione multipla;
2. L’analisi fattoriale esplorativa e confermativa;
3. L’analisi di varianza (ANOVA ad una via per campioni indipendenti, ANOVA ad una via a
misure ripetute, ANOVA a due vie per campioni indipendenti, ANOVA a due vie mista).
Ciascuna di queste analisi statistiche richiedono dataset organizzati in modo appropriato. Se i dati
non sono organizzati in modo appropriato, c’è il rischio di effettuare elaborazioni pasticciate. Man
mano che presenteremo le procedure per eseguire le analisi, descriveremo anche come deve esser
organizzato un dataset. Intanto forniamo alcune informazioni preliminari sull’organizzazione del
dataset.
14
Struttura ed organizzazione di un dataset
Un dataset è una matrice di dati dove per riga abbiamo le unità osservative o singole osservazioni,
che nel caso della psicologia sono, solitamente, i singoli soggetti e, per colonne, le variabili. Le
variabili possono essere fattoriali (identificano gruppi di soggetti, come, ad esempio, il sesso, il tipo
di professione, la presenza o meno di una patologia, il titolo di studio, la residenza, il livello
economico, ecc.) oppure variabili misurative su cui si devono fare le analisi statistiche. Le misure
possono essere variabili di tipo dicotomico, ossi con solo due tipi di valori (es.: giusto o sbagliato,
vero o falso, ecc.), oppure graduabili, ossia variabili che riportano i valori di caratteristiche che
hanno una gradazione di intensità, come il tempo di risposta, il livello di sensazione, il livello di
attitudine, il livello di accordo, ecc. Le risposte agli item di un questionario sono variabili
misurative. Se le risposte sono di tipo vero o falso, allora abbiamo misure dicotomiche; se le
risposte sono su scala Likert (Ad es. “per niente vero”, “poco vero”, “abbastanza vero”, “molto
vero”, “sempre vero”) allora abbiamo misure graduabili. Le risposte misurative possono essere
codificate numericamente (0 e 1 per le risposte dicotomiche; da 0 o da 1 a n per le risposte
graduabili). È preferibile usare sempre la codifica numerica per le variabili misurative, dato che le
analisi statistiche si effettuano su dati numerici. Non è possibile calcolare la media o la varianza su
dati non numerici.
Il dataset presenta delle colonne obbligatorie. La prima colonna è quella che serve per identificare il
soggetto. Di solito è definita con la sigla “ID” o “SOGG”, rispettivamente “identificativo” e
“soggetto”. Questa colonna riporta dei valori che possono essere caratteri o numeri che servono
appunto per identificare i soggetti. Ad ogni soggetto andrebbe abbinato un codice che permette la
sua rapida identificazione quando si scoprono della anomalie o delle peculiarità nei suoi dati.
Inoltre, il codice permette una selezione dei soggetti, qualora fosse necessario selezionare soggetti
con determinate caratteristiche. La forma più semplice di codifica è l’uso delle iniziali dei nomi e
cognomi associato al numero di riga (Per es.: il soggetto Mario Rossi della riga 11 sarà codificato
come mr11). Altre forme di codifica sono o l’uso del numero di riga, oppure di una sigla generica,
“s” per soggetto, abbinata al numero di riga. Ritornando all’esempio di Mario Rossi, possiamo
quindi o codificare semplicemente con il numero “11” oppure con la sigla “s11”. Ogni psicologo è
libero di decidere il criterio di codifica del soggetto, l’importante è che ogni soggetto abbia uno
specifico codice.
In alcuni casi può capitare che i dati del soggetto vengano riportati su più righe (magari in ricerche
in cui il soggetto è testato in più fasi). In questo caso allora per capire che è lo stesso soggetto
testato più volte si usano le sigle “mr11.bis” o “mr11-2”. Si sconsiglia l’uso di dataset con più righe
per ciascun soggetto, perché rende più difficile l’utilizzo del dataset per le analisi statistiche.
L’ideale è avere sempre un soggetto per ogni riga ed una colonna per ciascuna variabile fattoriale o
misurativa.
Il dataset può anche riportare oltre ai codici identificativi dei soggetti anche i loro nomi, sempreché
non ci siano rischi di violazione della privacy e il nome della persona che li ha esaminati o ha
somministrato loro i test (quando la ricerca implica l’uso di più esaminatori). Il dataset può riportare
il luogo e la data in cui il soggetto è stato esaminato. Questi, di solito, sono dati utili quando si tratta
di soggetti clinici.
15
Il dataset si compone, come abbiamo detto, di due grandi gruppi di variabili, le variabili fattoriali e
le variabili misurative. La variabili fattoriali specificano le caratteristiche dei soggetti, come sesso,
titolo di studio, livello economico, razza, professione, regione geografica, credo religioso, ecc. Nei
dataset, se la prima colonna è quella dei codici identificativi dei soggetti, la colonna dalla seconda
in poi riporta i dati delle variabili fattoriali. Tali variabili servono per categorizzare i soggetti, ossia
stabilire in quali gruppi inserirli (ad es., stabilire se il soggetto è un maschio od una femmina).
Oppure servono per definire la condizione sperimentale a cui sono stati assegnati (ad es. gruppo di
controllo e gruppo sperimentale). Queste variabili stabiliscono, in ultima analisi, i livelli dei fattori,
ossia i livelli della variabile indipendente tra i quali si devono eseguire le analisi statistiche (ad es.
maschi vs femmine o gruppo di controllo vs gruppo sperimentale). Il secondo grande gruppo, le
variabili misurative, specifica le “misure” sulle quali si eseguono le analisi statistiche. Le misure,
come abbiamo detto, possono essere di tipo dicotomico (la caratteristica è presente o assente, come
ad es. un attacco di emicrania, la presenza o assenza di una data capacità) oppure graduabili (come,
ad esempio, il livello d’ansia, d’intelligenza, di empatia, ecc.). Queste variabili possono essere tante,
in relazione al tipo di strumenti di misura adottati e al tipo di misura. Le variabili misurative, infatti,
possono essere:
1. Risposte ai singoli item di uno o più test
2. Punteggi ottenuti nelle diverse sottoscale di un test (es. la WAIS) o nelle scale che
compongono una batteria di test (es. il CBA)
3. Punteggi ottenuti in diverse prove sperimentali durante l’esecuzione di un esperimento il
laboratorio (es. percezione di diversi tipi di stimoli visivi o ascolto di diversi tipi di suoni).
4. Punteggi ottenuti in diverse fasi temporali (es., studio longitudinale in cui soggetti sono
testati in diversi periodi di tempo).
5. Valori ottenuti da diverse ricerche od esperimenti, come nelle ricerche di metanalisi.
La figura X mostra una rappresentazione schematica della struttura di un data base
La colonna “ID” è per l’identificativo dei soggetti (o delle unità osservative), mentre le colonne da
F1 a Fm riportano i valori o dati delle variabili fattoriali. Le colonne da V1 a Vn riportano i dati
misurativi.
ID F1 F2 Fm V1 V2 Vn ... ... ... ...
...
... ... ...
s1
s2
sk
...
...
...
d1,1 d1,2
d2,1
dk,m+n
... ... ... ... ...
... ... ... ... ...
... ... ... ... ... ...
... ... ... ... ... ... ... ... ... ... ...
... ... ... ... ... ... ...
... ...
... ... ... ... ... ... ... ... ... ... ... ... ...
... ... ... ... ... ... ... ... ... ... ... ... ...
... ... ... ... ... ... ... ... ... ... ... ...
16
La figura X mostra un esempi di un dataset in formato excel.
I formati più usati per i dataset sono i formati .txt (testo), .csv (comma-separated values) e .xls o
.xlsx (excel). Consigliamo l’uso di excel per la creazione di un dataset, sia perché è incluso nel
pacchetto Office di Windows, sia perché i fogli elettronici di excel sono facili da usare e permettono
essi stessi di verificare se c’è stato un errore nell’inserimento dei dati o se è presente un’anomalia.
Inoltre, i dataset excel sono compatibili non solo con RStudio ma con tutti gli altri tipi di
programmi statistici (SPSS, SAS, Statistica,...).
Una volta creato il dataset, è possibile caricarlo in RStudio ed eseguire le analisi statistiche. Per le
analisi statistiche, in particolare, occorre seguire la seguente procedura:
1. Verifica e controllo della completezza del dataset, verifica delle presenza di valori anomali e
trattamento dai datti mancanti;
2. Trasformazione del dataset o selezione di una sub-matrice per le analisi statistiche
3. Esecuzione delle analisi statistiche
4. Salvataggio degli esiti delle analisi statistiche su file e creazione di rappresentazioni grafiche
Prima di passare alle descrizioni di ciascuna fase della procedura, occorre fornire alcune
informazioni preliminari.
1. Le variabili fattoriali possono essere variabili continue come l’età. Queste possono essere
trasformate in fattori se si selezionano intervalli di valori con cui creare i livelli dei fattori.
Ad esempio, se ho un campione di soggetti dai 25 ai 64 anni, posso creare gli intervalli 25-
34, 35-44, 45-54, 55-64, ossia un fattore con 4 livelli d’età.
2. È meglio usare delle sigle opportune per identificare le variabili. Ad esempio, se si riportano
i dati relativi agli item di un test, usare sigle come “item1”, “item2” ecc. risulta
svantaggioso, perché non si sa a quale test fanno riferimento. Spesso i dataset contengono i
dati di tanti test, quindi occorre anche specificare a quale test fa riferimento l’item. Se
abbiamo usato il Big Five Questionnaire, allora usiamo la sigla BFQ per identificare il test.
Sappiamo, inoltre che il BFQ ha 5 dimensioni o fattori (Energia, Amicalità, Stabilità
Emotiva, Coscienziosità e Apertura Mentale). Ogni fattore si compone di due facet scales.
17
Ad esempio, il fattore Energia si compone della scala di Dinamismo e di Dominanza.
Usando la sigla “E” per indicare il fattore energia e le sigle “Do” e “Di” per indicare
dinamismo e dominanza, rispettivamente, allora la sigla “BFQ_E_Do_i1” significa che il
dato è relativo all’item 1 (i1) della facet scale Dominanza (Do) del Fattore Energia (E) del
questionario big five (BFQ).
Importazione di un dataset
Per facilitare le operazioni con RStudio, è necessario creare una cartella o directory di lavoro. In
questa directory dobbiamo mettere i dataset e salvare eventuali file Script creati con RStudio oppure
i file che contengono l’output delle analisi, di solito in formato .txt. Nel file “Uso di RStudio” viene
spiegato come importare un dataset. Qui aggiungiamo solo cosa fare una volta importato un dataset.
Una cosa fondamentale da eseguire è controllare se nel dataset sono presenti dati mancanti e, se sì,
quanti. Controllare se ci sono dati anomali è fondamentale prima di eseguire qualsiasi analisi,
altrimenti si rischia di ottenere risultati distorti e fasulli.
Controllo dei valori anomali
Il controllo dei valori anomali serve per escludere la possibilità che i valori inseriti siano sbagliati.
Ad esempio, se i valori delle risposte ad un item variano da 1 a 5, chiaramente un valore pari a 55
(ottenibile magari digitando per sbaglio due volt ei di seguito il tasto 5) risulta anomalo. Un metodo
per verificare l’esistenza di valori anomali è calcolare il minimo ed il massimo punteggio per
ciascuna colonna di dati con le funzioni “min()” e “max()”.
Se ci stanchiamo di calcolare i valori minimo e massimo di un dataset perché contiene tante
variabili, possiamo creare un semplice script come quello seguente, che chiameremo funzione
“maxmin”, nel quale daremo in assegnazione una matrice o data frame di dati e otterremo, in output
la sequenza di minimi e massimi per ciascuna variabile del dataset.
Lo script ha la seguente struttura
maxmin<-function(M){
dd<-dim(M)#variabile per le dimensioni del dataset (righe x colonne)
minimi<-vector()
massimi<-vector()
etich<-vector()
nomi<-colnames(M)
for(i in 1:dd[2]){#ciclo for per analisi colonna per colonna
x<-M[,i]
if(is.numeric(x)==TRUE){#funzione if per analisi solo se i dati sono
numerici
minimi[i]<-min(x)
massimi[i]<-max(x)
etich[i]<-nomi[i]# array per registrare i nomi delle variabili
18
}#end if
}#end for
ris<-cbind(etich,minimi,massimi)#matrice dei risultati
return(ris)
}#end function
La variabile di input è la variabile “M” che indica la matrice di dati in entrata. Nello script vengono
create delle nuove variabili che hanno la funzione di permettere l’esecuzione dello script. La
variabile “dd” che in realtà è un array, contiene il numero di righe e colonne della matrice dati in
entrata M. la variabile “minimi” è un array che include i valori minimi di una colonna di dati e la
variabile “massimi” include i valori massimi della colonna di dati. Questi sono nuovi array che
vengono generati con il comando “vector()” ed esistono solo nell’ambiente dello script. Il comando
“vector()” serve per generare nuovi array che sono vuoti fino a quando non vengono loro assegnati
dei valori. Eccetto le variabili singole che vengono create contestualmente all’assegnazione tramite
il comando di assegnazione “<-”, la variabili più complesse come gli array o le matrici necessitano
di essere prima definite, tramite il comando “vector” per gli array e “matrix” per le matrici.
Le variabili “nomi” ed “etich” servono per registrare i nomi di tutte le variabili del dataset e di
scegliere quelle che contengono i valori anomali. Usando le funzioni if e for è possibile, poi,
individuare le variabili ed i soggetti che presentano i valori anomali. In poche parole, il programma
passa al setaccio ogni singolo valore del dataset per individuare i valori minimi e massimi, gli
estremi della scala. Una volta individuato il valore, nella variabile etich viene segnato il nome della
variabile, nella variabili minimi viene segnato il minimo e nella variabile massimi il valore
massimo, generando così tre array che vengono composti con il comando “cbind” in una matrice
(cbind sta per “Column Bind”, assia abbinamento degli array per colonna) che costituisce la
variabile di output “ris” il cui contenuto viene stampato sulla console tramite la funzione return. È
possibile effettuare un abbinamento degli array per riga (Row Bind) con il comando “rbind”.
Facendo una prova con un dataset apposito è possibile verificare per ciascuna variabile di un dataset
gli estremi di scala ed individuare quelle variabili con valori estremi sbagliati. Ad esempio, se il
dataset contiene le risposte agli item di un test che sono risposte su scala Likert da 1 a 5 e troviamo
invece item con minimi inferiori a 1 e superiori a 5, allora vuol dire che qualcosa non va nel nostro
dataset. Occorre poi capire se si tratta di un errore di registrazione del dato o se, effettivamente,
alcuni item prevedono intervalli di valori diversi (cosa che capitava frequentemente con test
psicologici molto vecchi).
Un funzione molto utile sarebbe quella che consente di individuare i dati anomali o i dati mancanti
per ciascuna riga e colonna del dataset, in modo da individuare con precisione la variabile ed il
soggetto che hanno quel dato. Questo consente di andare a verificare se il dato anomalo è dovuto ad
un’errata trascrizione del dato e, quindi, risolvibile correggendo la trascrizione o se, nel caso di dati
mancanti, il soggetto ha effettivamente omesso di rispondere oppure se l’esaminatore si è
dimenticato di riportare il dato per una distrazione.
Per facilità di esposizione proponiamo come esempio due tipi di script, uno per rilevare i dati
anomali ed uno per rilevare i dati mancanti.
Rilevazione dei dati anomali
Lo script per la rilevazione dei dati mancanti, denominato “detect” è il seguente:
19
detect<-function(M){
dd<-dim(M)
qq<-readline("inserisci valore minimo di scala: ")
minimo<-as.numeric(qq)
qq<-readline("inserisci valore massimo di scala: ")
massimo<-as.numeric(qq)
mm<-matrix(0,nrow=dd[1],ncol=dd[2])
for (i in 1:dd[2]){
w<-which(M[,i] < minimo)
if (length(w)!=0){mm[w,i]<-1}
w<-which(M[,i] > massimo)
if (length(w)!=0){mm[w,i] <- 1}
}#end for
etich<-colnames(M)
print.noquote("----------------------------")
print.noquote("individuazione dati anomali")
print.noquote("----------------------------")
for (i in 1:dd[2]){
for (j in 1:dd[1]){
if (mm[j,i]!=0){
print.noquote("variabile e soggetto con dato anomalo")
ris<-c(etich[i],j)
print(ris)
}#end if
}#end for2
}#end for 1
}#end fuction
Lo script si articola in tre parti. Nella prima (i comandi sono in colore blu) compare la funzione
“readline” che serve per inserire gli estremi della scala. Se i dati sono le risposte a degli item,
supponiamo su scala Likert da 1 a 7, allora si inseriscono i valori 1 e 7. Se il test prevede risposte
dicotomico 0 e 1, allora gli estremi sono 0 e 14. Nella seconda parte (i comandi sono di colore
rosso) abbiamo le funzioni if e for che servono per individuare il dato anomalo, sostanzialmente il
dato che è inferiore al valore minimo, oppure il dato che è superiore al valore massimo. Se viene
individuato il dato anomalo, allora si inserisce nella matrice “mm” che contiene solo valori zero il
valore 1, che indica la presenza del dato anomalo. Il comando “length()” serve per effettuare
l’assegnazione del valore 1 ad mm solo quando effettivamente viene individuato il dato anomalo.
Occorre far notare che il valore 1 viene assegnato non solo in caso di valori fuori scala, ma anche se
la cella del dataset è vuota. La terza parte ( i comandi sono di colore arancio), infine, effettua la
stampa sulla console di RStudio delle variabili e dei soggetti che presentano il valore anomalo. In
questo modo possiamo sapere un quale cella del dataset è presente il valore anomalo.
Lo script per individuare i valori mancanti, denominato “mancanti” è il seguente:
4 Se la scala delle risposte ad un item prevede graduazioni definite con etichette verbali, ad esempio, “per niente”,
“poco”, “abbastanza” e “molto”, conviene tradurre queste etichette in valori numerici, ad esempio 1, 2, 3 e 4 e inserirli nei dataset. I valori numerici, oltre a poter essere usati nelle analisi statistiche, facilitano l’individuazione di dati anomali e mancanti.
20
mancanti<-function(M){
dd<-dim(M)
etich<-colnames(M)
print.noquote("----------------------------")
print.noquote("individuazione dati mancanti")
print.noquote("----------------------------")
qq<-readline("inserisci tipo di dato mancante ('1' per NA o NaN; '2' per cella
vuota, '3' per altro: ): ")
if (qq=="1"){
for (i in 1:dd[2]){
for (j in 1:dd[1]){
if (is.na(M[j,i]) == TRUE){
print.noquote("variabile e soggetto con dato mancante")
ris<-c(etich[i],j)
print(ris)
}#end if
}#end for2
}#end for 1
}else if (qq=="2"){
for (i in 1:dd[2]){
for (j in 1:dd[1]){
if (is.na(M[j,i]) == FALSE &M[j,i] == ""){
print.noquote("variabile e soggetto con dato mancante")
ris<-c(etich[i],j)
print(ris)
}#end if
}#end for2
}#end for 1
}else if (qq=="3"){
qq<-readline("inserisci il valore usato per indicare i dati mancanti: ")
type<-as.numeric(qq)
for (i in 1:dd[2]){
for (j in 1:dd[1]){
if (is.na(M[j,i]) == FALSE & M[j,i]==type){
print.noquote("variabile e soggetto con dato mancante")
ris<-c(etich[i],j)
print(ris)
}#end if
}#end for2
}#end for 1
}#end if
}#end function
Lo script è apparentemente un po’ complesso, ma in realtà si articola in due parti. Nella prima parte
(in blu) l’utente deve scegliere l’opzione per l’individuazione dei valori mancanti. I dataset in R
prevedono diverse tipologie di dati mancanti o missing. I dati mancanti possono essere indicati:
1) Dai simboli “NA” o “NaN” che in R indicano che la cella non contiene i dati. Se in R o
RStudio vengono caricati dei dataset fatti con altre applicazioni solitamente alle eventuali
celle vuote dei dataset vengono assegnati i valori NA (Not Available, ossia dato non
disponibile). NaN (Not a Number), invece, indica un valore indefinibile ottenibile
applicando operazioni matematiche assurde, ad esempio 0/05.
5 Dividendo un numero qualsiasi per zero si ottiene infinito. Dividendo zero per un numero qualsiasi si ottiene 0.
Dividendo zero per zero si ottiene un valore anomalo, indicato in R con il simbolo NaN.
21
2) Possono essere semplicemente celle vuote. Questa possibilità compare di frequente quando
si creano dei dataset successivi in cui, per motivi logico matematici alcuni dati non sono
calcolabili e, quindi, registrabili.
3) Oppure si usano valori particolari all’interno del dataset, ad esempio 999 o -999, per
indicare il dato mancante.
Nel programma l’utente può scegliere tre opzioni: 1 se il dataset contiene valori NA o NaN come
valori mancanti; 2 se il dataset contiene celle vuote; 3 se il dataset contiene valori particolari che
codificano il dato mancante. In quest’ultimo caso il programma chiede all’utente di riportare il
valore codificato.
Occorre dire che solitamente è raro che i dataset contengano celle vuote, anche in caso di omessa
risposta. Infatti, la cella vuota non esclude il caso che il dato mancante sia dovuto ad una distrazione
di chi ha creato il dataset. Se, invece, compare un dato palesemente artificiale e già convenuto come
valore per indicare il dato mancante (ad esempio, -999), allora si è sicuri che il dato mancante ha
come unica causa il fatto che il soggetto non ha dato la risposta.
La seconda parte dello script (in rosso) consiste in diverse funzioni if e for che, a seconda della
scelta dell’utente, permettono di effettuare la ricerca del valore mancante e di stampare il nome
della variabile e il numero di riga (il soggetto) per cui si ha un dato mancante. In questo modo è
possibile andare a vedere quale persona non ha risposto e per quale item o variabile non ha dato la
risposta.
Esempio di ricerca di valori anomali o mancanti in un dataset
Supponiamo di avere un piccolo dataset in cui sono presenti dai valori anomali o mancanti, come
nel seguente esempio:
> X
hap1 hap2 hap3 hap4 hap5 hap6 hap7 hap8 hap9 hap10 hap11 hap12
1 3 4 5 4 5 5 5 5 4 5 5 4
2 1 5 2 4 5 5 4 1 5 4 1
3 3 3 4 4 4 4 3 3 4 5 4 4
4 5 5 5 5 5 55 5 5 5 3 5 5
5 5 3 4 4 3 4 3 3 22 3 4 5
6 5 2 4 5 3 5 2 4 3 2 5 4
7 5 4 3 5 3 5 3 3 5 3 4 5
8 1 5 5 4 4 5 4 5 3 5 5 2
9 3 5 5 3 5 5 5 4 1 5 5 5
10 2 4 4 1 3 5 4 0 1 4 4 1
11 4 5 4 4 4 3 5 4 3 5 4
12 3 5 5 1 5 5 5 5 1 5 5 1
Il dataset prevede tre valori anomali (0, 22 e 55) e due dati mancanti, rappresentati da due celle
vuote.
Applicando lo script detect otteniamo
> source('D:/MT documents 2/R works/meto 2018/detect.R')
22
> detect(X)
inserisci valore minimo di scala: 1
inserisci valore massimo di scala: 5
[1] ----------------------------
[1] individuazione dati anomali
[1] ----------------------------
[1] variabile e soggetto con dato anomalo
[1] "hap3" "2"
[1] variabile e soggetto con dato anomalo
[1] "hap6" "4"
[1] variabile e soggetto con dato anomalo
[1] "hap8" "10"
[1] variabile e soggetto con dato anomalo
[1] "hap9" "5"
[1] variabile e soggetto con dato anomalo
[1] "hap10" "11"
Il programma ha individuato 5 dati anomali (i tre valori fuori scala ed i due dati mancanti).
Applicando lo script missing otteniamo
> source('D:/MT documents 2/R works/meto 2018/missing.R')
> missing(X)
[1] ----------------------------
[1] individuazione dati mancanti
[1] ----------------------------
inserisci tipo di dato mancante ('1' per NA o NaN; '2' per cella vuota, '3' per
altro: ): 2
[1] variabile e soggetto con dato mancante
[1] "hap3" "2"
[1] variabile e soggetto con dato mancante
[1] "hap10" "11"
Per identificare i valori anomali conviene stralciare dalla lista dei dati anomali gli elementi
corrispondenti a quelli riportati nella lista dei dati mancanti.
Cosa fare in caso di dati anomali o mancanti presenti nel dataset
Se nel dataset, durante le operazioni di verifica, compaiono dei dati anomali o mancanti, occorre
prendere delle precauzioni per evitare che succedano disastri nelle analisi statistiche.
Nel caso dei dati anomali è necessario provvedere alla correzione andando a recuperare o il
materiale cartaceo o i fogli usati per le prime annotazioni dei dati. Qualora i dati originali fossero,
per qualsiasi motivo, indisponibili, la strategia è escludere quel dato, trasformandolo al limite in
dato mancante. Si rischia però di perdere l’informazione.
Il dato mancante determina diversi problemi nelle analisi statistiche. I più frequenti sono
23
1. Difficoltà nel calcolare il punteggio intero del soggetto: se i dati mancanti sono troppi, ossia
se il soggetto risponde a pochi item, il punteggio intero, di solito dato dalla somma o dalla
media dei punteggi dei singoli item risulta fuorviante o distorto.
2. Difficoltà nel calcolare l’attendibilità delle risposte: i dati mancanti rendono problematico il
calcolo dell’attendibilità, soprattutto se si usa l’alpha di Cronbach.
3. Difficoltà nell’eseguire le analisi statistiche come la correlazione, la regressione e l’analisi
fattoriale. Se si hanno dati mancanti e non è possibile calcolare i punteggi interi, può
capitare che alcuni soggetti vengano esclusi in alcune correlazioni ma non in altre,
modificando i gradi di libertà dei test rendendoli, quindi, difficilmente comparabili.
Per i dati mancanti, esistono diverse strategie per ridurre i loro effetti sulle analisi statistiche, delle
quali le più diffuse sono:
1. Eliminazione dei soggetti con dati mancanti (listwise deletion). È la strategia più corretta,
ma c’è il rischio di eliminare troppi soggetti, riducendo la potenza del test. Il rischio di
compromettere le analisi aumenta enormemente soprattutto quando si hanno campioni con
pochi soggetti.
2. Sostituzione dei dati mancanti con la media dei valori per variabile o per soggetto
(replacement with mean). Un modo per ovviare al rischio di perdere i soggetti è quello di
sostituire i valori mancanti con la media per variabile (quando si devono calcolare un
punteggi interi al test o fare analisi correlazionali). Il limite particolare di questa procedura è
che la media rimpiazza il dato mancante, aumentando così i gradi di libertà, ma mantenendo
inalterata la variabilità dei dati. Il rischio è che si abbiano basse covarianze o correlazioni tra
variabili. Tuttavia esistono ricerche che dimostrano che se la percentuale dei dati mancanti,
sul totale dei dati, è inferiore al 20%, la sostituzione con la media non compromette
significativamente le analisi statistiche, in particolare l’analisi fattoriale.
3. Utilizzo di tecniche iterative per la stima dei valori mancanti. Sono le tecniche migliori e si
basano sull’uso di programmi che, partendo dai dati disponibili, effettuano una serie di stime
dei dati mancanti. Queste stime vengono verificate al fine di ottenere la stima che
maggiormente si approssima all’ipotetico valore reale. Queste procedure sono quelle che
garantiscono la maggior affidabilità nella determinazione dei dati mancanti, riducendo il
rischio di risultati distorti nei test statistici, però sono complesse e richiedono l’uso di
particolari programmi. Le due tecniche più note sono la tecnica basata sull’algortimo della
massimizzazione del dato atteso (l’Expected Maximization Algorithm) e la tecnica delle
imputazioni multiple (Multiple Imputation Technique).
Se i dati mancanti riguardano i punteggi ai test, occorre dire che alcuni di questi test hanno stabilito
delle regole precise per il loro trattamento. Ad esempio, il manuale del’MMPI-2 stabilisce che in
caso di un numero di risposte superiore a 30, non si possa fare alcuna analisi dei dati dei soggetti.
Altri test possono prevedere altre regole. Solitamente la regola più diffusa è escludere dalle analisi i
soggetti con più del 10% di dati mancanti. Tuttavia occorre consultare cosa consiglia di fare il
manuale del test psicologico per capire come trattare i dati mancanti, anche se, in genere, nessuno
vieta di seguire soluzioni alternative. Ad esempio se il manuale suggerisce di eliminare i soggetti
con più del 10% di dati mancanti, tuttavia è possibile usare un’altra procedura come la
massimizzazione del dato atteso o l’imputazione multipla per gestire i dati mancanti.
24
Nel caso si voglia sostituire i dati mancanti con le medie dei valori per colonna basta semplicemente
usare il comando “mean” sui dati per colonna. Ad esempio, voglio sostituire il dato mancante nella
seconda riga e nella quarta colonna di X con la media dei valori per colonna, per cui scrivo:
> X[2,3]<-mean(as.numeric(X$hap3),na.rm=TRUE)
Se si visualizza di nuovo il contenuto della matrice X si vedrà che ora al posto della cella vuota
compare il valore 4.36363636363636. Il comando “as.numeric” serve per trasformare i valori della
colonna in numeri (Se la cella è vuota automaticamente il programma trasforma tutti i valori della
colonna in caratteri. Questo non avviene se il valore mancante è indicato da NA, NaN o da un
numero convenzionale). Il comando “na.rm=TRUE” è necessario, dato che la funzione mean si
blocca se nell’array esiste anche un solo valore nullo.
La sostituzione dei dati mancanti con i valori medi per colonna si effettua di solito quando si deve
eseguire l’analisi fattoriale, perché l’analisi fattoriale richiede un elevato numero di soggetti e se ci
sono molti soggetti con dati mancanti la listwise deletion rischia di ridurre notevolmente la
grandezza campionaria. Occorre dire che tale tecnica è relativamente sicura solo se si ha un
percentuale di dati mancanti inferiore al 20%.
Se la matrice dati presenta dei valori mancanti ed occorre calcolare il punteggio globale del
soggetto al test, se il punteggio globale è dato dalla media dei valori, l’assenza di uno o più dati non
risulta problematica. Diventa problematica se il punteggio intero è dato dalla somma dei punteggi ai
singoli item, perché basta anche un solo dato mancante per alterare gli esiti delle analisi statistiche,
soprattutto se si tratta di correlazioni e regressioni. In questo caso converrebbe eliminare il soggetto.
La sostituzione delle medie per colonna non rappresenta al soluzione più idonea, dato che la media
è data dalla somma dei punteggi di tutti i soggetti per quella determinata variabile e, quindi, è
influenzata dalle risposte degli altri soggetti.
25
Analisi descrittive con RStudio
Una volta controllato il dataset e sistemato il problema dei dati mancanti, è possibile eseguire le
analisi statistiche.
Le analisi statistiche sono di due tipi: le analisi statistiche descrittive e le analisi statistiche
inferenziali. Solitamente per analisi descrittive ed inferenziali si intendono le statistiche eseguite
sullo specifico campione oppure l’uso delle caratteristiche statistiche del campione per fare
inferenze sulla popolazione da cui deriva il campione. In altri termini, le statistiche descrittive
servono per descrivere le caratteristiche del campione, verso quale valore tendono i valori del
campione (media) o la dispersione dei dati all’interno del campione (varianza). Le statistiche
inferenziali, invece, usano gli indici di tendenza centrale e di dispersione, ossia la media e la
varianza del campione per determinare la media e la varianza della popolazione da cui il campione è
stato estratto. La statistica inferenziale è utile, pertanto, per determinare i parametri (media e
varianza) della popolazione o per confrontare i parametri di popolazioni diverse. Ad esempio, se
ipotizzo una differenza nei parametri della popolazione maschile e femminile per quanto riguarda il
tratto di intelligenza o di estroversione o di autostima, tramite la statistica inferenziale, che si basa
sul calcolo dei parametri dei campione estratti dalle popolazioni di maschi e femmine, posso capire
se esiste o no una differenza nei parametri. Con il t di Student posso verificare se esiste una
differenza tra le medie delle due popolazioni. Con l’F test posso verificare se esiste una differenza
nella varianza delle due popolazioni (test dell’omogeneità della varianza).
La statistica descrittiva è utile soprattutto per comprendere se i dati del campione sono dati
affidabili oppure se presentano delle problematicità. Oltre alla media ed alla varianza altre
caratteristiche descrittive risultano importanti da analizzare come ad esempio l’asimmetria
(skewness) e la curtosi (kurtosis).
Prima di poter eseguire le analisi descrittive occorre far sapere che esiste un dataset elaborato
apposta per permettere l’esecuzione sia della analisi descrittive che inferenziali. Questo dataset è un
file excel nominato semplicemente “dataset”, Il dataset è disponibile sul sito
“www.psicometria,unich.it” in cui, cliccando sul link “programmi di studio”e selezionando il link
“EPG associati a Metodologia della Ricerca e Tecniche Multivariate di Analisi dei Dati” è possibile
scaricare il file. Oltre al dataset occorre scaricare il file “lista per dataset” che contiene una lista che
descrive il tipo e la natura delle variabili inserite nel file dataset. Il nome dei file è “Legenda di
dataset”.
Occorre far notare che il dataset così come viene caricato è in formato “tbl” (table). Occorre
trasformarlo in una altro formato, ad esempio in formato data frame, se il dataset contiene sia dati
numerici che stringhe, usando il comando “as.data.frame()”, altrimenti si rischia di non poter usare
quei comandi per le analisi statistiche che non supportano formati diversi da quelli base, come i
formati delle matrici e dei data frame.
Creando con il comando as.data.frame un secondo dataset, che chiameremo per semplicità
“dataset2” possiamo effettuare le prime analisi fondamentali:
26
1) Le analisi descrittive generali che servono per definire le caratteristiche dello specifico
campione di dati
2) Analisi di attendibilità, come l’alpha di Cronbach, per valutare quella serie di dati che
costituiscono le risposte soggettive a degli item o a delle variabili per verificare l’affidabilità
dei dati empirici.
Analisi descrittive di base
Lo script per eseguire le analisi descrittive, in questo caso il file è denominato “describe_data.R”, è
il seguente
descr<-function(X,Fatt){
library(psych)
if (Fatt[1] == 0){
ris<-describe(X,na.rm=TRUE)
} else {
ris<-describeBy(X, as.factor(Fatt),na.rm = TRUE)
}
#print(ris)
return(ris)
}#end function
La struttura dello script è molto semplice dato che il comando specifico per le analisi descrittive,
“describe”, è di per se un comando complesso.
Le prime 12 colonne di dataset2 contengono le risposte ad un test sulla felicità composto da 12
item. Il campione è composto da 204 soggetti. Quindi, selezionando le prime 12 colonne di dataset2
e assegnando i loro valori alla funzione otteniamo una matrice di statistiche descrittive per ciascuna
delle 12 variabili o item. Occorre far notare che lo script è stato progettato in modo da poter
calcolare le descrittive per tutto il campione di dati, oppure per calcolare le statistiche
specificatamente per sottocampioni di soggetti. Ad esempio, se il campione è composto da maschi e
femmine, allora si usa la variabile o fattore che stabilisce il sesso dei soggetti per eseguire le analisi
indipendentemente per i due gruppi.
Le statistiche descrittive ottenute con il comando describe sono le seguenti:
item name: il nome della variabile.
vars: il numero che identifica la singola variabile.
number of valid cases (n): il numero di soggetti validi (senza dati mancanti).
mean: la media dei valori.
standard deviation: la varianza dei valori (deviazione standard).
27
trimmed mean (with trim defaulting to .1) : la media dei valori escludendo i valori con
probabilità inferiore 0,1 o superiore a 0,99. Se tale media è molto diversa dalla media
normale significa che c’è un forte effetto degli outliers.
median: valore della mediana.
mad: deviazione media assoluta dalla mediana. È un indice di varianza, solo che è dato dalle
distanze dei punteggi dalla mediana.
Minimum: valore massimo.
Maximum: valore minimo.
Skew: asimmetria (skewness) dei valori.
Kurtosis: curtosi dei valori.
standard error: errore standard dei valori che indica la varianza della distribuzione
campionaria.
Per quanto riguarda le statistiche, occorre fare qualche precisazione. Solitamente nelle
pubblicazioni si riportano solo la media e la deviazione standard. Però ci sono altre statistiche che
consentono di capire se la distribuzione dei dati è normale o no. Alcune di queste sono gli indici di
asimmetria (skewness) e curtosi (kurtosis).
Senza entrare nei dettagli matematici, l’asimmetria misura quanto è asimmetrica la distribuzione dei
dati. Sappiamo che il modello ideale di distribuzione è la distribuzione gaussiana o normale. Tale
distribuzione è assolutamente simmetrica nel senso che i valori più basso o più alti rispetto alla
media sono entrambi il 50% dei dati totali. Se la distribuzione tende ad essere assi metrica, vuol dire
che i valori più bassi e quelli più alti tendono ad avere percentuali diverse dal 50%. In particolare,
se la percentuale di valori sotto la media supera quelli sopra la media, si ha asimmetria positiva. Se i
valori sopra la media superano quelli sotto la media, si ha asimmetria negativa. La figura seguente
mostra le distribuzioni simmetriche, con asimmetria positiva e con asimmetria negativa.
Le distribuzioni simmetriche hanno valori di asimmetria o skewness pari a zero. Le distribuzioni
con asimmetria positiva hanno valori maggiori di zero, mentre le distribuzioni con asimmetria
negativa hanno valori minori di zero. Se una distribuzione ha valori di skewness superiori o inferiori
a zero, possono sorgere dei problemi nelle analisi statistiche. Solitamente valori di skewness
superiori a 2 o inferiori a -2 sono considerati problematici. Gli effetti negativi più rilevanti
dell’asimmetria sono:
1. Problemi nell’interpretazione degli indici di tendenza centrale (moda, mediana e media) dato
che nelle distribuzioni asimmetriche tendono a divergere, come si vede nella figura
precedente;
28
2. alterazione dei cutoff, che aumentano o diminuiscono a seconda che la skewness sia positiva
o negativa;
3. effetti sulla potenza dei test statistici con il rischio di aumentare il numero di falsi positivi o
di falsi negativi nei test.
La curtosi, invece, descrive il tipo di varianza della distribuzione di dati. Esistono tre tipi di curtosi:
la leptocurtosi, la mesocurtosi e la platicurtosi. La distribuzione gaussiana è mesocurtotica, ossia ha
la classica forma a campana. Se questa campana tende a rigonfiarsi e a dilatarsi, abbiamo la
distribuzione platicurtotica. Se la campana tende a restringersi e a innalzarsi al centro abbiamo la
distribuzione leptocurtotica. La figura seguente mostra le distribuzioni con i tre tipi di curtosi.
I valori accettabili di curtosi, così come quelli dell’asimmetria, sono inclusi tra -2 e 2. Se i valori di
curtosi sono inferiori a zero, significa che la distribuzione tende ad essere platicurtotica (ad
appiattirsi). Se sono superiori a zero, la distribuzione tende ad essere leptocurtotica (a restringersi).
Se la curtosi è eccessivamente positiva o negativa, si possono avere problemi nelle analisi
statistiche. Tra i più rilevanti citiamo:
1. Le distribuzioni con curtosi anomale possono alterare i valori di significatività dei test
statistici;
2. Le distribuzioni con curtosi anomale possono indicare la presenza di outliers, ossia di
soggetti che danno valori estremamente anomali e che alterano la stima dei parametri della
popolazione;
3. Le distribuzioni con curtosi anomale hanno effetti negativi sulle correlazioni tra le variabili
e possono alterare i test basati sui modelli di equazioni strutturali (usati in analisi fattoriale).
Vediamo ora gli esiti delle analisi descrittive sulle dati riportati nelle prime 12 colonne di dataset2.
Nella console di RStudio scriviamo i comandi per caricare (source) ed eseguire lo script (descr) ed
otteniamo:
> source('D:/MT documents 2/R works/descrittive/describe_data.R')
> descr(dataset2[,1:12],0)
vars n mean sd median trimmed mad min max range skew kurtosis se
hap1 1 204 3.54 1.23 4 3.66 1.48 1 5 4 -0.60 -0.61 0.09
hap2 2 204 3.81 1.09 4 3.94 1.48 1 5 4 -0.84 0.08 0.08
hap3 3 204 4.13 0.94 4 4.27 1.48 1 5 4 -1.11 0.92 0.07
hap4 4 204 3.63 1.31 4 3.79 1.48 1 5 4 -0.76 -0.51 0.09
29
hap5 5 204 3.60 0.94 4 3.65 1.48 1 5 4 -0.40 0.11 0.07
hap6 6 204 4.40 0.86 5 4.55 0.00 1 5 4 -1.54 2.39 0.06
hap7 7 204 3.71 1.07 4 3.81 1.48 1 5 4 -0.75 -0.04 0.08
hap8 8 204 3.99 1.07 4 4.15 1.48 1 5 4 -1.21 1.22 0.07
hap9 9 204 2.82 1.44 3 2.78 1.48 1 5 4 0.19 -1.27 0.10
hap10 10 204 3.54 1.08 4 3.59 1.48 1 5 4 -0.29 -0.72 0.08
hap11 11 204 4.31 0.81 4 4.44 1.48 1 5 4 -1.44 2.89 0.06
hap12 12 204 3.74 1.42 4 3.91 1.48 1 5 4 -0.91 -0.58 0.10
Occorre fare notare che nelle parentesi tonde oltre a scrivere la matrice o sub matrice di dati
(dataset2[,1:12]), abbiamo anche inserito uno zero perché questo valore serva a far capire al
programma che le analisi devono essere fatte sull’intero campione di soggetti che, in tutto, sono
204.
Analizzando l’output, possiamo subito evidenziare alcune caratteristiche della nostra distribuzione
di dati. I 12 item del test della felicità tendono ad avere punteggi alti. Infatti il valore centrale della
scala è 3, però osserviamo che quasi tutte le medie e tutte le mediane sono maggiori di tre (escluso
l’item hap9). Inoltre, quasi tutte le asimmetria sono negative, ciò indica che i valori sopra la media
sono più frequenti di quelli sotto la media. Tale tendenza è indicata anche dal fatto che le mediane
sono sempre superiori alle medie. Tutti i valori di asimmetria sono compresi tra -2 e 2. Per quanto
riguarda le curtosi, invece, si scopre che metà sono positive e metà sono negative, e per due item
abbiamo valori di curtosi superiori a 2 (hap6 e hap11). Questo è spiegabile con il fatto che i
punteggi in questi due item tendono a concentrarsi tutti nell’estremità alta della scala. Infatti sia
hap6 che hap11 hanno mediane che coincidono con i valori più alti della scala (5 e 4,
rispettivamente). Anche se sono alti, i valori di curtosi non indicano che i dati dei due item siano
inutilizzabili, sebbene abbiano una distribuzione fortemente diversa da quella normale.
Se vogliamo eseguire le analisi descrittive separatamente per i maschi e le femmine, allora
dobbiamo scrivere:
> descr(dataset2[,1:12],dataset$gender)
Nella funzione questa volta, al posto dello zero, abbiamo inserito la variabile fattore che è:
dataset$gender , che specifica i soggetti di sesso maschile o femminile. Otteniamo, quindi, due
output separati, uno per il gruppo di maschi e l’altro per il gruppo di femmine:
Descriptive statistics by group
group: 1
vars n mean sd median trimmed mad min max range skew kurtosis se
hap1 1 107 3.51 1.28 4 3.63 1.48 1 5 4 -0.64 -0.65 0.12
hap2 2 107 3.96 1.04 4 4.10 1.48 1 5 4 -0.98 0.40 0.10
hap3 3 107 4.26 0.82 4 4.38 1.48 2 5 3 -1.02 0.59 0.08
hap4 4 107 3.70 1.21 4 3.85 1.48 1 5 4 -0.77 -0.26 0.12
hap5 5 107 3.76 0.84 4 3.79 1.48 1 5 4 -0.45 0.12 0.08
hap6 6 107 4.53 0.73 5 4.67 0.00 2 5 3 -1.33 0.69 0.07
hap7 7 107 3.84 0.94 4 3.94 1.48 1 5 4 -0.82 0.40 0.09
hap8 8 107 4.17 0.90 4 4.28 1.48 1 5 4 -1.11 1.35 0.09
hap9 9 107 2.93 1.46 3 2.92 1.48 1 5 4 0.13 -1.37 0.14
hap10 10 107 3.77 0.93 4 3.83 1.48 2 5 3 -0.23 -0.87 0.09
30
hap11 11 107 4.45 0.66 5 4.54 0.00 2 5 3 -0.97 0.59 0.06
hap12 12 107 3.80 1.36 4 3.99 1.48 1 5 4 -0.95 -0.43 0.13
-------------------------------------------------------------------------------
--------
group: 2
vars n mean sd median trimmed mad min max range skew kurtosis se
hap1 1 97 3.58 1.19 4 3.67 1.48 1 5 4 -0.51 -0.67 0.12
hap2 2 97 3.64 1.13 4 3.75 1.48 1 5 4 -0.69 -0.21 0.11
hap3 3 97 3.99 1.05 4 4.14 1.48 1 5 4 -1.01 0.45 0.11
hap4 4 97 3.56 1.41 4 3.68 1.48 1 5 4 -0.70 -0.84 0.14
hap5 5 97 3.43 1.02 3 3.48 1.48 1 5 4 -0.23 -0.07 0.10
hap6 6 97 4.25 0.97 5 4.41 0.00 1 5 4 -1.46 2.03 0.10
hap7 7 97 3.56 1.19 4 3.66 1.48 1 5 4 -0.57 -0.57 0.12
hap8 8 97 3.78 1.20 4 3.96 1.48 1 5 4 -1.05 0.39 0.12
hap9 9 97 2.70 1.41 3 2.63 1.48 1 5 4 0.24 -1.19 0.14
hap10 10 97 3.30 1.18 3 3.33 1.48 1 5 4 -0.10 -0.95 0.12
hap11 11 97 4.15 0.93 4 4.29 1.48 1 5 4 -1.39 2.28 0.09
hap12 12 97 3.66 1.49 4 3.81 1.48 1 5 4 -0.83 -0.80 0.15
Il gruppo 1 è composto da 107 soggetti femminili, mentre il gruppo 2 è composto da 97 soggetti
maschili. Osserviamo che i valori delle medie, delle varianze, delle mediane e di tutte le altre
statistiche descrittive sono diversi da un gruppo all’altro. Inoltre rileviamo che le curtosi degli item
hap6 e hap11 tendono ad essere alte (>2) nei maschi, ma nella norma per le femmine.
Rappresentazione grafica dei dati
Esistono vari modi per rappresentare i dati con i grafici. Qui ne verranno presentati alcuni che
possono essere utili.
I grafici in RStudio vengono stampati all’interno della finestra “Plots”. Cliccando sul pulsante
il programma crea una nuova finestra più ampia che permette una migliore
visualizzazione del grafico. Dalla finestra zoom il grafico può essere copiato e inserito dentro un
file testo cliccando sul pulsante destro del mouse.
Il comando “pairs.panel”
Tale comando consente di rappresentare sia la variabilità di una serie di variabili che la loro
correlazione con altre variabili. Se si selezionano, ad esempio, 3 variabili, il comando genera una
finestra con 9 grafici, disposti a scacchiera. Nei 3 grafici lungo la diagonale principale viene
visualizzata la distribuzione di frequenza dei singoli valori della variabile sottoforma sia di
istogramma che di curva di densità. Nel triangolo inferiore della scacchiera viene visualizzato il
diagramma di dispersione della variabile con le altre variabili. Il diagramma rappresenta la
correlazione dei valori della variabile con i valori delle altre variabili. I circoli neri indicano i dati
empirici. Il programma disegna una linea rossa che passa attraverso i circoli e che rappresenta la
tendenza lineare dei dati, ossia se i dati della prima variabile tendono ad essere positivamente o
31
negativamente correlati con quelli della seconda variabile. Se c’è una correlazione positiva, la linea
ha inclinazione o pendenza positiva; se c’è una correlazione negativa, la linea ha inclinazione o
pendenza negativa. Il punto rosso indica il centro della distribuzione di dati e, attorno ad esso,
compare un’ellisse che rappresenta la zona di maggior concentrazione dei datti. L’ellisse serve per
delineare meglio l’andamento delle varianze delle due variabili. I riquadri del triangolo superiore
della scacchiera riportano solo i valori numerici della correlazione tra le variabili.
Ad esempio, se vogliamo rappresentare la correlazione tra gli item hap1, hap2 e hap2 di dataset2,
che sono i prime 3 item del test sulla felicità, basta scrivere:
> pairs.panels(dataset2[,1:3])
E, nella finestra Plots, apparirà il seguente grafico a scacchiera:
Il comando pairs.panels è incluso nel pacchetto psych.
Varianza delle variabili
Diagrammi di
dispersione
Correlazioni
numeriche
32
Il comando “boxplot”
Tale comando consente di creare un grafico, il box-and-whisker plot6, che è una utile
rappresentazione dell’andamento della distribuzione dei dati. Il grafico è composto da un rettangolo
che indica l’area dei punteggi tra il primo e terzo quartile (25% e 75% percentile, rispettivamente)
in cui si ha il 50% dei dati, da una linea con, alle estremità, due barre a T, che rappresenta
l’estensione dei valori in cui si ha il 95% dei punteggi (5% e 95% percentile) ed, eventualmente, da
una serie di simboli che rappresentano gli outliers, ossia i soggetti con punteggi estremi o fuori
scala. All’interno del rettangolo viene disegnata una linea spessa che rappresenta la mediana della
distribuzione dei punteggi. Il comando boxplot può essere eseguito su una singola variabile. Se i
valori della variabile sono suddivisibili in diversi sottogruppi, allora si usa una funzione “Y ~
Group” dove Y rappresenta i valori di cui si vuole la distribuzione e Group è la variabile fattore che
consente di riportare i vari diagrammi per ciascun gruppo.
Ad esempio, se voglio conoscere le caratteristiche della distribuzione dei punteggi suddivise per
maschi e femmine, allora scrivo:
> boxplot(dataset2$happines~dataset2$gender,las=1)
in cui la variabile dataset2$gender rappresenta i livelli del fattore sesso e la variabile
dataset2$happines è il punteggio totale al test sulla felicità (maggiore è il punteggio, maggiore
il livello di felicità) L’output del grafico è:
6 In italiano è definito diagramma a scatola e baffi o diagramma degli estremi e dei quartili.
95% percentile
5% percentile
25% percentile
75% percentile
50% percentile
(mediana)
outlier
33
I valori 1 sull’asse orizzontale indicano le femmine ed i valori 2 i maschi. Il comando boxplot è
incluso nel pacchetto graphics.
Il comando “barplot”
Il comando barplot è utile per rappresentare la frequenza o la probabilità di determinate categorie o
livelli di fattori. Ad esempio, può essere utile per rappresentare visivamente il numero di maschi e
femmine, il numero dei soggetti con titoli di studio diversi, il numero di persone che fanno
determinate professioni, ecc. Ad esempio, se vogliamo sapere quanti soggetti nel nostro dataset
sono maschi e femmine (la variabile è dataset2$gender), allora scriviamo:
> barplot(table(dataset2$gender),names.arg=c("femmine","maschi"),las=1)
Il comando “table” serve per conteggiare quanti soggetti abbiamo nella categoria maschile e quanti
in quella femminile. Il comando “names.arg” serve per definire il nome della categorie ed il
comando “las” per rappresentare orizzontalmente i dati numerici del grafico. L’output visivo è:
Sull’asse verticale sono riportate le frequenze, ossia il numero di soggetti per categoria, Se
vogliamo riportare le proporzioni (valori da 0 a 1), doppiamo usare il comando “prop.table”. Questo
comando trasforma l’output di table in valori proporzionali (da 0 ad 1) più facili da interpretare in
termini di numerosità relativa. Creiamo una variabile con i valori proporzionali, che chiameremo
“tab.p”:
> tab.p<- prop.table(table(dataset2$gender))
34
Ora possiamo stampare gli istogrammi che rappresentano le proporzioni di soggetti per categoria:
Il comando barplot è incluso nel pacchetto graphics.
Stima dell’attendibilità
L’attendibilità dei dati serve per stabilire se le risposte fornite dai soggetti sono affidabili o no. Gli
indici di attendibilità sono importanti perché se le risposte dei soggetti non sono affidabili, allora
anche le analisi statistiche forniranno risultati distorti.
Solitamente, l’affidabilità si basa sull’omogeneità delle risposte del soggetto. Nel caso di risposte a
test e questionari, l’omogeneità si verifica se il soggetto tende a dare, più o meno, gli stessi punteggi
a ciascun item. Nel caso della ricerca in laboratorio, l’affidabilità si può misurare se al soggetto si
chiedere di ripetere più volte la risposta. Ad esempio, se il compito del soggetto è quello di valutare
il livello di chiarezza di alcune superfici, allora tali superfici dovrebbero essere presentate
ripetutamente più volte allo stesso soggetto, in modo da avere più risposte per ogni stimolo.
Confrontando tra di loro queste risposte è possibile verificare se il soggetto ha dato risposte valide o
no.
Nel nostro caso possiamo sempre usare i dati di dataset2 relativi ai 12 item del test della felicità per
verificare l’attendibilità delle risposte. Creiamo uno script dl nome “reliability” e denominando la
funzione “rel”. La figura seguente mostra la struttura dello script.
rel<-function(M){
library(psych)
dd<-dim(M)
etich<-colnames(M)
35
ris<-alpha(M,check.keys=TRUE,na.rm=TRUE)
output<-list("alpha p. grezzi" = ris$total$raw_alpha,"alpha p. stand" =
ris$total$std.alpha,
"alpha se l'item è rimosso" =
cbind(etich,ris$item.stats$n,round(ris$alpha.drop$raw_alpha,digits=3)))
print.noquote("")
print.noquote("-------------------------------------------------------------
------------")
print.noquote("calcolo dell'alpha di Cronbach e del valore di alpha se
l'item è rimosso")
print(output)
capture.output(CI.a<-alpha.ci(ris$total$raw_alpha,dd[1]))
ris2<-c(CI.a$lower.ci,CI.a$upper.ci)
print.noquote("------------------------------------------------------")
print.noquote("calcolo dell'intervallo di confidenza di alpha (95%)")
print(ris2,digits=3)
}#end function
Osserviamo che dentro lo script esiste il comando “library” che serve per attivare i comandi
contenuti nel pacchetto “psych”. Infatti il comando per calcolare l’attendibilità, il comando “alpha”,
così come il precedente comando “describe” sono contenuti nel pacchetto psych, per cui se questo
pacchetto non è stato installato prima dell’esecuzione delle analisi il programma darà un messaggio
di errore che, semplicemente, avvisa che non trova al funzione indicata nello script.
Il comando alpha consente di calcolare l’alpha di Cronbach così come di eseguire tutta una serie di
operazioni. All’interno della funzione alpha, oltre ad aver specificato la matrice di dati in input, M,
sono stati inseriti alcuni parametri. Il comando “check.keys = TRUE” serve per poter calcolare
l’alpha di Cronbach anche quando il dataset contiene item i cui valori sono invertiti. Occorre dire
che, prima di calcolare l’alpha di Cronbach, se il questionario prevede item con punteggi invertiti è
assolutamente necessario correggerli re-invertendoli in modo da evitare problemi nella stima
dell’attendibilità A volte, però, succede che per qualche motivo i punteggi di alcuni item risultino
invertiti anche se non esistono all’interno del test item con punteggi invertiti. In questo caso il
problema può esser dovuto ad un’anomalia nella distribuzione dei punteggi. Di default, il valore
logico di chek.key è posizionato su FALSE. Tuttavia conviene porlo sempre a TRUE, dato che può
sempre comparire un’anomalia dai dati. Il comando “na.rm = TRUE” serve per rimuovere i dati
mancanti dall’analisi. L’eliminazione è di tipo listwise, nel senso che si rimuovono dall’analisi i
soggetti con dati mancanti.
Vediamo ora, applicando lo script “reliability” cosa si ottiene. Se si osserva, nello script esiste una
variabile definita “output” che serve per selezionare alcune componenti dalla variabile risultato
“ris”. Come abbiamo detto, il comando alpha effettua molte analisi e quindi genera un output
complesso. Perciò conviene selezionare gli elementi da presentare nell’output. Che cosa conviene
presentare? Gli elementi che conviene visualizzare sono:
1. ris$total$raw_alpha: tale comando riporta il valore di alpha per i dati grezzi;
2. ris$total$std.alpha: il comando riporta il valore di alpha per i dati trasformati in punteggi
standardizzati (con varianza pari ad 1);
36
3. cbind(etich,ris$item.stats$n,round(ris$alpha.drop$raw_alpha,digits=3))): questo commando
crea una matrice in cu nell prima colonna sono riportati I nomi degli item o delle variabili
(etich), nella seconda colonna il numero di osservazioni valide o di soggetti
(ris$item.stats$n), nella terza colonna la variazione del valore di alpha se l’item dovesse
essere rimosso dal test (ris$alpha.drop$raw_alpha).
Il fatto di stampare una matrice in cui per ogni item si calcola l’alpha di Cronbach è utile per
cercare di capire quanto l’item è importante nel determinare la validità del questionario. Se,
eliminando l’item, si osserva una notevole riduzione del valore di alpha, ciò significa che quell’item
fornisce un importante contributo nel determinare la validità del test. Se, al contrario, rimuovendo
l’item si osserva un incremento del valore di alpha, ciò significa che quell’item sta riducendo la
validità delle risposte al test. Quindi gli item che danno valori di alpha, una volta che sono stati
rimossi, più basso del valore di alpha al test intero, danno un contributo positivo alla validità del
test; quelli che hanno valori di alpha più alti danno un contributo negativo.
Oltre alla funzione per il calcolo di alpha c’è la funzione per la stima dell’intervallo di confidenza
“alpha.ci”. Di default, questa funzione calcola l’intervallo di valori alpha all’interno del quale si ha
il 95% di trovare il vero valore di attendibilità. L’utilità di tale funzione sta soprattutto nel fatto che
fornisce un’ulteriore informazione sulla validità delle risposte dei soggetti. Infatti, se l’intervallo di
confidenza si mantiene entro valori alti, allora si ha sicurezza della validità del test. La tabella
seguente mostra come interpretare i valori di alpha del test, secondo le direttive fornite dallo
psicometrista Paul Kline:
Livelli di alpha di Cronbach e loro intepretazione
α ≥ 0.9 Excellent (High-Stakes testing)
0.7 ≤ α < 0.9 Good (Low-Stakes testing)
0.6 ≤ α < 0.7 Acceptable
0.5 ≤ α < 0.6 Poor
α < 0.5 Unacceptable
Fonte: Kline, P. (2000). The handbook of psychological testing (2nd ed.). London: Routledge, pag.
13.
In poche parole un buon test dovrebbe avere un valore alpha superiore a 0,70 (test buono o
eccellente). Valori tra 0,60 e 0,70 sono accettabili, però valori inferiori a 0,60 indicano che il test è
poco attendibile. Valori inferiori a 0,50 indicano che il test non funziona proprio.
Vediamo ora cosa otteniamo usando sempre i punteggi di dataset2 per quanto riguarda
l’attendibilità dei punteggi usando lo script reliability. Scrivendo:
> source('D:/MT documents 2/R works/meto 2018/reliability.R')
> rel(dataset2[,1:12])
Otteniamo il seguente output:
37
[1]
[1] -------------------------------------------------------------------------
[1] calcolo dell'alpha di Cronbach e del valore di alpha se l'item è rimosso
$`alpha p. grezzi`
[1] 0.839349
$`alpha p. stand`
[1] 0.8532927
$`alpha se l'item è rimosso`
etich
[1,] "hap1" "204" "0.833"
[2,] "hap2" "204" "0.829"
[3,] "hap3" "204" "0.825"
[4,] "hap4" "204" "0.826"
[5,] "hap5" "204" "0.821"
[6,] "hap6" "204" "0.83"
[7,] "hap7" "204" "0.824"
[8,] "hap8" "204" "0.823"
[9,] "hap9" "204" "0.843"
[10,] "hap10" "204" "0.825"
[11,] "hap11" "204" "0.822"
[12,] "hap12" "204" "0.825"
[1] ------------------------------------------------------
[1] calcolo dell'intervallo di confidenza di alpha (95%)
[1] 0.807 0.869
Il valore di alpha dell’intero test sulla felicità è pari a 0,84, un valore buono. L’intervallo di
confidenza è compreso tra 0,81 e 0,87, quindi sia i limiti inferiori e superiori di alpha sono buoni.
Per quanto riguarda la variazione dell’alpha se gli item vengono rimossi, si osserva che solo la
rimozione dell’item hap9 determina un incremento del valore alpha (0,843). L’incremento è, però,
molto lieve.
Possiamo effettuare l’analisi di attendibilità specifica per i due gruppi di maschi e femmine.
Occorre però selezionare i soggetti di sesso maschile o femminile prima di assegnare la matrice di
dati alla funzione. Un modo piuttosto semplice è usare il comando “which()”. Con tale comando
selezioniamo le righe di dati che corrispondono ad uno specifico valore. Usando la variabile
dataset2$gender, che assume valore 1 per i soggetti femminili e 2 per quelli maschili, allora
ponendo:
> p<-which(dataset2$gender==1)
Inseriamo in p i numeri di riga corrispondenti ai soggetti di sesso femminile. Per calcolare l’alpha di
Cronbach specifico per i soggetti femminili, usiamo sempre lo script reliability scrivendo:
> rel(dataset2[p,1:12])
ed otteniamo il seguente output:
38
[1]
[1] -------------------------------------------------------------------------
[1] calcolo dell'alpha di Cronbach e del valore di alpha se l'item è rimosso
$`alpha p. grezzi`
[1] 0.5920279
$`alpha p. stand`
[1] 0.7077781
$`alpha se l'item è rimosso`
etich
[1,] "hap1" "107" "0.655"
[2,] "hap2" "107" "0.528"
[3,] "hap3" "107" "0.529"
[4,] "hap4" "107" "0.648"
[5,] "hap5" "107" "0.497"
[6,] "hap6" "107" "0.557"
[7,] "hap7" "107" "0.504"
[8,] "hap8" "107" "0.503"
[9,] "hap9" "107" "0.669"
[10,] "hap10" "107" "0.492"
[11,] "hap11" "107" "0.549"
[12,] "hap12" "107" "0.646"
[1] ------------------------------------------------------
[1] calcolo dell'intervallo di confidenza di alpha (95%)
[1] 0.475 0.694
Warning message:
In alpha(M, check.keys = TRUE, na.rm = TRUE) :
Some items were negatively correlated with total scale and were automatically
reversed.
This is indicated by a negative sign for the variable name.
Notiamo subito un messaggio d’avviso in rosso. Il programma ha individuato degli item con
punteggi invertiti. È riuscito lo stesso a calcolare il valore di alpha re-invertendo i punteggi di tali
item, tuttavia è chiaro che qualcosa non è andato per il verso giusto nelle risposte di questi soggetti.
Inoltre osserviamo che il valore di alpha è basso essendo uguale a 0,59 e l’intervallo di confidenza
varia da 0,48 e 0,69, sotto il valore di 0,70. Le risposte dei soggetti non sono buone e si rileva che ci
sono ben quattro item (hap1, hap4, hap9 e hap12) la cui rimozione determinerebbe un incremento
dell’attendibilità.
Se adesso selezioniamo i dati per i soggetti maschili scrivendo:
> p<-which(dataset2$gender==2)
otteniamo:
[1]
[1] -------------------------------------------------------------------------
[1] calcolo dell'alpha di Cronbach e del valore di alpha se l'item è rimosso
$`alpha p. grezzi`
[1] 0.8792781
39
$`alpha p. stand`
[1] 0.8876025
$`alpha se l'item è rimosso`
etich
[1,] "hap1" "97" "0.87"
[2,] "hap2" "97" "0.867"
[3,] "hap3" "97" "0.866"
[4,] "hap4" "97" "0.871"
[5,] "hap5" "97" "0.866"
[6,] "hap6" "97" "0.872"
[7,] "hap7" "97" "0.867"
[8,] "hap8" "97" "0.868"
[9,] "hap9" "97" "0.882"
[10,] "hap10" "97" "0.868"
[11,] "hap11" "97" "0.866"
[12,] "hap12" "97" "0.872"
[1] ------------------------------------------------------
[1] calcolo dell'intervallo di confidenza di alpha (95%)
[1] 0.843 0.911
Nel caso dei soggetti maschili le risposte agli item sono buone dato che il valore di alpha è pari a
0,88, gli estremi dell’intervallo di confidenza sono 0,84 e 0,91. L’unico item che sembra un po’
problematico è l’item hap9, la cui rimozione determinerebbe un incremento di alpha fino a 0,882,
però si tratta sempre di un incremento molto lieve.