SEM with latent variables

From parceled SEM to full latent-variable SEM; disattenuation

Author
Affiliation

George Michaelides

Norwich Business School, University of East Anglia

Published

July 7, 2026

Learning objectives

By the end of this tutorial you will be able to:

  • explain why modelling latent variables is preferable to modelling manifest scores
  • build a SEM that combines a measurement model (=~) with a structural model (~)
  • count degrees of freedom for a SEM by hand
  • compare path analysis estimates (manifest variables) with SEM estimates (latent variables) and understand disattenuation
  • fit a full latent-variable SEM with three factors and a mediation structure

Setup

Setup code (you have seen this before)
library(haven)
library(lavaan)
library(tidySEM)

Why latent variables?

In Tutorial 09 we fitted a path model with manifest variables — mean scores computed from the items. For example, pa was the mean of pa1, pa2, pa3. This is simple, but it has a cost: the mean score contains measurement error.

Measurement error has two consequences for regression:

  1. Attenuation. The regression coefficient of a variable measured with error is biased toward zero. If pa is an imperfect measure of the true positive-affect construct, the path from pa to creat will underestimate the true effect.

  2. Bias in other paths. When multiple predictors are measured with different amounts of error, the relative sizes of their coefficients are distorted — the more reliable predictor looks relatively stronger.

Modelling the latent variable behind the items removes these biases. The latent variable is the error-free part of the construct; the residual variances of the individual items absorb the measurement error. This is the central advantage of SEM over path analysis with manifest variables.

The trade-off

The cost of modelling latent variables is model complexity. A latent factor with three indicators adds parameters (loadings, residual variances) and the model must be identified. In return, you get:

  • Unbiased estimates of the structural paths
  • A testable measurement model — you can check whether the items load well on their factors
  • More degrees of freedom, which makes the overall model testable

From path analysis to SEM: parceled SEM

Our first SEM uses a parceled job-control factor (from Tutorial 08) alongside manifest pa and creat. This is a half-way house: one latent variable, two manifest variables. It is a common practical choice when you have many items for one construct but only three items for the others.

Building the parcels

ps$p1 <- (ps$con9 + ps$con10) / 2
ps$p2 <- (ps$con1 + ps$con8)  / 2
ps$p3 <- (ps$con3 + ps$con6)  / 2
ps$pa <- (ps$pa1 + ps$pa2 + ps$pa3) / 3
ps$creat <- (ps$creat1 + ps$creat2 + ps$creat3) / 3

The model

model_sem_parcel <- '
  # Measurement model for job control (latent)
  con =~ p1 + p2 + p3

  # Structural model
  creat ~ pa + con
  pa    ~ con
'

The # lines are comments inside the model string — lavaan ignores them. We use comments to separate the measurement and structural parts of the model, which makes the syntax easier to read as models grow.

We fit with sem():

fit_sem_parcel <- sem(model_sem_parcel, data = ps, estimator = "MLR")
summary(fit_sem_parcel, standardized = TRUE, fit.measures = TRUE, rsquare = TRUE)
## lavaan 0.6-21 ended normally after 22 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        11
## 
##                                                   Used       Total
##   Number of observations                           332         343
## 
## Model Test User Model:
##                                               Standard      Scaled
##   Test Statistic                                 0.965       0.927
##   Degrees of freedom                                 4           4
##   P-value (Chi-square)                           0.915       0.921
##   Scaling correction factor                                  1.041
##     Yuan-Bentler correction (Mplus variant)                       
## 
## Model Test Baseline Model:
## 
##   Test statistic                               402.002     378.803
##   Degrees of freedom                                10          10
##   P-value                                        0.000       0.000
##   Scaling correction factor                                  1.061
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    1.000       1.000
##   Tucker-Lewis Index (TLI)                       1.019       1.021
##                                                                   
##   Robust Comparative Fit Index (CFI)                         1.000
##   Robust Tucker-Lewis Index (TLI)                            1.020
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)              -1888.462   -1888.462
##   Scaling correction factor                                  0.912
##       for the MLR correction                                      
##   Loglikelihood unrestricted model (H1)      -1887.979   -1887.979
##   Scaling correction factor                                  0.946
##       for the MLR correction                                      
##                                                                   
##   Akaike (AIC)                                3798.923    3798.923
##   Bayesian (BIC)                              3840.780    3840.780
##   Sample-size adjusted Bayesian (SABIC)       3805.887    3805.887
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.000       0.000
##   90 Percent confidence interval - lower         0.000       0.000
##   90 Percent confidence interval - upper         0.031       0.026
##   P-value H_0: RMSEA <= 0.050                    0.979       0.983
##   P-value H_0: RMSEA >= 0.080                    0.002       0.002
##                                                                   
##   Robust RMSEA                                               0.000
##   90 Percent confidence interval - lower                     0.000
##   90 Percent confidence interval - upper                     0.029
##   P-value H_0: Robust RMSEA <= 0.050                         0.980
##   P-value H_0: Robust RMSEA >= 0.080                         0.002
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.008       0.008
## 
## Parameter Estimates:
## 
##   Standard errors                             Sandwich
##   Information bread                           Observed
##   Observed information based on                Hessian
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   con =~                                                                
##     p1                1.000                               0.687    0.772
##     p2                0.811    0.067   12.179    0.000    0.557    0.797
##     p3                0.899    0.072   12.483    0.000    0.618    0.794
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   creat ~                                                               
##     pa                0.187    0.043    4.335    0.000    0.187    0.237
##     con              -0.099    0.074   -1.343    0.179   -0.068   -0.080
##   pa ~                                                                  
##     con               0.244    0.092    2.642    0.008    0.168    0.155
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .p1                0.321    0.038    8.430    0.000    0.321    0.405
##    .p2                0.178    0.022    8.251    0.000    0.178    0.365
##    .p3                0.224    0.029    7.711    0.000    0.224    0.370
##    .creat             0.689    0.047   14.712    0.000    0.689    0.943
##    .pa                1.146    0.073   15.757    0.000    1.146    0.976
##     con               0.472    0.062    7.603    0.000    1.000    1.000
## 
## R-Square:
##                    Estimate
##     p1                0.595
##     p2                0.635
##     p3                0.630
##     creat             0.057
##     pa                0.024

Counting degrees of freedom

With \(q = 5\) observed variables (p1, p2, p3, pa, creat), the covariance matrix has \(5 \times 6 / 2 = 15\) non-redundant elements.

Free parameters:

  • 2 loadings on con (first fixed to 1 by marker-variable method)
  • 2 regression paths in the creat equation (pa, con)
  • 1 regression path in the pa equation (con)
  • 3 residual variances of the parcels
  • 1 residual variance of pa
  • 1 residual variance of creat
  • 1 latent variance of con

That is \(t = 11\). So \(\text{df} = 15 - 11 = 4\).

Reading the output

The output now has both a Latent variables section (the con =~ p1 + p2 + p3 loadings) and a Regressions section (the structural paths). Compare the structural paths to those from the path analysis in Tutorial 09:

  • The path from con to pa should be slightly larger in the SEM than in the path analysis — disattenuation removes the bias from con being measured with error.
  • The path from pa to creat should be similar — pa is still a manifest variable in this model.
  • The path from con to creat (direct effect) may also change.
NoteDisattenuation

When a predictor is measured with error, its regression coefficient is biased toward zero. Modelling the predictor as a latent variable (with the measurement error absorbed into the residual variances of its indicators) removes this bias. The latent-variable coefficient is typically larger in absolute value than the manifest-variable coefficient. This is called disattenuation — the coefficient has been “corrected for attenuation” due to measurement error.

Full latent-variable SEM

Now we make the full jump: all three constructs are latent variables, each measured by its own indicators.

The model

model_sem_full <- '
  # Measurement model
  con   =~ p1 + p2 + p3
  pa    =~ pa1 + pa2 + pa3
  creat =~ creat1 + creat2 + creat3

  # Structural model
  creat ~ pa + con
  pa    ~ con
'

We parcel only the job-control items (into p1, p2, p3) because there are six of them and we want a simpler measurement model. Positive affect and creativity are modelled at the item level with three indicators each.

Fitting the model

fit_sem_full <- sem(model_sem_full, data = ps, estimator = "MLR")
summary(fit_sem_full, standardized = TRUE, fit.measures = TRUE, rsquare = TRUE)
## lavaan 0.6-21 ended normally after 28 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        21
## 
##                                                   Used       Total
##   Number of observations                           332         343
## 
## Model Test User Model:
##                                               Standard      Scaled
##   Test Statistic                                25.528      24.788
##   Degrees of freedom                                24          24
##   P-value (Chi-square)                           0.378       0.417
##   Scaling correction factor                                  1.030
##     Yuan-Bentler correction (Mplus variant)                       
## 
## Model Test Baseline Model:
## 
##   Test statistic                              1289.618    1206.185
##   Degrees of freedom                                36          36
##   P-value                                        0.000       0.000
##   Scaling correction factor                                  1.069
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.999       0.999
##   Tucker-Lewis Index (TLI)                       0.998       0.999
##                                                                   
##   Robust Comparative Fit Index (CFI)                         0.999
##   Robust Tucker-Lewis Index (TLI)                            0.999
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)              -3551.266   -3551.266
##   Scaling correction factor                                  0.974
##       for the MLR correction                                      
##   Loglikelihood unrestricted model (H1)      -3538.503   -3538.503
##   Scaling correction factor                                  1.004
##       for the MLR correction                                      
##                                                                   
##   Akaike (AIC)                                7144.533    7144.533
##   Bayesian (BIC)                              7224.441    7224.441
##   Sample-size adjusted Bayesian (SABIC)       7157.828    7157.828
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.014       0.010
##   90 Percent confidence interval - lower         0.000       0.000
##   90 Percent confidence interval - upper         0.047       0.046
##   P-value H_0: RMSEA <= 0.050                    0.965       0.974
##   P-value H_0: RMSEA >= 0.080                    0.000       0.000
##                                                                   
##   Robust RMSEA                                               0.010
##   90 Percent confidence interval - lower                     0.000
##   90 Percent confidence interval - upper                     0.047
##   P-value H_0: Robust RMSEA <= 0.050                         0.969
##   P-value H_0: Robust RMSEA >= 0.080                         0.000
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.028       0.028
## 
## Parameter Estimates:
## 
##   Standard errors                             Sandwich
##   Information bread                           Observed
##   Observed information based on                Hessian
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   con =~                                                                
##     p1                1.000                               0.687    0.772
##     p2                0.810    0.067   12.160    0.000    0.557    0.797
##     p3                0.898    0.072   12.473    0.000    0.617    0.794
##   pa =~                                                                 
##     pa1               1.000                               0.956    0.806
##     pa2               1.046    0.075   13.952    0.000    1.000    0.780
##     pa3               1.090    0.076   14.379    0.000    1.042    0.843
##   creat =~                                                              
##     creat1            1.000                               0.745    0.753
##     creat2            1.047    0.077   13.540    0.000    0.780    0.818
##     creat3            1.127    0.080   14.086    0.000    0.840    0.855
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   creat ~                                                               
##     pa                0.205    0.054    3.789    0.000    0.264    0.264
##     con              -0.102    0.069   -1.465    0.143   -0.094   -0.094
##   pa ~                                                                  
##     con               0.227    0.091    2.496    0.013    0.163    0.163
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .p1                0.320    0.038    8.412    0.000    0.320    0.404
##    .p2                0.178    0.022    8.248    0.000    0.178    0.364
##    .p3                0.224    0.029    7.734    0.000    0.224    0.370
##    .pa1               0.492    0.077    6.359    0.000    0.492    0.350
##    .pa2               0.645    0.073    8.851    0.000    0.645    0.392
##    .pa3               0.444    0.065    6.881    0.000    0.444    0.290
##    .creat1            0.423    0.042    9.979    0.000    0.423    0.432
##    .creat2            0.300    0.037    8.162    0.000    0.300    0.330
##    .creat3            0.259    0.039    6.578    0.000    0.259    0.268
##     con               0.472    0.062    7.597    0.000    1.000    1.000
##    .pa                0.890    0.105    8.485    0.000    0.973    0.973
##    .creat             0.517    0.065    7.914    0.000    0.930    0.930
## 
## R-Square:
##                    Estimate
##     p1                0.596
##     p2                0.636
##     p3                0.630
##     pa1               0.650
##     pa2               0.608
##     pa3               0.710
##     creat1            0.568
##     creat2            0.670
##     creat3            0.732
##     pa                0.027
##     creat             0.070

Counting degrees of freedom

With \(q = 9\) observed variables (p1, p2, p3, pa1, pa2, pa3, creat1, creat2, creat3), the covariance matrix has \(9 \times 10 / 2 = 45\) non-redundant elements.

Free parameters:

  • 2 loadings on con + 2 loadings on pa + 2 loadings on creat = 6 loadings
  • 2 regression paths in creat equation + 1 in pa equation = 3 structural paths
  • 3 parcel residual variances + 3 pa residual variances + 3 creat residual variances = 9 indicator residual variances
  • 1 latent variance of con + 1 residual variance of pa + 1 residual variance of creat = 3 latent (residual) variances

That is \(t = 6 + 3 + 9 + 3 = 21\). So \(\text{df} = 45 - 21 = 24\).

Fit indices

fitMeasures(fit_sem_full, c("chisq", "df", "pvalue",
                            "cfi", "tli",
                            "rmsea", "rmsea.ci.lower", "rmsea.ci.upper",
                            "srmr"))
##          chisq             df         pvalue            cfi            tli 
##         25.528         24.000          0.378          0.999          0.998 
##          rmsea rmsea.ci.lower rmsea.ci.upper           srmr 
##          0.014          0.000          0.047          0.028

The model has 24 degrees of freedom — plenty of information to test it. If the fit indices meet the Hu and Bentler cutoffs, the model’s structure is consistent with the data.

Comparing path analysis, parceled SEM, and full SEM

Let us compare the key structural paths across the three models:

# Path analysis (manifest variables) — from Tutorial 09
ps$con_m <- (ps$con1 + ps$con3 + ps$con6 + ps$con8 + ps$con9 + ps$con10) / 6
ps$pa_m  <- (ps$pa1 + ps$pa2 + ps$pa3) / 3
ps$cr_m  <- (ps$creat1 + ps$creat2 + ps$creat3) / 3

model_path_m <- '
  cr_m ~ pa_m + con_m
  pa_m ~ con_m
'
fit_path <- sem(model_path_m, data = ps, estimator = "MLR")

# Extract standardised structural paths from each model
get_paths <- function(fit) {
  pe <- parameterEstimates(fit, standardized = TRUE)
  pe[pe$op == "~", c("lhs", "rhs", "std.all")]
}

paths_path  <- get_paths(fit_path)
paths_parcel <- get_paths(fit_sem_parcel)
paths_full   <- get_paths(fit_sem_full)

paths_path
##    lhs   rhs std.all
## 1 cr_m  pa_m   0.235
## 2 cr_m con_m  -0.073
## 3 pa_m con_m   0.144
paths_parcel
##     lhs rhs std.all
## 4 creat  pa   0.237
## 5 creat con  -0.080
## 6    pa con   0.155
paths_full
##      lhs rhs std.all
## 10 creat  pa   0.264
## 11 creat con  -0.094
## 12    pa con   0.163

The comparison shows:

  • The path from con to pa is larger in the SEM models than in the path analysis — disattenuation corrects for the measurement error in job control.
  • The path from pa to creat is larger in the full SEM than in the parceled SEM or path analysis — disattenuation corrects for the measurement error in positive affect.
  • The direct path from con to creat may change in either direction.

This is the core argument for SEM over path analysis with manifest scores: the structural paths are unbiased estimates of the true relationships among the constructs, not the attenuated estimates you get from imperfectly-measured scores.

Drawing the full SEM

tidySEM::graph_sem(fit_sem_full, std = TRUE)

Path diagram for the full latent-variable SEM. Job control (con) is a latent factor measured by three parcels; positive affect (pa) and creativity (creat) are latent factors measured by three items each. Structural paths: con -> pa, con -> creat, pa -> creat.

The diagram shows both layers of the model:

  • Measurement layer: arrows from each latent factor (circle) to its indicators (squares)
  • Structural layer: arrows among the latent factors — con → pa, con → creat, pa → creat

Mathematical foundation (optional)

A full SEM combines a measurement model with a structural model. In matrix form:

Measurement model:

\[ \mathbf{y} = \mathbf{\Lambda} \mathbf{\eta} + \mathbf{\varepsilon} \]

This is the same as the CFA matrix form from Tutorial 06 — observed variables (\(\mathbf{y}\)) are linear functions of latent variables (\(\mathbf{\eta}\)) plus measurement error (\(\mathbf{\varepsilon}\)).

Structural model:

\[ \mathbf{\eta} = \mathbf{B} \mathbf{\eta} + \mathbf{\zeta} \tag{1}\]

Here \(\mathbf{B}\) is a matrix of structural coefficients (the regression paths among latent variables) and \(\mathbf{\zeta}\) is a vector of disturbances — the residual variances of the endogenous latent variables.

The model-implied covariance matrix combines both:

\[ \hat{\Sigma}(\theta) = \mathbf{\Lambda} (\mathbf{I} - \mathbf{B})^{-1} \mathbf{\Psi} (\mathbf{I} - \mathbf{B})^{-T} \mathbf{\Lambda}' + \mathbf{\Theta} \tag{2}\]

You do not need to manipulate these matrices to use lavaan. They are included here so you recognise the notation when you encounter it in SEM papers. For the rest of this series we use the simplified lowercase Greek symbols (\(\lambda\), \(\beta\), \(\psi\), \(\theta\), \(\zeta\)).

Common errors

Warninglavaan WARNING: model has not converged in full SEM

A full SEM with many indicators and structural paths is more likely to have convergence problems than a simple CFA. Check for Heywood cases (negative variances), check that every factor has at least three indicators, and consider parceling some of the indicators to simplify the measurement model.

Very different estimates between path analysis and SEM

If the SEM estimates are dramatically different from the path analysis estimates, check whether the measurement model fits well on its own (fit a CFA first). A poorly-fitting measurement model can distort the structural estimates.

Negative residual variance for a latent dependent variable

If pa or creat has a negative disturbance variance (\(\zeta\)), the structural model may be misspecified. Consider whether the structural paths are theoretically justified, and whether there are omitted predictors that should be included.

Exercises

  1. Fit the parceled SEM from the tutorial (job control as a latent factor measured by p1, p2, p3; pa and creat as manifest mean scores). Compare the standardised path from con to pa to the same path from the path analysis in Tutorial 09. Is the SEM estimate larger? Why?

  2. Fit the full latent-variable SEM (all three constructs as latent factors). Write down the standardised structural paths and the \(R^2\) for creat. How much of the variance in creativity is explained by the model?

  3. Count the degrees of freedom for the full SEM by hand (using the t-rule). Confirm that your count matches the df reported by fitMeasures().

  4. Compare the parceled SEM and the full SEM using lavTestLRT(). Which model fits better? Is the more complex full SEM justified, or does the simpler parceled model fit as well?

Exercise 1

fitMeasures(fit_sem_parcel, c("chisq", "df", "pvalue", "cfi", "tli",
                              "rmsea", "srmr"))
##  chisq     df pvalue    cfi    tli  rmsea   srmr 
##  0.965  4.000  0.915  1.000  1.019  0.000  0.008
get_paths(fit_path)
##    lhs   rhs std.all
## 1 cr_m  pa_m   0.235
## 2 cr_m con_m  -0.073
## 3 pa_m con_m   0.144
get_paths(fit_sem_parcel)
##     lhs rhs std.all
## 4 creat  pa   0.237
## 5 creat con  -0.080
## 6    pa con   0.155

The con → pa path from the parceled SEM should be larger than the same path from the path analysis. This is disattenuation — the latent con factor is free of measurement error, so its coefficient is not biased toward zero.

Exercise 2

summary(fit_sem_full, standardized = TRUE, rsquare = TRUE)
## lavaan 0.6-21 ended normally after 28 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        21
## 
##                                                   Used       Total
##   Number of observations                           332         343
## 
## Model Test User Model:
##                                               Standard      Scaled
##   Test Statistic                                25.528      24.788
##   Degrees of freedom                                24          24
##   P-value (Chi-square)                           0.378       0.417
##   Scaling correction factor                                  1.030
##     Yuan-Bentler correction (Mplus variant)                       
## 
## Parameter Estimates:
## 
##   Standard errors                             Sandwich
##   Information bread                           Observed
##   Observed information based on                Hessian
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   con =~                                                                
##     p1                1.000                               0.687    0.772
##     p2                0.810    0.067   12.160    0.000    0.557    0.797
##     p3                0.898    0.072   12.473    0.000    0.617    0.794
##   pa =~                                                                 
##     pa1               1.000                               0.956    0.806
##     pa2               1.046    0.075   13.952    0.000    1.000    0.780
##     pa3               1.090    0.076   14.379    0.000    1.042    0.843
##   creat =~                                                              
##     creat1            1.000                               0.745    0.753
##     creat2            1.047    0.077   13.540    0.000    0.780    0.818
##     creat3            1.127    0.080   14.086    0.000    0.840    0.855
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   creat ~                                                               
##     pa                0.205    0.054    3.789    0.000    0.264    0.264
##     con              -0.102    0.069   -1.465    0.143   -0.094   -0.094
##   pa ~                                                                  
##     con               0.227    0.091    2.496    0.013    0.163    0.163
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .p1                0.320    0.038    8.412    0.000    0.320    0.404
##    .p2                0.178    0.022    8.248    0.000    0.178    0.364
##    .p3                0.224    0.029    7.734    0.000    0.224    0.370
##    .pa1               0.492    0.077    6.359    0.000    0.492    0.350
##    .pa2               0.645    0.073    8.851    0.000    0.645    0.392
##    .pa3               0.444    0.065    6.881    0.000    0.444    0.290
##    .creat1            0.423    0.042    9.979    0.000    0.423    0.432
##    .creat2            0.300    0.037    8.162    0.000    0.300    0.330
##    .creat3            0.259    0.039    6.578    0.000    0.259    0.268
##     con               0.472    0.062    7.597    0.000    1.000    1.000
##    .pa                0.890    0.105    8.485    0.000    0.973    0.973
##    .creat             0.517    0.065    7.914    0.000    0.930    0.930
## 
## R-Square:
##                    Estimate
##     p1                0.596
##     p2                0.636
##     p3                0.630
##     pa1               0.650
##     pa2               0.608
##     pa3               0.710
##     creat1            0.568
##     creat2            0.670
##     creat3            0.732
##     pa                0.027
##     creat             0.070

The standardised structural paths appear in the Regressions section. The \(R^2\) for creat appears in the R-Square section — it tells you what proportion of the variance in the creativity latent factor is explained by pa and con.

Exercise 3

With \(q = 9\) observed variables, the covariance matrix has \(9 \times 10 / 2 = 45\) elements. Free parameters: 6 loadings + 3 structural paths + 9 indicator residual variances + 3 latent (residual) variances = 21. So \(\text{df} = 45 - 21 = 24\). Confirm with:

fitMeasures(fit_sem_full, "df")
## df 
## 24

Exercise 4

lavTestLRT(fit_sem_parcel, fit_sem_full)
## 
## Scaled Chi-Squared Difference Test (method = "satorra.bentler.2001")
## 
## lavaan->lavTestLRT():  
##    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    RMSEA Df diff Pr(>Chisq)
## fit_sem_parcel  4 3798.9 3840.8  0.9648                                       
## fit_sem_full   24 7144.5 7224.4 25.5278     23.903 0.024577      20     0.2467

A significant result means the full SEM fits significantly better than the parceled SEM — the additional latent variables (pa and creat) improve the model. A non-significant result means the simpler parceled model fits as well. Note that the two models are not strictly nested (the parceled model uses manifest pa and creat, while the full model uses latent pa and creat), so the likelihood-ratio test is approximate. Compare the AIC/BIC values as well for a non-nested comparison.

Summary & next tutorial

You have moved from path analysis with manifest variables to full structural equation modelling with latent variables. You have seen how disattenuation changes the structural path estimates, how to count degrees of freedom for a SEM, and how to draw the full model with tidySEM. The model we fitted — con → pa → creat with a direct path con → creat — is the structure of a mediation model. In the next two tutorials we develop the theory of mediation (Tutorial 11) and then fit it in lavaan with bootstrap confidence intervals (Tutorial 12).

Further reading

  • Kelloway (2015) — chapters 4 and 5 cover SEM with latent variables and the comparison to path analysis.
  • Beaujean (2014) — a lavaan-based walkthrough of full SEM, including the matrix form.
  • Bollen (1989) — the canonical reference for the mathematical foundations of SEM.
  • Hoyle (2012) — the Handbook of Structural Equation Modeling, comprehensive reference for every aspect of SEM.

References

Beaujean, A. A. (2014). Latent variable modeling using r: A step-by-step guide. Routledge.
Bollen, K. A. (1989). Structural equations with latent variables. Wiley Series in Probability and Mathematical Statistics.
Hoyle, R. H. (2012). Handbook of structural equation modeling.
Kelloway, E. K. (2015). Using mplus for structural equation modeling (2nd ed.). SAGE Publications.