26. Dati mancanti#

Raramente un ricercatore si trova nella situazione fortunata nella quale un’analisi statistica (di tipo CFA o altro) può essere condotta utilizzando un set di dati in cui tutte le variabili sono state osservate su tutte le unità statistiche: nella pratica ricerca i dati mancanti sono la norma piuttosto che l’eccezione.

26.1. Tipologie di dati mancanti#

Ci sono molti motivi che possono stare alla base dei dati mancanti. Ad esempio, i dati possono mancare per disegno dello studio (“mancanza pianificata”), come ad esempio nei progetti di ricerca in cui i partecipanti al campione vengono selezionati casualmente per completare sottoinsiemi diversi della batteria di valutazione (una scelta di questo tipo viene motivata, ad esempio, a causa di considerazioni pratiche come i vincoli di tempo). In tali condizioni, si presume che i dati mancanti si distribuiscano in un modo completamente casuale rispetto a tutte le altre variabili nello studio.

In generale, i meccanismi che determinano la presenza di dati mancanti possono essere classificati in tre categorie:

  1. valori mancanti completamente casuali (Missing Completely At Random, MCAR). La probabilità di dati mancanti su una variabile non è collegata né al valore mancante sulla variabile, né al valore di ogni altra variabile presente nella matrice dati che si sta analizzando;

  2. valori mancanti casuali (Missing At Random, MAR). I valori mancanti sono indipendenti dal valore che viene a mancare, ma dipendono da altre variabili, cioè i dati sulla variabile sono mancanti per categorie di partecipanti che potrebbero essere identificati dai valori assunti dalle altre variabili presenti nello studio;

  3. valori mancanti non ignorabili (Missing Not At Random, MNAR). La mancanza di un dato può dipendere sia dal valore del dato stesso che dalle altre variabili. Per esempio, se si studia la salute mentale e le persone depresse riferiscono meno volentieri informazioni riguardanti il loro stato di salute, allora i dati non sono mancanti per caso.

26.2. La gestione dei dati mancanti#

Il passo successivo dopo la definizione dei meccanismi è quello della gestione dei dati mancanti. Sostanzialmente le scelte possibili sono due: l’eliminazione dei casi o la sostituzione dei dati mancanti. Un metodo semplice, indicato solo nel caso in cui l’ammontare dei dati mancanti è limitato e questi sono mancanti completamente a caso (MCAR), è quello di cancellare i casi con dati mancanti (case deletion).

I modi per eliminare i casi sono due: listwise deletion e pairwise deletion. Nel primo caso si elimina dal campione ogni caso che ha dati mancanti. Le analisi avverranno quindi solo sui casi che hanno valori validi per tutte le variabili in esame. In questo modo si ottiene una maggiore semplicità di trattazione nell’analisi statistica, tuttavia non si utilizza tutta l’informazione osservata (si riduce la numerosità campionaria e, quindi, l’informazione). Il secondo metodo è la* pairwise deletio*n, che utilizza tutti i casi che hanno i dati validi su due variabili volta per volta. In questo modo si riesce a massimizzare la numerosità del campione da utilizzare, ma si tratta comunque di un metodo che presenta dei problemi, per esempio il fatto che con questo approccio i parametri del modello saranno basati su differenti insiemi di dati, con differenti numerosità campionarie e differenti errori standard.

Quando i dati non sono MNAR è opportuno sostituirli con appropriate funzioni dei dati effettivamente osservati. Questa procedura è chiamata imputazione (imputation). Di seguito sono indicati alcuni metodi.

  1. Mean Imputation. Il dato mancante viene sostituito con la media della variabile. Questo metodo, utilizzato troppo spesso per la sua semplicità, riducendo la variabilità dei dati, ha invece effetti importanti su molte analisi dei dati e, in generale, dovrebbe essere evitato.

  2. Regression Imputation. Si tratta di un approccio basato sulle informazioni disponibili per le altre variabili. Si stima una equazione di regressione lineare per ogni variabile utilizzando le altre come predittori. Questo metodo offre il vantaggio di poter utilizzare dei rapporti esistenti tra le variabili per effettuare le valutazioni dei dati mancanti; tuttavia esso è usato raramente, in quanto amplifica i rapporti di correlazione tra le variabili; quindi, se le analisi si baseranno su regressioni, questo metodo è sconsigliato.

  3. Multiple Imputation. La tecnica di multiple imputation, applicabile in caso di MAR, prevede che un dato mancante su una variabile sia sostituito, sulla base dei dati esistenti anche sulle altre variabili, con un valore che però comprende anche una componente di errore ricavata dalla distribuzione dei residui della variabile.

  4. Expectation-Maximization. Un altro approccio moderno del trattamento dei dati mancanti è l’applicazione dell’algoritmo Expectation Maximization (EM). La tecnica è quella di stimare i parametri sulla base dei dati osservati, e di stimare poi i dati mancanti sulla base di questi parametri (fase E). Poi i parametri vengono nuovamente stimati sulla base della nuova matrice di dati (fase M), e così via. Questo processo viene iterato fino a quando i valori stimati convergono. Tuttavia, una limitazione fondamentale dell’utilizzo dell’algoritmo EM per calcolare le matrici di input per le analisi CFA/SEM è che gli errori standard risultanti delle stime dei parametri non sono consistenti. Pertanto, gli intervalli di confidenza e i test di significatività possono risultare compromessi.

26.2.1. Metodo Direct ML#

Benché vengano talvolta usati, i metodi precedenti sono stati presentati solo per ragioni storiche. Nella pratica concreta è preferibile usare il metodo Direct ML, conosciuto anche come “raw ML” o “full information ML” (FIML), in quanto è generalmente considerano come il metodo migliore per gestire i dati mancanti nella maggior parte delle applicazioni CFA e SEM. Direct ML è esente dai problemi associati all’utilizzo dell’algoritmo EM e produce stime consistenti sotto l’ipotesi di normalità multivariata per dati mancanti MAR.

Intuitivamente, l’approccio utilizza la relazione tra le variabili per dedurre quali siano i valori mancanti con maggiore probabilità. Ad esempio, se due variabili, \(X\) e \(Y\), sono correlate positivamente, allora se, per alcune osservazioni \(i\), \(X_i\) è il valore più alto nella variabile, è probabile che anche il valore mancante \(Y_i\) sia un valore alto. FIML utilizza queste informazioni senza procedere all’imputazione dei valori mancanti, ma invece basandosi sulle stime più verosimili dei parametri della popolazione, ovvero massimizzando direttamente la verosimiglianza del modello specificato. Sotto l’assunzione di normalità multivariata, la funzione di verosimiglianza diventa

\[ L(\mu, \Sigma) = \prod_i f(y_i \mid \mu_i, \Sigma_i), \]

laddove \(y_i\) sono i dati, \(\mu_i\) e \(\Sigma_i\) sono i parametri della popolazione se gli elementi mancanti in \(y_i\) vengono rimossi. Si cercano i valori \(\mu\) e \(\Sigma\) che massimizzano la verosimiglianza.

In lavaan l’applicazione di tale metodo si ottiene specificando l’argomento missing = "ml".

26.2.2. Un esempio concreto#

Per applicare il metodo direct ML, brown2015confirmatory prende in esame i dati reali di un questionario (un singolo fattore, quattro item, una covarianza di errore) con dati mancanti (N = 650). Leggiamo i dati dell’esempio:

d <- rio::import("./data//brown_table_9_1.csv")
head(d)
A data.frame: 6 × 5
subjects1s2s3s4
<int><int><int><int><int>
15760201NA
25761333NA
35763244NA
45761200NA
55769211NA
65771433NA

Il modello viene specificato come segue brown2015confirmatory:

model <- '
  esteem =~ s1 + s2 + s3 + s4
  s2 ~~ s4
'

Adattiamo il modello ai dati:

fit <- cfa(model, data = d, missing = "fiml")

È possibile identificare le configurazioni di risposte agli item che contengono dati mancanti:

fit@Data@Mp[[1]]$npatterns
5
pats <- fit@Data@Mp[[1]]$pat * 1L
colnames(pats) <- fit@Data@ov.names[[1]]
print(pats)
     s1 s2 s3 s4
[1,]  1  1  1  1
[2,]  1  1  1  0
[3,]  0  1  1  1
[4,]  1  0  1  1
[5,]  1  1  0  1

Possiamo ora esaminare il livello di copertura della covarianza nei dati, ovvero la proporzione di dati disponibili per ciascun indicatore e per ciascuna coppia di indicatori:

coverage <- fit@Data@Mp[[1]]$coverage
colnames(coverage) <- rownames(coverage) <- fit@Data@ov.names[[1]]
print(coverage)
          s1        s2        s3        s4
s1 0.9615385 0.9230769 0.9230769 0.6692308
s2 0.9230769 0.9615385 0.9230769 0.6692308
s3 0.9230769 0.9230769 0.9615385 0.6692308
s4 0.6692308 0.6692308 0.6692308 0.7076923

Ad esempio, consideriamo l’item s1; se moltiplichiamo la copertura di questo elemento per la numerosità campionaria possiamo concludere che questa variabile contiene 25 osservazioni mancanti; e così via.

650 * 0.9615385
625.000025

Procediamo poi come sempre per esaminare la soluzione ottenuta.

effectsize::interpret(fit)
A data.frame: 10 × 4
NameValueThresholdInterpretation
<chr><dbl><dbl><effctsz_>
GFI 0.9994494320.95satisfactory
AGFI 0.9922920470.90satisfactory
NFI 0.9991925810.90satisfactory
NNFI 0.9989775350.90satisfactory
CFI 0.9998295890.90satisfactory
RMSEA0.0202378800.05satisfactory
SRMR 0.0048531260.08satisfactory
RFI 0.9951554870.90satisfactory
PNFI 0.1665320970.50poor
IFI 0.9998301330.90satisfactory
standardizedSolution(fit)
A lavaan.data.frame: 15 × 9
lhsoprhsest.stdsezpvalueci.lowerci.upper
<chr><chr><chr><dbl><dbl><dbl><dbl><dbl><dbl>
esteem=~s1 0.73744750.0198846537.0862690.000000e+00 0.6984743 0.7764207
esteem=~s2 0.92044990.0134077568.6505750.000000e+00 0.8941712 0.9467286
esteem=~s3 0.88041160.0132528666.4318210.000000e+00 0.8544365 0.9063867
esteem=~s4 0.90459750.0163285955.3996100.000000e+00 0.8725941 0.9366010
s2 ~~s4 -0.88599170.21560986-4.1092363.969709e-05-1.3085793-0.4634042
s1 ~~s1 0.45617110.0293277715.5542370.000000e+00 0.3986898 0.5136525
s2 ~~s2 0.15277200.02468233 6.1895316.034349e-10 0.1043956 0.2011485
s3 ~~s3 0.22487540.02333594 9.6364410.000000e+00 0.1791378 0.2706130
s4 ~~s4 0.18170330.02954160 6.1507607.711243e-10 0.1238028 0.2396038
esteem~~esteem 1.00000000.00000000 NA NA 1.0000000 1.0000000
s1 ~1 2.37536510.0776012530.6098820.000000e+00 2.2232695 2.5274608
s2 ~1 1.88092440.0657847028.5921240.000000e+00 1.7519887 2.0098600
s3 ~1 1.58382400.0591405526.7806760.000000e+00 1.4679106 1.6997373
s4 ~1 1.84966160.0710108426.0475950.000000e+00 1.7104829 1.9888403
esteem~1 0.00000000.00000000 NA NA 0.0000000 0.0000000

26.3. Dati mancanti in R#

26.4. Motivazione#

La pulizia dei dati (data cleaning) in R è fondamentale per effettuare qualsiasi analisi. Uno degli aspetti più importanti della pulizia dei dati è la gestione dei dati mancanti. I valori mancanti (missing values) vengono indicati dal codice NA, che significa not available — non disponibile.

26.5. Trattamento dei dati mancanti#

Se una variabile contiene valori mancanti, R non è in grado di applicare ad essa alcune Funzioni, come ad esempio la media. Per questa ragione, la gran parte delle funzioni di R prevedono modi specifici per trattare i valori mancanti.

Ci sono diversi tipi di dati “mancanti” in R;

  • NA - generico dato mancante;

  • NaN - il codice NaN (Not a Number) indica i valori numerici impossibili, quali ad esempio un valore 0/0;

  • Inf e -Inf - Infinity, si verifca, ad esempio, quando si divide un numero per 0.

La funzione is.na() ritorna un output che indica con TRUE le celle che contengono NA o NaN.

Si noti che

  • se is.na(x) è TRUE, allora !is.na(x) è FALSE;

  • all(!is.na(x)) ritorna TRUE se tutti i valori x sono NOT NA;

  • any(is.na(x)) risponde alla domanda: c’è qualche valore NA (almeno uno) in x?;

  • complete.cases(x) ritorna TRUE se ciascun elemento di x è is NOT NA; ritorna FALSE se almeno un elemento di x è NA;

Le funzioni R is.nan() e is.infinite() si applicano ai tipi di dati NaN e Inf.

Per esempio, consideriamo il seguente data.frame:

d <- tibble(
  w = c(1, 2, NA, 3, NA), 
  x = 1:5, 
  y = 1, 
  z = x ^ 2 + y,
  q = c(3, NA, 5, 1, 4)
)
d
A tibble: 5 × 5
wxyzq
<dbl><int><dbl><dbl><dbl>
111 2 3
221 5NA
NA3110 5
34117 1
NA5126 4
is.na(d$w)
is.na(d$x)
  1. FALSE
  2. FALSE
  3. TRUE
  4. FALSE
  5. TRUE
  1. FALSE
  2. FALSE
  3. FALSE
  4. FALSE
  5. FALSE

Per creare un nuovo Dataframe senza valori mancanti:

d_clean <- d[complete.cases(d), ]
d_clean
A tibble: 2 × 5
wxyzq
<dbl><int><dbl><dbl><dbl>
111 23
341171

Oppure, se vogliamo eliminare le righe con NA solo in una variabile:

d1 <- d[!is.na(d$q), ]
d1
A tibble: 4 × 5
wxyzq
<dbl><int><dbl><dbl><dbl>
111 23
NA31105
341171
NA51264

Se vogliamo esaminare le righe con i dati mancanti in qualunque colonna:

d_na <- d[!complete.cases(d), ]
d_na
A tibble: 3 × 5
wxyzq
<dbl><int><dbl><dbl><dbl>
221 5NA
NA3110 5
NA5126 4

Spesso i valori mancanti vengono sostiuti con valori “ragionevoli”, come ad esempio la media dei valori in quella colonna del Dataframe. Oppure, vengono considerati come “ragionevoli” i valori che vengono predetti conoscendo le altre variabili del Dataframe. Questa procedura si chiama imputazione multipla. Questo è però un argomento avanzato che non verrà trattato in questo insegnamento. La cosa più semplice da fare, in presenza di dati mancanti, è semplicemente quella di escludere tutte le righe nelle quali ci sono degli NAs.