Konfirmatorische Faktorenanalyse (CFA) mit R lavaan
5. Mehrgruppen-CFA (MGCFA) und Messinvarianzprüfung

Arndt Regorz, Dipl. Kfm. & MSc. Psychologie, 27.10.2022

Dieses ist eine Begleitseite zum Video-Tutorial über die Mehrgruppen-CFA mit lavaan.



(Hinweis: Mit Anklicken des Videos wird ein Angebot des Anbieters YouTube genutzt.)


R-Code aus dem Video-Tutorial

Hier ist der gesamte Code aus dem Video-Tutorial.

# Mehrgruppen-CFA (MGCFA)

library(lavaan)

# R-Code ist auch auf der Begleitseite zum Video

head(HolzingerSwineford1939)
levels(HolzingerSwineford1939$school)

# 1. Invarianzprüfung mit automatischen Gleichheitsrestriktionen
# =================================

# Unbeschränktes Modell in beiden Gruppen (Konfigurale Messinvarianz)

model1 <- ' visual =~ x1 + x2 + x3
textual =~ x4 + x5 + x6
speed =~ x7 + x8 + x9 '

fit1 <- cfa(model1,
data = HolzingerSwineford1939,
group = "school",
std.lv = TRUE)

summary(fit1, fit.measures =TRUE, standardized = TRUE)

mi <- modindices(fit1)
mi[mi$mi > 10,]

# Unbeschränktes Modell in beiden Gruppen bearbeitet

model2 <- ' visual =~ x1 + x2 + x3 + x9
textual =~ x4 + x5 + x6
speed =~ x7 + x8 + x9'

fit1a <- cfa(model2,
data = HolzingerSwineford1939,
group = "school",
std.lv = TRUE)

summary(fit1a, fit.measures =TRUE, standardized = TRUE)

mi <- modindices(fit1a)
mi[mi$mi > 10,]

# Unbeschränktes Modell (bearbeitet) je Gruppe

library(dplyr)
Holzinger_Pasteur <- filter(HolzingerSwineford1939, school=="Pasteur")
Holzinger_Grant <- filter(HolzingerSwineford1939, school=="Grant-White")

fit1a_Pasteur <- cfa(model2,
data = Holzinger_Pasteur,
std.lv = TRUE)

summary(fit1a_Pasteur, fit.measures =TRUE, standardized = TRUE)

mi <- modindices(fit1a_Pasteur)
mi[mi$mi > 10,]

fit1a_Grant <- cfa(model2,
data = Holzinger_Grant,
std.lv = TRUE)

summary(fit1a_Grant, fit.measures =TRUE, standardized = TRUE)

mi <- modindices(fit1a_Grant)
mi[mi$mi > 10,]

# Modell mit gleichen Ladungen in beiden Gruppen (Metrische Messinvarianz, weak invariance)

fit2 <- cfa(model2,
data = HolzingerSwineford1939,
group = "school",
group.equal = "loadings",
std.lv = TRUE)

summary(fit2, fit.measures =TRUE, standardized = TRUE)

lavTestLRT(fit1a, fit2)

fitMeasures(fit1a, "cfi") - fitMeasures(fit2, "cfi")

# Modell mit gleichen Intercepts (Skalare Messinvarianz, strong invariance)

fit3 <- cfa(model2,
data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings", "intercepts"),
std.lv = TRUE)

summary(fit3, fit.measures =TRUE, standardized = TRUE)

lavTestLRT(fit2, fit3)

fitMeasures(fit2, "cfi") - fitMeasures(fit3, "cfi")

# Andere mögliche Parameter für group.equal =

# "means": intercepts/means of the latent variables
# "residuals": residual variances of the observed variables
# "residual.covariances": residual covariances of the observed variables
# "lv.variances": (residual) variances of the latent variables
# "lv.covariances": (residual) covariances of the latent varibles
# "regressions": regression coefficients in the model

# (Einige davon sind für eine CFA nicht relevant, sondern für SEM/Pfadmodell)

# Technisches Beispiel: Wenn nur partielle Gleichheit zwischen Gruppen geprüft werden soll

fit3a <- cfa(model2,
data = HolzingerSwineford1939,
group = "school",
group.equal = c("loadings", "intercepts"),
group.partial = c("x5 ~ 1"),
std.lv = TRUE)

summary(fit3a, fit.measures =TRUE, standardized = TRUE)

lavTestLRT(fit2, fit3a)

# Wenn wir zwei Ladungen zwischen den Gruppen freigeben wollten, z.B.:
# group.partial = c("visual =~ x1", "speed =~ x7"))

# 2. Manuelle Restriktionen
# =====================

# Metrische Messinvarianz (gleiche Ladungen) manuell mit expliziten Gleichheitsrestriktionen

model4a <- ' visual =~ c(a1, a2) * x1 + c(b1, b2) * x2 + c(c1, c2) * x3 + c(j1, j2) * x9
textual =~ c(d1, d2) * x4 + c(e1, e2) * x5 + c(f1, f2) * x6
speed =~ c(g1, g2) * x7 + c(h1, h2) * x8 + c(i1, i2) * x9

a1 == a2
b1 == b2
c1 == c2
d1 == d2
e1 == e2
f1 == f2
g1 == g2
h1 == h2
i1 == i1
j1 == j2'

fit4a <- cfa(model4a,
data = HolzingerSwineford1939,
group = "school",
std.lv = TRUE)

summary(fit4a, fit.measures =TRUE, standardized = TRUE)

# Weitere Möglichkeiten bei der manuellen Definition

# a) Parameter auf konkrete Werte setzen:
# c(1, 1) * x1

# b) Parameter teilweise freigeben:
# c(1, NA) * x1