Data are simulated using lavaan. From this simulation it is possible to extract 3 factors (t1 t2 t3) and 3 arbitrary levels (m1 m2 m3).
# specify population model
population_model<-'t1=~x1+0.8*x2+1.2*x3
t2=~x4+0.5*x5+1.5*x6
t3=~x7+0.1*x8+0.9*x9'
# generate data
set.seed(1234)
model_data<-lavaan::simulateData(population_model,sample.nobs=45000)
model_data$method<-c(rep("m1",15000),rep("m2",15000),rep("m3",15000))
model_data$id<-rep(1:15000,3)[1:45000]
mtmm_data<-reshape(model_data,idvar="id",timevar="method",direction="wide")
default_model<-'t1=~x1+x2+x3
t2=~x4+x5+x6
t3=~x7+x8+x9'
dm<-lavaan::cfa(default_model,data=model_data)
findex<-c("rmsea","cfi","tli","rni","rfi","ifi","srmr","gfi")
# lavaan::inspect(dm,what="std")
# lavaan::parameterEstimates(dm,standardized=TRUE)
lavaan::fitMeasures(dm,findex)
## rmsea cfi tli rni rfi ifi srmr gfi
## 0.000 1.000 1.000 1.000 0.999 1.000 0.003 1.000
semPlot::semPaths(dm,"model",layout="tree2",what="std")
## Registered S3 methods overwritten by 'huge':
## method from
## plot.sim BDgraph
## print.sim BDgraph
In order to perform CFA MTMM we need at least four models
- Model 1 Freely correlated traits and methods
- Model 2 No traits – freely correlated methods
- Model 3 Perfectly correlated traits – freely correlated methods
- Model 4 Freely correlated traits – perfectly independent methods
Then models 2-4 are compared with model 1 - Model 2 should be worst than model 1 - Model 3 should be worst than model 1 - Model 4 should be as good as model 1
It is easier to spesify these models incrementally.
methods<-"
method_1=~x1.m1+x2.m1+x3.m1+x4.m1+x5.m1+x6.m1+x7.m1+x8.m1+x9.m1
method_2=~x1.m2+x2.m2+x3.m2+x4.m2+x5.m2+x6.m2+x7.m2+x8.m2+x9.m2
method_3=~x1.m3+x2.m3+x3.m3+x4.m3+x5.m3+x6.m3+x7.m3+x8.m3+x9.m3
"
traits<-"
t1=~x1.m1+x2.m1+x3.m1+x1.m2+x2.m2+x3.m2+x1.m3+x2.m3+x3.m3
t2=~x4.m1+x5.m1+x6.m1+x4.m2+x5.m2+x6.m2+x4.m3+x5.m3+x6.m3
t3=~x7.m1+x8.m1+x9.m1+x7.m2+x8.m2+x9.m2+x7.m3+x8.m3+x9.m3
"
covariances<-"
method_1~~0*t1
method_1~~0*t2
method_1~~0*t3
method_2~~0*t1
method_2~~0*t2
method_2~~0*t3
method_3~~0*t1
method_3~~0*t2
method_3~~0*t3
"
perfectly_correlated_traits<-"
t1~~1*t2
t1~~1*t3
t2~~1*t3
"
perfectly_correlated_methods<-"
method_1~~1*method_2
method_1~~1*method_3
method_2~~1*method_3
"
perfectly_independent_methods<-"
method_1~~0*method_2
method_1~~0*method_3
method_2~~0*method_3
"
correlated_residuals<-"
x1.m1~~x1.m2
x1.m1~~x1.m3
x1.m2~~x1.m3
x2.m1~~x2.m2
x2.m1~~x2.m3
x2.m2~~x2.m3
x3.m1~~x3.m2
x3.m1~~x3.m3
x3.m2~~x3.m3
x4.m1~~x4.m2
x4.m1~~x4.m3
x4.m2~~x4.m3
x5.m1~~x5.m2
x5.m1~~x5.m3
x5.m2~~x5.m3
x6.m1~~x6.m2
x6.m1~~x6.m3
x6.m2~~x6.m3
x7.m1~~x7.m2
x7.m1~~x7.m3
x7.m2~~x7.m3
x8.m1~~x8.m2
x8.m1~~x8.m3
x8.m2~~x8.m3
x9.m1~~x9.m2
x9.m1~~x9.m3
x9.m2~~x9.m3
"
perfectly_correlated_residuals<-"
x1.m1~~1*x1.m2
x1.m2~~1*x1.m3
x2.m1~~1*x2.m2
x2.m2~~1*x2.m3
x3.m1~~1*x3.m2
x3.m2~~1*x3.m3
x4.m1~~1*x4.m2
x4.m2~~1*x4.m3
x5.m1~~1*x5.m2
x5.m2~~1*x5.m3
x6.m1~~1*x6.m2
x6.m2~~1*x6.m3
x7.m1~~1*x7.m2
x7.m2~~1*x7.m3
x8.m1~~1*x8.m2
x8.m2~~1*x8.m3
x9.m1~~1*x9.m2
x9.m2~~1*x9.m3
"
freely_correlated_traits_methods_model<-paste0(traits,methods,covariances)
methods_only_model<-methods
perfectly_correlated_traits_model<-paste0(freely_correlated_traits_methods_model,perfectly_correlated_traits)
perfectly_correlated_methods_model<-paste0(freely_correlated_traits_methods_model,perfectly_correlated_methods)
perfectly_independent_methods_model<-paste0(freely_correlated_traits_methods_model,perfectly_independent_methods)
correlated_residuals_model<-paste0(traits,correlated_residuals)
perfectly_correlated_residuals_model<-paste0(traits,perfectly_correlated_residuals)
The four model spesifications can be easilly inspected with cat.
cat(freely_correlated_traits_methods_model)
##
## t1=~x1.m1+x2.m1+x3.m1+x1.m2+x2.m2+x3.m2+x1.m3+x2.m3+x3.m3
## t2=~x4.m1+x5.m1+x6.m1+x4.m2+x5.m2+x6.m2+x4.m3+x5.m3+x6.m3
## t3=~x7.m1+x8.m1+x9.m1+x7.m2+x8.m2+x9.m2+x7.m3+x8.m3+x9.m3
##
## method_1=~x1.m1+x2.m1+x3.m1+x4.m1+x5.m1+x6.m1+x7.m1+x8.m1+x9.m1
## method_2=~x1.m2+x2.m2+x3.m2+x4.m2+x5.m2+x6.m2+x7.m2+x8.m2+x9.m2
## method_3=~x1.m3+x2.m3+x3.m3+x4.m3+x5.m3+x6.m3+x7.m3+x8.m3+x9.m3
##
## method_1~~0*t1
## method_1~~0*t2
## method_1~~0*t3
## method_2~~0*t1
## method_2~~0*t2
## method_2~~0*t3
## method_3~~0*t1
## method_3~~0*t2
## method_3~~0*t3
cat(methods_only_model)
##
## method_1=~x1.m1+x2.m1+x3.m1+x4.m1+x5.m1+x6.m1+x7.m1+x8.m1+x9.m1
## method_2=~x1.m2+x2.m2+x3.m2+x4.m2+x5.m2+x6.m2+x7.m2+x8.m2+x9.m2
## method_3=~x1.m3+x2.m3+x3.m3+x4.m3+x5.m3+x6.m3+x7.m3+x8.m3+x9.m3
cat(perfectly_correlated_traits_model)
##
## t1=~x1.m1+x2.m1+x3.m1+x1.m2+x2.m2+x3.m2+x1.m3+x2.m3+x3.m3
## t2=~x4.m1+x5.m1+x6.m1+x4.m2+x5.m2+x6.m2+x4.m3+x5.m3+x6.m3
## t3=~x7.m1+x8.m1+x9.m1+x7.m2+x8.m2+x9.m2+x7.m3+x8.m3+x9.m3
##
## method_1=~x1.m1+x2.m1+x3.m1+x4.m1+x5.m1+x6.m1+x7.m1+x8.m1+x9.m1
## method_2=~x1.m2+x2.m2+x3.m2+x4.m2+x5.m2+x6.m2+x7.m2+x8.m2+x9.m2
## method_3=~x1.m3+x2.m3+x3.m3+x4.m3+x5.m3+x6.m3+x7.m3+x8.m3+x9.m3
##
## method_1~~0*t1
## method_1~~0*t2
## method_1~~0*t3
## method_2~~0*t1
## method_2~~0*t2
## method_2~~0*t3
## method_3~~0*t1
## method_3~~0*t2
## method_3~~0*t3
##
## t1~~1*t2
## t1~~1*t3
## t2~~1*t3
cat(perfectly_correlated_methods_model)
##
## t1=~x1.m1+x2.m1+x3.m1+x1.m2+x2.m2+x3.m2+x1.m3+x2.m3+x3.m3
## t2=~x4.m1+x5.m1+x6.m1+x4.m2+x5.m2+x6.m2+x4.m3+x5.m3+x6.m3
## t3=~x7.m1+x8.m1+x9.m1+x7.m2+x8.m2+x9.m2+x7.m3+x8.m3+x9.m3
##
## method_1=~x1.m1+x2.m1+x3.m1+x4.m1+x5.m1+x6.m1+x7.m1+x8.m1+x9.m1
## method_2=~x1.m2+x2.m2+x3.m2+x4.m2+x5.m2+x6.m2+x7.m2+x8.m2+x9.m2
## method_3=~x1.m3+x2.m3+x3.m3+x4.m3+x5.m3+x6.m3+x7.m3+x8.m3+x9.m3
##
## method_1~~0*t1
## method_1~~0*t2
## method_1~~0*t3
## method_2~~0*t1
## method_2~~0*t2
## method_2~~0*t3
## method_3~~0*t1
## method_3~~0*t2
## method_3~~0*t3
##
## method_1~~1*method_2
## method_1~~1*method_3
## method_2~~1*method_3
# Compare
# freely correlated traits / freely correlated methods
# no traits / freely correlated methods
lavaan::anova(fm,mm) # Evidence of convergent validity for significant results
## Chi Square Difference Test
##
## Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
## fm 291 1343799 1344461 16544
## mm 321 1365147 1365581 37952 21408 30 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Compare
# freely correlated traits / freely correlated methods
# perfectly correlated traits / freely correlated methods
lavaan::anova(fm,ctm) # Weak evidence for discriminant validity for significant results
## Chi Square Difference Test
##
## Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
## fm 291 1343799 1344461 16544
## ctm 294 1356603 1357242 29354 12810 3 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Compare
# freely correlated traits / freely correlated methods
# freely correlated traits / perfectly independent methods
lavaan::anova(fm,imm) # Evidence for discriminant validity for non significant results
## Chi Square Difference Test
##
## Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
## fm 291 1343799 1344461 16544
## imm 294 1352749 1353389 25501 8957 3 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1