✏️ Esercizi

39. ✏️ Esercizi#

E1. Si ripeta l’esercizio che abbiamo svolto in precedenza usando l’analisi fattoriale esplorativa, questa volta usando la CFA in lavaan. I dati sono forniti da Brown [Bro15] e riguardano a otto misure di personalità raccolte su un campione di 250 pazienti che hanno concluso un programma di psicoterapia:

  • anxiety (N1),

  • hostility (N2),

  • depression (N3),

  • self-consciousness (N4),

  • warmth (E1),

  • gregariousness (E2),

  • assertiveness (E3),

  • positive emotions (E4).

varnames <- c("N1", "N2", "N3", "N4", "E1", "E2", "E3", "E4")
sds <- "5.7  5.6  6.4  5.7  6.0  6.2  5.7  5.6"

cors <- "
 1.000
 0.767  1.000
 0.731  0.709  1.000
 0.778  0.738  0.762  1.000
-0.351  -0.302  -0.356  -0.318  1.000
-0.316  -0.280  -0.300  -0.267  0.675  1.000
-0.296  -0.289  -0.297  -0.296  0.634  0.651  1.000
-0.282  -0.254  -0.292  -0.245  0.534  0.593  0.566  1.000"

psychot_cor_mat <- getCov(cors, names = varnames)
n <- 250

Il modello con due fattori ortogonali può essere adattato ai dati nel modo seguente.

cfa_mod <- "
  N =~ N1 + N2 + N3 + N4
  E =~ E1 + E2 + E3 + E4
"
fit_cfa <- lavaan::cfa(
    cfa_mod,
    sample.cov = psychot_cor_mat,
    sample.nobs = n,
    orthogonal = TRUE,
    std.lv = TRUE
)
semPlot::semPaths(fit_cfa,
    what = "col", whatLabels = "par", style = "mx", 
    layout = "tree2", nCharNodes = 7,
    shapeMan = "rectangle", sizeMan = 8, sizeMan2 = 5
)
../_images/1c5c9a7caf893bcbe4bdbb09638ec0d536fa82d6001ccdaf675009ed48b92743.png

Esaminiamo le saturazioni fattoriali:

parameterEstimates(fit_cfa, standardized = TRUE) %>%
    dplyr::filter(op == "=~") %>%
    dplyr::select(
        "Latent Factor" = lhs,
        Indicator = rhs,
        B = est,
        SE = se,
        Z = z,
        "p-value" = pvalue,
        Beta = std.all
    ) %>%
    knitr::kable(
        digits = 3, booktabs = TRUE, format = "markdown",
        caption = "Factor Loadings"
    )
Table: Factor Loadings

|Latent Factor |Indicator |     B|    SE|      Z| p-value|  Beta|
|:-------------|:---------|-----:|-----:|------:|-------:|-----:|
|N             |N1        | 0.882| 0.051| 17.422|       0| 0.884|
|N             |N2        | 0.847| 0.052| 16.340|       0| 0.849|
|N             |N3        | 0.840| 0.052| 16.134|       0| 0.842|
|N             |N4        | 0.882| 0.051| 17.432|       0| 0.884|
|E             |E1        | 0.795| 0.056| 14.276|       0| 0.796|
|E             |E2        | 0.838| 0.054| 15.369|       0| 0.839|
|E             |E3        | 0.788| 0.056| 14.097|       0| 0.789|
|E             |E4        | 0.697| 0.058| 11.942|       0| 0.699|

Il risultato sembra sensato: le saturazioni su ciascun fattore sono molto alte. Tuttavia, la matrice delle correlazioni residue

cor_table <- residuals(fit_cfa, type = "cor")$cov
knitr::kable(
    cor_table,
    digits = 3,
    format = "markdown",
    booktabs = TRUE
)
|   |     N1|     N2|     N3|     N4|     E1|     E2|     E3|     E4|
|:--|------:|------:|------:|------:|------:|------:|------:|------:|
|N1 |  0.000|  0.017| -0.013| -0.003| -0.351| -0.316| -0.296| -0.282|
|N2 |  0.017|  0.000| -0.006| -0.012| -0.302| -0.280| -0.289| -0.254|
|N3 | -0.013| -0.006|  0.000|  0.018| -0.356| -0.300| -0.297| -0.292|
|N4 | -0.003| -0.012|  0.018|  0.000| -0.318| -0.267| -0.296| -0.245|
|E1 | -0.351| -0.302| -0.356| -0.318|  0.000|  0.007|  0.006| -0.022|
|E2 | -0.316| -0.280| -0.300| -0.267|  0.007|  0.000| -0.011|  0.007|
|E3 | -0.296| -0.289| -0.297| -0.296|  0.006| -0.011|  0.000|  0.015|
|E4 | -0.282| -0.254| -0.292| -0.245| -0.022|  0.007|  0.015|  0.000|

rivela che il modello ipotizzato dall’analisi fattoriale confermativa non è adeguato.

fit2_cfa <- lavaan::cfa(
    cfa_mod,
    sample.cov = psychot_cor_mat,
    sample.nobs = n,
    orthogonal = FALSE,
    std.lv = TRUE
)
semPlot::semPaths(fit2_cfa,
    what = "col", whatLabels = "par", style = "mx", 
    layout = "tree2", nCharNodes = 7,
    shapeMan = "rectangle", sizeMan = 8, sizeMan2 = 5
)
../_images/403eba1f5fe2625cb44879079fdc679d7a9cdbe5131944dac66961e18fb5fea1.png

Esaminiamo le saturazioni fattoriali.

parameterEstimates(fit2_cfa, standardized = TRUE) %>%
    dplyr::filter(op == "=~") %>%
    dplyr::select(
        "Latent Factor" = lhs,
        Indicator = rhs,
        B = est,
        SE = se,
        Z = z,
        "p-value" = pvalue,
        Beta = std.all
    ) %>%
    knitr::kable(
        digits = 3, booktabs = TRUE, format = "markdown",
        caption = "Factor Loadings"
    )
Table: Factor Loadings

|Latent Factor |Indicator |     B|    SE|      Z| p-value|  Beta|
|:-------------|:---------|-----:|-----:|------:|-------:|-----:|
|N             |N1        | 0.883| 0.051| 17.472|       0| 0.885|
|N             |N2        | 0.847| 0.052| 16.337|       0| 0.849|
|N             |N3        | 0.842| 0.052| 16.190|       0| 0.844|
|N             |N4        | 0.880| 0.051| 17.381|       0| 0.882|
|E             |E1        | 0.800| 0.055| 14.465|       0| 0.802|
|E             |E2        | 0.832| 0.054| 15.294|       0| 0.834|
|E             |E3        | 0.788| 0.056| 14.150|       0| 0.789|
|E             |E4        | 0.698| 0.058| 11.974|       0| 0.699|

Esaminiamo i residui.

cor_table <- residuals(fit2_cfa, type = "cor")$cov
knitr::kable(
    cor_table,
    digits = 3,
    format = "markdown",
    booktabs = TRUE
)
|   |     N1|     N2|     N3|     N4|     E1|     E2|     E3|     E4|
|:--|------:|------:|------:|------:|------:|------:|------:|------:|
|N1 |  0.000|  0.016| -0.015| -0.002| -0.042|  0.005|  0.008| -0.013|
|N2 |  0.016|  0.000| -0.007| -0.010| -0.006|  0.028|  0.002|  0.004|
|N3 | -0.015| -0.007|  0.000|  0.018| -0.062|  0.006| -0.007| -0.035|
|N4 | -0.002| -0.010|  0.018|  0.000| -0.010|  0.053|  0.007|  0.023|
|E1 | -0.042| -0.006| -0.062| -0.010|  0.000|  0.006|  0.001| -0.027|
|E2 |  0.005|  0.028|  0.006|  0.053|  0.006|  0.000| -0.007|  0.010|
|E3 |  0.008|  0.002| -0.007|  0.007|  0.001| -0.007|  0.000|  0.014|
|E4 | -0.013|  0.004| -0.035|  0.023| -0.027|  0.010|  0.014|  0.000|

Sistemiamo le saturazioni fattoriali in una matrice 8 \(\times\) 2:

lambda <- inspect(fit2_cfa, what = "std")$lambda
lambda
A lavaan.matrix: 8 × 2 of type dbl
NE
N10.88482140.0000000
N20.84851280.0000000
N30.84364320.0000000
N40.88197360.0000000
E10.00000000.8018485
E20.00000000.8337599
E30.00000000.7894530
E40.00000000.6990366

Otteniamo la matrice di intercorrelazoni fattoriali.

Phi <- inspect(fit2_cfa, what = "std")$psi
Phi
A lavaan.matrix.symmetric: 2 × 2 of type dbl
NE
N 1.000000-0.434962
E-0.434962 1.000000

Otteniamo la matrice di varianze residue.

Psi <- inspect(fit2_cfa, what = "std")$theta
Psi
A lavaan.matrix.symmetric: 8 × 8 of type dbl
N1N2N3N4E1E2E3E4
N10.2170910.00000000.00000000.00000000.0000000.00000000.0000000.0000000
N20.0000000.28002610.00000000.00000000.0000000.00000000.0000000.0000000
N30.0000000.00000000.28826610.00000000.0000000.00000000.0000000.0000000
N40.0000000.00000000.00000000.22212250.0000000.00000000.0000000.0000000
E10.0000000.00000000.00000000.00000000.3570390.00000000.0000000.0000000
E20.0000000.00000000.00000000.00000000.0000000.30484450.0000000.0000000
E30.0000000.00000000.00000000.00000000.0000000.00000000.3767640.0000000
E40.0000000.00000000.00000000.00000000.0000000.00000000.0000000.5113478

Mediante i parametri del modello la matrice di correlazione si riproduce nel modo seguente:

\[ \boldsymbol{\Sigma} =\boldsymbol{\Lambda} \boldsymbol{\Phi} \boldsymbol{\Lambda}^{\mathsf{T}} + \boldsymbol{\Psi}. \]

In \(\textsf{R}\) scriviamo:

R_hat <- lambda %*% Phi %*% t(lambda) + Psi
R_hat %>%
    round(3)
A lavaan.matrix.symmetric: 8 × 8 of type dbl
N1N2N3N4E1E2E3E4
N1 1.000 0.751 0.746 0.780-0.309-0.321-0.304-0.269
N2 0.751 1.000 0.716 0.748-0.296-0.308-0.291-0.258
N3 0.746 0.716 1.000 0.744-0.294-0.306-0.290-0.257
N4 0.780 0.748 0.744 1.000-0.308-0.320-0.303-0.268
E1-0.309-0.296-0.294-0.308 1.000 0.669 0.633 0.561
E2-0.321-0.308-0.306-0.320 0.669 1.000 0.658 0.583
E3-0.304-0.291-0.290-0.303 0.633 0.658 1.000 0.552
E4-0.269-0.258-0.257-0.268 0.561 0.583 0.552 1.000

Le correlazioni residue sono:

(psychot_cor_mat - R_hat) %>%
    round(3)
A lavaan.matrix.symmetric: 8 × 8 of type dbl
N1N2N3N4E1E2E3E4
N1 0.000 0.016-0.015-0.002-0.042 0.005 0.008-0.013
N2 0.016 0.000-0.007-0.010-0.006 0.028 0.002 0.004
N3-0.015-0.007 0.000 0.018-0.062 0.006-0.007-0.035
N4-0.002-0.010 0.018 0.000-0.010 0.053 0.007 0.023
E1-0.042-0.006-0.062-0.010 0.000 0.006 0.001-0.027
E2 0.005 0.028 0.006 0.053 0.006 0.000-0.007 0.010
E3 0.008 0.002-0.007 0.007 0.001-0.007 0.000 0.014
E4-0.013 0.004-0.035 0.023-0.027 0.010 0.014 0.000

Calcoliamo la correlazione predetta dal modello tra le variabili \(Y_1\) e \(Y_2\):

lambda[1, 1] * lambda[2, 1] + lambda[1, 2] * lambda[2, 2] +
    lambda[1, 1] * lambda[2, 2] * Phi[1, 2] +
    lambda[1, 2] * lambda[2, 1] * Phi[1, 2]
0.750782309575684

Questo risultato è molto simile al valore contenuto dell’elemento (1, 2) della matrice di correlazioni osservate:

psychot_cor_mat[1, 2]
0.767

Usando le funzonalità di lavaan la matrice di correlazione predetta si ottiene con:

fitted(fit2_cfa)$cov |>
    print()
       N1     N2     N3     N4     E1     E2     E3     E4
N1  0.996                                                 
N2  0.748  0.996                                          
N3  0.743  0.713  0.996                                   
N4  0.777  0.745  0.741  0.996                            
E1 -0.307 -0.295 -0.293 -0.306  0.996                     
E2 -0.320 -0.306 -0.305 -0.319  0.666  0.996              
E3 -0.303 -0.290 -0.289 -0.302  0.630  0.656  0.996       
E4 -0.268 -0.257 -0.255 -0.267  0.558  0.580  0.550  0.996

La matrice dei residui è

resid(fit2_cfa)$cov |>
    print()
       N1     N2     N3     N4     E1     E2     E3     E4
N1  0.000                                                 
N2  0.016  0.000                                          
N3 -0.015 -0.007  0.000                                   
N4 -0.002 -0.010  0.018  0.000                            
E1 -0.042 -0.006 -0.062 -0.010  0.000                     
E2  0.005  0.028  0.006  0.053  0.006  0.000              
E3  0.008  0.002 -0.007  0.007  0.001 -0.007  0.000       
E4 -0.013  0.004 -0.035  0.023 -0.026  0.010  0.014  0.000

La matrice dei residui standardizzati è

resid(fit2_cfa, type = "standardized")$cov |>
    print()
       N1     N2     N3     N4     E1     E2     E3     E4
N1  0.000                                                 
N2  1.674  0.000                                          
N3 -1.769 -0.569  0.000                                   
N4 -0.350 -1.152  1.746  0.000                            
E1 -1.214 -0.161 -1.646 -0.294  0.000                     
E2  0.154  0.794  0.168  1.626  0.637  0.000              
E3  0.219  0.062 -0.191  0.193  0.075 -0.693  0.000       
E4 -0.314  0.092 -0.824  0.552 -1.481  0.624  0.690  0.000

I valori precedenti possono essere considerati come punti z, dove i valori con un valore assoluto maggiore di 2 possono essere ritenuti problematici. Tuttavia, è importante considerare che in questo modo si stanno eseguendo molteplici confronti, pertanto, si dovrebbe considerare l’opportunità di applicare una qualche forma di correzione per i confronti multipli.

E2. Si utilizzino i dati dass21.txt che corrispondono alla somministrazione del test DASS-21 a 334 partecipanti. Lo schema di codifica si può trovare seguendo questo link. Si adatti ai dati un modello a tre fattori usando l’analisi fattoriale esplorativa con la funzione lavaan::efa(). Usando le saturazioni fattoriali e la matrice di inter-correlazioni fattoriali, si trovi la matrice di correlazioni riprodotta dal modello. Senza usare l’albebra matriciale, si trovi la correlazione predetta tra gli indicatori DASS-1 e DASS-2.