These notes provide the code from Part 1 of the workshop on categorical factor analysis.
Estimation in lavaan
Note that for Delta parameterization, “scale” is fixed to 1 and residual variances = \(1 - \lambda^2\). For Theta parameterization, residual variances = 1 and scales = \(1 / \sqrt{1 + \lambda^2}\). In both cases, the only free parameters are the factors loadings and thresholds, but their values depend on the scaling. Use summary, parameterEstimates or standardizedSolution to see model output.
library(lavaan)dat <-read.csv("cint_data.csv")# Model syntaxmod1 <-' depression =~ cint1 + cint2 + cint4 + cint11 + cint27 + cint28 + cint29 + cint30'# Fit model using delta parameterizationfit.delta <-cfa(mod1, data = dat, std.lv = T, # standardize latent variableordered = T) # data are ordered# Fit model using theta parameterizationfit.theta <-cfa(mod1, data = dat, std.lv = T, # standardize latent variableordered = T, # data are orderedparameterization ="theta")estimates <-cbind(parameterEstimates(fit.delta)[, 1:4], parameterEstimates(fit.theta)[, 4])names(estimates)[4:5] <-c("Delta", "Theta")knitr::kable(estimates, digits =3)
lhs
op
rhs
Delta
Theta
depression
=~
cint1
0.671
0.905
depression
=~
cint2
0.592
0.734
depression
=~
cint4
0.533
0.630
depression
=~
cint11
0.569
0.692
depression
=~
cint27
0.699
0.977
depression
=~
cint28
0.573
0.699
depression
=~
cint29
0.615
0.780
depression
=~
cint30
0.552
0.662
cint1
|
t1
-1.111
-1.498
cint1
|
t2
-0.009
-0.012
cint1
|
t3
1.073
1.447
cint2
|
t1
-0.645
-0.800
cint2
|
t2
0.192
0.238
cint2
|
t3
1.006
1.248
cint4
|
t1
-1.047
-1.237
cint4
|
t2
-0.108
-0.127
cint4
|
t3
0.977
1.155
cint11
|
t1
-0.992
-1.206
cint11
|
t2
-0.244
-0.297
cint11
|
t3
0.939
1.142
cint27
|
t1
-0.414
-0.579
cint27
|
t2
0.207
0.290
cint27
|
t3
0.982
1.372
cint28
|
t1
-0.759
-0.927
cint28
|
t2
-0.003
-0.004
cint28
|
t3
0.953
1.163
cint29
|
t1
0.012
0.015
cint29
|
t2
0.576
0.731
cint29
|
t3
1.360
1.725
cint30
|
t1
-0.353
-0.424
cint30
|
t2
0.260
0.311
cint30
|
t3
1.073
1.287
cint1
~~
cint1
0.550
1.000
cint2
~~
cint2
0.650
1.000
cint4
~~
cint4
0.716
1.000
cint11
~~
cint11
0.676
1.000
cint27
~~
cint27
0.512
1.000
cint28
~~
cint28
0.672
1.000
cint29
~~
cint29
0.622
1.000
cint30
~~
cint30
0.695
1.000
depression
~~
depression
1.000
1.000
cint1
~*~
cint1
1.000
0.741
cint2
~*~
cint2
1.000
0.806
cint4
~*~
cint4
1.000
0.846
cint11
~*~
cint11
1.000
0.822
cint27
~*~
cint27
1.000
0.715
cint28
~*~
cint28
1.000
0.820
cint29
~*~
cint29
1.000
0.789
cint30
~*~
cint30
1.000
0.834
cint1
~1
0.000
0.000
cint2
~1
0.000
0.000
cint4
~1
0.000
0.000
cint11
~1
0.000
0.000
cint27
~1
0.000
0.000
cint28
~1
0.000
0.000
cint29
~1
0.000
0.000
cint30
~1
0.000
0.000
depression
~1
0.000
0.000
Both models have the same fit to the data – only the scaling changes.
Comparing models using chi-square difference tests
Testing config, weak, and strong invariance. Note that strong invariance model estimates “scales” of LRs (in Delta parameterization) or residual variances of LRVs (in Theta parameterization).
# Config, weak, and strong (estimates "scales" of LRV)lavTestLRT(fit.config, fit.weak, fit.strong)
Scaled Chi-Squared Difference Test (method = "satorra.2000")
lavaan NOTE:
The "Chisq" column contains standard test statistics, not the
robust test that should be reported per model. A robust difference
test is a function of two standard (not robust) statistics.
Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
fit.config 40 37.534
fit.weak 47 57.126 12.091 7 0.09761 .
fit.strong 62 112.075 63.910 15 5.3e-08 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Testing config, weak, and strict invariance. Note that strict invariance model does not estimate “scales” or residual variance of LRVs.
# Config, weak, and strict (doesn't estimates "scales" of LRV))lavTestLRT(fit.config, fit.weak, fit.strict.delta)
Scaled Chi-Squared Difference Test (method = "satorra.2000")
lavaan NOTE:
The "Chisq" column contains standard test statistics, not the
robust test that should be reported per model. A robust difference
test is a function of two standard (not robust) statistics.
Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
fit.config 40 37.534
fit.weak 47 57.126 12.091 7 0.09761 .
fit.strict.delta 70 121.781 73.542 23 3.411e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Same result using theta parameterization for strict invariance (lavaan code is simpler, model fit is the same).
# Same fit when using theta for strict (simpler code)lavTestLRT(fit.config, fit.weak, fit.strict.theta)
Scaled Chi-Squared Difference Test (method = "satorra.2000")
lavaan NOTE:
The "Chisq" column contains standard test statistics, not the
robust test that should be reported per model. A robust difference
test is a function of two standard (not robust) statistics.
Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
fit.config 40 37.534
fit.weak 47 57.126 12.091 7 0.09761 .
fit.strict.theta 70 122.510 76.762 23 1.053e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Related models
Testing homogeneity of variance by comparing weak invariance model to a model that adds constraints on factor variances.
fit.homo <-cfa(mod1, data = dat, std.lv = T, ordered = T, group ="cfemale",group.equal =c("loadings", "lv.variances"))lavTestLRT(fit.weak, fit.homo)
Scaled Chi-Squared Difference Test (method = "satorra.2000")
lavaan NOTE:
The "Chisq" column contains standard test statistics, not the
robust test that should be reported per model. A robust difference
test is a function of two standard (not robust) statistics.
Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
fit.weak 47 57.126
fit.homo 48 88.228 6.023 1 0.01412 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Omnibus test of wether factor means differ over groups, by comparing strong invariance model to a model that adds constraints on factor means (mainly useful with > 2 groups).
fit.omnibus <-cfa(mod1, data = dat, std.lv = T, ordered = T, group ="cfemale",group.equal =c("loadings", "thresholds", "means"))lavTestLRT(fit.strong, fit.omnibus)
Scaled Chi-Squared Difference Test (method = "satorra.2000")
lavaan NOTE:
The "Chisq" column contains standard test statistics, not the
robust test that should be reported per model. A robust difference
test is a function of two standard (not robust) statistics.
Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
fit.strong 62 112.08
fit.omnibus 63 260.51 28.474 1 9.497e-08 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1