rr-lavaan

Estimating regression paths in lavaan, df and test statistics


I am trying to compare structural equation models using lavaan in R. I have 4 latent variables, three of which are being estimated by 8 observed variables and one of which is being estimated by 2 observed variables.

When I run the measurement model, the test user model has 293 degrees of freedom with 58 model parameters. When I run the structural model, with three additional regression paths estimated, I receive the same model statistics with the same number of degrees of freedom (293) and the same number of model parameters (58).

Because the models are identical, and I try to compare them with anova, there are no degrees of freedom difference, and no chi-square difference, because it is the same model output. So, I receive the following error

Warning message: In lavTestLRT(object = object, ..., model.names = NAMES) : lavaan WARNING: some models have the same degrees of freedom

semPaths is showing the regression coefficients estimated, and the output for parameter estimates are showing the regression coefficients for the structural model, but the fit indices (AIC, BIC, etc.), chi-square, and degrees of freedom are identical.

I thought I had simply put the wrong model in the summary function, but no, that was not it.

I am trying not to be a dolt, but I cannot figure out why lavaan is giving me exactly the same df and chi-square when I am estimating three additional paths/parameters. Any insight is welcomed. Again, I apologize of I am missing the obvious.

Here is the code:

# Pre-Post Measurement Model 1 - (TM)
MeasTM1 <- '
 
  posttransp8 =~ post_Understand_Successful_Work + 
                post_Purpose_Assignment + 
                post_Assignment_Objectives_Course + 
                post_Instructor_Identified_Goal + 
                post_Steps_Required + 
                post_Assignment_Instructions +
                post_Detailed_Directions + 
                post_Knew_How_Evaluated
                
  
  preskills8 =~ pre_Express_Ideas_Write + 
                 pre_Express_Ideas_Speak + 
                 pre_Collaborate_Academic + 
                 pre_Analyz + pre_Synthesize + 
                 pre_Apply_New_Contexts + 
                 pre_Consider_Ethics + 
                 pre_Capable_Self_Learn
 
  postskills8 =~ post_Express_Ideas_Write + 
                 post_Express_Ideas_Speak + 
                 post_Collaborate_Academic + 
                 post_Analyz + post_Synthesize + 
                 post_Apply_New_Contexts + 
                 post_Consider_Ethics + 
                 post_Capable_Self_Learn
  
  postbelong2 =~ post_Belong_School_Commty + post_Helped_Belong_School_Commty

'

fitMeasTM1 <- sem(MeasTM1, data=TILTSEM)

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

semPaths(fitMeasTM1, whatLabels = "std", layout = "tree")

# Pre-Post Factor Model 1 - (TM)
#Testing regression on Pre-Post Skills

FactTM1 <- '
 
#latent factors

  posttransp8 =~ post_Understand_Successful_Work + 
                post_Purpose_Assignment + 
                post_Assignment_Objectives_Course + 
                post_Instructor_Identified_Goal + 
                post_Steps_Required + 
                post_Assignment_Instructions +
                post_Detailed_Directions + 
                post_Knew_How_Evaluated
                
  
  preskills8 =~ pre_Express_Ideas_Write + 
                 pre_Express_Ideas_Speak + 
                 pre_Collaborate_Academic + 
                 pre_Analyz + pre_Synthesize + 
                 pre_Apply_New_Contexts + 
                 pre_Consider_Ethics + 
                 pre_Capable_Self_Learn
 
  postskills8 =~ post_Express_Ideas_Write + 
                 post_Express_Ideas_Speak + 
                 post_Collaborate_Academic + 
                 post_Analyz + post_Synthesize + 
                 post_Apply_New_Contexts + 
                 post_Consider_Ethics + 
                 post_Capable_Self_Learn
  
  postbelong2 =~ post_Belong_School_Commty + post_Helped_Belong_School_Commty

#regressions
  postskills8 ~ preskills8 + postbelong2 + posttransp8
'

fitFactTM1 <- sem(FactTM1, data=TILTSEM)

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

semPaths(fitFactTM1, whatLabels = "std", layout = "tree")

anova(fitMeasTM1,fitFactTM1)

Here is the model output for the two models (to show that they are identical):

=========================Pre-Post Measurement Model 1 - (TM)============================= Estimator ML Optimization method NLMINB Number of model parameters 58

                                              Used       Total

Number of observations 521 591

Model Test User Model:

Test statistic 1139.937 Degrees of freedom 293 P-value (Chi-square) 0.000

Model Test Baseline Model:

Test statistic 4720.060 Degrees of freedom 325 P-value 0.000

User Model versus Baseline Model:

Comparative Fit Index (CFI) 0.807 Tucker-Lewis Index (TLI) 0.786

Loglikelihood and Information Criteria:

Loglikelihood user model (H0) -13335.136 Loglikelihood unrestricted model (H1) -12765.167

Akaike (AIC) 26786.271 Bayesian (BIC) 27033.105 Sample-size adjusted Bayesian (BIC) 26849.000

Root Mean Square Error of Approximation:

RMSEA 0.074 90 Percent confidence interval - lower 0.070 90 Percent confidence interval - upper 0.079 P-value RMSEA <= 0.05 0.000

Standardized Root Mean Square Residual:

SRMR 0.068

=========================Pre-Post Factor Model 1 - (TM)======================

Estimator ML Optimization method NLMINB Number of model parameters 58

                                              Used       Total

Number of observations 521 591

Model Test User Model:

Test statistic 1139.937 Degrees of freedom 293 P-value (Chi-square) 0.000

Model Test Baseline Model:

Test statistic 4720.060 Degrees of freedom 325 P-value 0.000

User Model versus Baseline Model:

Comparative Fit Index (CFI) 0.807 Tucker-Lewis Index (TLI) 0.786

Loglikelihood and Information Criteria:

Loglikelihood user model (H0) -13335.136 Loglikelihood unrestricted model (H1) -12765.167

Akaike (AIC) 26786.271 Bayesian (BIC) 27033.105 Sample-size adjusted Bayesian (BIC) 26849.000

Root Mean Square Error of Approximation:

RMSEA 0.074 90 Percent confidence interval - lower 0.070 90 Percent confidence interval - upper 0.079 P-value RMSEA <= 0.05 0.000

Standardized Root Mean Square Residual:

SRMR 0.068


Solution

  • You aren't using up more degrees of freedom.

    One thing that makes lavaan::sem() dangerous to use over lavaan::lavaan() is that its defaults are hard to remember and/or notice. If you look at ?lavaan::sem, you will see those defaults:

    The sem function is a wrapper for the more general lavaan function, but setting the following default options: int.ov.free = TRUE, int.lv.free = FALSE, auto.fix.first = TRUE (unless std.lv = TRUE), auto.fix.single = TRUE, auto.var = TRUE, auto.cov.lv.x = TRUE, auto.efa = TRUE, auto.th = TRUE, auto.delta = TRUE, and auto.cov.y = TRUE

    You can find out what this means via ?lavOptions:

    auto.cov.lv.x: If TRUE, the covariances of exogenous latent variables are included in the model and set free.

    By default, all exogenous latent variables (i.e., all of your latent factors) are correlated in your model already.

    I'm also not sure how you are identifying the 2-item factor, so I'm surprised this does not throw a warnings, unless you're ignoring it.