10 CFA and SEM with lavaan
10.1 Confirmatory Factor Analysis (CFA)
Lavaan is a free open source package for latent variable modeling in R. The lavaan
package is developed and maintained by Yves Rosseel (Rosseel, 2012; see also http://lavaan.ugent.be). The name lavaan
refers to latent variable analysis. Lavaan can be used to estimate a variety of statistical models: path analysis, structural equation models (SEM) and confirmatory factor analyses (CFA).
10.1.1 Setup: Packages and data
pacman::p_load(tidyverse, ggplot2, ggthemes, haven, lavaan, lavaanPlot, knitr, psych,
semPlot, semTools, wesanderson)
# Import data
data <- read_sav("data/adolescents_ls.sav")
# Select life satisfaction items
ls <- data %>%
select(num_range("life", 1:10)) %>%
drop_na
The life satisfaction data consist of 10 items relating to different aspects/areas of life satisfaction. The adolescents were asked:
“How satisfied are you with…?”
Items | |
---|---|
life1 | your school grade |
life2 | your looks and appearance |
life3 | your relationship with your teacher |
life4 | your school life |
life5 | your social life |
life6 | your personality |
life7 | your relationships with your friends |
life8 | your relationship with your parents |
life9 | your family life |
life10 | your socio-economic status |
The response was on a 7-point scale from 1 = “not satisfied at all” to 7 = “very satisfied”.
The questions on life satisfaction can be divided into four domains. We rename the variables in such a way that it becomes clear which LS domain they belong to. To bring the order of the variables in line with their content domains, we also change the order using select()
.
ls <- ls %>%
rename(fam1 = life8,
fam2 = life9,
fam3 = life10,
school1 = life1,
school2 = life3,
school3 = life4,
self1 = life2,
self2 = life6,
friends1 = life5,
friends2 = life7
) %>%
select(school1, school2, school3, self1, self2,
friends1, friends2, fam1, fam2, fam3)
Remove outliers
The ML estimation assumes a multivariate normal distribution. We can check multivariate skewness and kurtosis (Mardia’s coefficients):
mardiaSkew(ls, use = "everything")
#> b1d chi df p
#> 3.209181e+01 1.476223e+03 2.200000e+02 9.489595e-185
mardiaKurtosis(ls, use = "everything")
#> b2d z p
#> 191.24697 38.20193 0.00000
Both skewness and kurtosis are very high, pointing to multivariate outliers that might inflate standard errors of coefficients (coefficients themselves are mostly unaffected by non-normality).
Thus, we remove all subjects/observations with values outside +/- 3 SD from the mean on at least one of the ten life satisfaction variables. By removing univariate outliers we also want to make sure that influential data points play no role for the factor solution.
# Definition of a `keep` function that only selects data points that are between
# +/- 3 standard deviations of a variable
keep <- function(x) {
(x >= mean(x) - 3*sd(x)) &
(x <= mean(x) + 3*sd(x))
}
# Selecting these data points with `filter` and assigning them to a new data set
ls_clean <- ls %>%
filter(keep(school1) &
keep(school2) &
keep(school3) &
keep(self1) &
keep(self2) &
keep(friends1) &
keep(friends2) &
keep(fam1) &
keep(fam2) &
keep(fam3))
Check Mardia’s coefficients again:
mardiaSkew(ls_clean, use = "everything")
#> b1d chi df p
#> 1.306214e+01 5.551409e+02 2.200000e+02 6.851861e-31
mardiaKurtosis(ls_clean, use = "everything")
#> b2d z p
#> 1.370003e+02 8.761739e+00 1.922612e-18
Much smaller but still significant!
10.1.2 Defining the CFA model in lavaan
The calculation of a CFA with lavaan
in done in two steps: in the first step, a model defining the hypothesized factor structure has to be set up; in the second step this model is estimated using cfa()
. This function takes as input the data as well as the model definition. Model definitions in lavaan
all follow the same type of syntax.
In the syntax, certain characters (operators) are predefined and a number of default settings are applied. For example, by default the scaling of the latent variable is achieved by fixing the loading of the first indicator (manifest variable) for a certain latent variable to the value of 1
.
=~
means that the latent variable (here named Factor1
) to the left of the operator is defined by all variables to the right of it. The manifest (measured) variables from the dataset on the right are separated by a +
.
An example of six items explained by two factors (latent variables):
example_model <- "
Factor1 =~ var1 + var2 + var3
Factor2 =~ var4 + var5 + var6
# The order of the manifest variables is relevant only for fixing one loading per factor.
# Here the loadings of `var1` and `var4` are set to the value 1.
# Comments like this are ignored by lavaan.
"
The parameters of the model do not have to be explicitly defined (e.g. l12 for the loading of the second item (var2
) on the first factor (Factor1
). However, they could be defined explicitly and we will see below that this is necessary in some situations.
Another default is that factor variances and covariances are automatically specified for all latent variables in a CFA. The operator for specifying a variance/covariance is ~~
. Variances are defined as covariances of a variable with itself. I.e. in this example we could add the lines Factor1 ~~ Factor1
, Factor2 ~~ Factor2
(latent variable variances), and Factor1 ~~ Factor2
(latent variable covariance) without changing the model definition. The same holds for the residual variances of the manifest variables (but not for potential residual covariances!).
10.1.3 Estimating the model
Syntax for estimation: cfa(model = example_model, data = dataframe)
However, the direct execution of this syntax results in only a very limited output, containing only the number of estimated parameters, the number of observations, and the chi-square statistics.
Therefore, the result of cfa()
must first be assigned to an output object (e.g. fit_example_model
) and the detailed output (including the parameter estimates) extracted with summary(fit_example_model)
. For the summary()
-function there are some additional arguments: fit.measures = TRUE
outputs a number of global fit indices (e.g. SRMR, RMSEA, CLI, TLI) as well as information criteria (e.g. AIC and BIC), and with standardized = TRUE
we get the standardized parameter estimators as well as the unstandardized parameter estimators.
10.1.4 CFA with four factors
For theoretical reasons, we first estimate a model with four factors. We define one factor for each content domain of life satisfaction (school, self, friends, family). In addition, as usual we postulate a simple structure, i.e. all potential cross-loadings are restricted to the value 0 (manifest variables appear only in the equation of their respective factor).
Modell definition
model_4f <- "
school =~ school1 + school2 + school3
self =~ self1 + self2
friends =~ friends1 + friends2
family =~ fam1 + fam2 + fam3
"
In a figure:
Model estimation
fit_mod4f <- cfa(model_4f, data = ls_clean)
summary(fit_mod4f, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 40 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 26
#>
#> Number of observations 255
#>
#> Estimator ML
#> Model Fit Test Statistic 51.433
#> Degrees of freedom 29
#> P-value (Chi-square) 0.006
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 583.039
#> Degrees of freedom 45
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.958
#> Tucker-Lewis Index (TLI) 0.935
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3427.760
#> Loglikelihood unrestricted model (H1) -3402.044
#>
#> Number of free parameters 26
#> Akaike (AIC) 6907.520
#> Bayesian (BIC) 6999.593
#> Sample-size adjusted Bayesian (BIC) 6917.166
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.055
#> 90 Percent Confidence Interval 0.029 0.079
#> P-value RMSEA <= 0.05 0.341
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.053
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> school =~
#> school1 1.000 0.572 0.420
#> school2 1.431 0.257 5.572 0.000 0.819 0.638
#> school3 1.995 0.403 4.947 0.000 1.141 0.858
#> self =~
#> self1 1.000 0.730 0.669
#> self2 0.940 0.156 6.028 0.000 0.685 0.784
#> friends =~
#> friends1 1.000 0.661 0.791
#> friends2 0.614 0.117 5.235 0.000 0.406 0.531
#> family =~
#> fam1 1.000 0.782 0.742
#> fam2 1.061 0.129 8.233 0.000 0.830 0.846
#> fam3 0.598 0.084 7.136 0.000 0.467 0.510
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> school ~~
#> self 0.075 0.039 1.947 0.052 0.180 0.180
#> friends 0.111 0.039 2.862 0.004 0.293 0.293
#> family 0.098 0.040 2.427 0.015 0.219 0.219
#> self ~~
#> friends 0.296 0.059 5.049 0.000 0.614 0.614
#> family 0.142 0.052 2.735 0.006 0.249 0.249
#> friends ~~
#> family 0.178 0.048 3.700 0.000 0.344 0.344
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .school1 1.528 0.147 10.414 0.000 1.528 0.824
#> .school2 0.978 0.137 7.130 0.000 0.978 0.593
#> .school3 0.469 0.209 2.245 0.025 0.469 0.265
#> .self1 0.656 0.100 6.575 0.000 0.656 0.552
#> .self2 0.295 0.076 3.865 0.000 0.295 0.386
#> .friends1 0.262 0.079 3.301 0.001 0.262 0.375
#> .friends2 0.419 0.047 8.948 0.000 0.419 0.718
#> .fam1 0.498 0.079 6.336 0.000 0.498 0.449
#> .fam2 0.274 0.077 3.574 0.000 0.274 0.285
#> .fam3 0.622 0.061 10.240 0.000 0.622 0.740
#> school 0.327 0.109 3.001 0.003 1.000 1.000
#> self 0.532 0.120 4.452 0.000 1.000 1.000
#> friends 0.437 0.095 4.594 0.000 1.000 1.000
#> family 0.611 0.109 5.593 0.000 1.000 1.000
Visualizing the model
We visualize structural equation models using semPlot
.
semPaths(fit_mod4f, "par", weighted = FALSE, nCharNodes = 7, shapeMan = "rectangle",
sizeMan = 8, sizeMan2 = 5)
Local model fit: Comparing the empirical and implied variance-covariance matrix
The lavInspect()
function allows extracting information from a lavaan object. The argument what
specifies which information should be extracted. The value sampstat
of this argument stands for “sample statistics”, the empirical variance-covariance matrix:
lavInspect(fit_mod4f, what = "sampstat")
#> $cov
#> schol1 schol2 schol3 self1 self2 frnds1 frnds2 fam1 fam2 fam3
#> school1 1.855
#> school2 0.444 1.648
#> school3 0.640 0.944 1.771
#> self1 0.104 0.156 0.235 1.189
#> self2 0.167 0.015 0.105 0.500 0.765
#> friends1 0.193 0.088 0.249 0.312 0.271 0.699
#> friends2 0.043 0.095 0.098 0.151 0.183 0.268 0.584
#> fam1 0.369 0.134 0.159 0.136 0.189 0.170 0.168 1.110
#> fam2 0.258 0.162 0.137 0.067 0.118 0.164 0.116 0.656 0.962
#> fam3 0.136 0.173 0.242 0.144 0.198 0.160 0.099 0.326 0.394 0.841
The variance-covariance matrix implied by the model is obtained with what = 'implied'
:
lavInspect(fit_mod4f, what = "implied")
#> $cov
#> schol1 schol2 schol3 self1 self2 frnds1 frnds2 fam1 fam2 fam3
#> school1 1.855
#> school2 0.468 1.648
#> school3 0.653 0.934 1.771
#> self1 0.075 0.108 0.150 1.189
#> self2 0.071 0.101 0.141 0.500 0.765
#> friends1 0.111 0.159 0.221 0.296 0.278 0.699
#> friends2 0.068 0.097 0.136 0.182 0.171 0.268 0.584
#> fam1 0.098 0.140 0.196 0.142 0.134 0.178 0.109 1.110
#> fam2 0.104 0.149 0.208 0.151 0.142 0.189 0.116 0.649 0.962
#> fam3 0.059 0.084 0.117 0.085 0.080 0.106 0.065 0.365 0.388 0.841
The smaller the differences between these two matrices, the better the model fits the data, i.e. the closer the variances and covariances recalculated from the estimated parameters are to the empirical variances and covariances.
The residual matrix results from the subtraction of the variance-covariance matrix implied by the model from the observed (empirical) variance-covariance matrix.
residual_matrix <-
lavInspect(fit_mod4f, what = "sampstat")$cov -
lavInspect(fit_mod4f, what = "implied")$cov
residual_matrix
#> schol1 schol2 schol3 self1 self2 frnds1 frnds2 fam1 fam2
#> school1 0.000
#> school2 -0.024 0.000
#> school3 -0.013 0.009 0.000
#> self1 0.028 0.049 0.085 0.000
#> self2 0.096 -0.086 -0.036 0.000 0.000
#> friends1 0.082 -0.070 0.028 0.016 -0.007 0.000
#> friends2 -0.025 -0.002 -0.038 -0.031 0.012 0.000 0.000
#> fam1 0.271 -0.007 -0.037 -0.006 0.055 -0.008 0.059 0.000
#> fam2 0.154 0.013 -0.071 -0.084 -0.023 -0.024 0.001 0.007 0.000
#> fam3 0.077 0.089 0.125 0.059 0.118 0.054 0.034 -0.040 0.006
#> fam3
#> school1
#> school2
#> school3
#> self1
#> self2
#> friends1
#> friends2
#> fam1
#> fam2
#> fam3 0.000
A direct extraction of the residual matrix is possible with the argument what = "resid"
:
lavInspect(fit_mod4f, what = "resid")
#> $cov
#> schol1 schol2 schol3 self1 self2 frnds1 frnds2 fam1 fam2
#> school1 0.000
#> school2 -0.024 0.000
#> school3 -0.013 0.009 0.000
#> self1 0.028 0.049 0.085 0.000
#> self2 0.096 -0.086 -0.036 0.000 0.000
#> friends1 0.082 -0.070 0.028 0.016 -0.007 0.000
#> friends2 -0.025 -0.002 -0.038 -0.031 0.012 0.000 0.000
#> fam1 0.271 -0.007 -0.037 -0.006 0.055 -0.008 0.059 0.000
#> fam2 0.154 0.013 -0.071 -0.084 -0.023 -0.024 0.001 0.007 0.000
#> fam3 0.077 0.089 0.125 0.059 0.118 0.054 0.034 -0.040 0.006
#> fam3
#> school1
#> school2
#> school3
#> self1
#> self2
#> friends1
#> friends2
#> fam1
#> fam2
#> fam3 0.000
Particularly relevant for the local fit diagnostics is the variance-covariance matrix of standardized residuals. This cannot be obtained using lavInspect()
, but with the function resid()
.
resid(fit_mod4f, type = "standardized")
#> $type
#> [1] "standardized"
#>
#> $cov
#> schol1 schol2 schol3 self1 self2 frnds1 frnds2 fam1 fam2
#> school1 0.000
#> school2 -0.640 0.000
#> school3 -1.035 2.314 0.000
#> self1 0.336 0.698 1.529 0.000
#> self2 1.437 -1.738 -1.196 0.000 0.000
#> friends1 1.331 -1.659 1.254 1.235 -0.901 0.000
#> friends2 -0.421 -0.044 -0.843 -1.100 0.680 0.000 0.000
#> fam1 3.298 -0.106 -0.764 -0.126 1.645 -0.266 1.560 0.000
#> fam2 2.081 0.243 -2.382 -2.080 -1.010 -1.338 0.017 2.679 0.000
#> fam3 1.064 1.357 1.960 1.080 2.829 1.386 0.892 -2.809 0.790
#> fam3
#> school1
#> school2
#> school3
#> self1
#> self2
#> friends1
#> friends2
#> fam1
#> fam2
#> fam3 0.000
The following standardisized residuals turn out to be significant (absolute value \(\geq 2.58\: \widehat=\: p\leq 0.01\))
fam1 ~~ schule1 = 3.298
fam3 ~~ selbst2 = -2.829
fam3 ~~ fam1 = -2.809
fam2 ~~ fam1 = 2.679
Global model fit
For CFI = 0.958 and NNFI/TLI = 0.935 values around the recommended cut-off criterion of 0.97/0.95 resulted. The RMSEA = 0.055 is slightly above the cut-off of 0.05, but it is not significantly higher than 0.05 (90 % CI = [0.029; 0.079]). Furthermore, the SRMR = 0.053 points to a good model fit (SRMR < 0.08).
Exemplary computation of CFI, NNFI/TLI, AIC, and BIC:
\(CFI=1-\frac{\chi_{t}^{2}-d f_{t}}{\chi_{i}^{2}-d f_{i}}=1-\frac{51.433-29}{583.039 -45}=1-\frac{22.433}{538.039}=0.958\)
\(NNFI/TLI = \left(\frac{\chi_{i}^{2}}{d f_{i}}-\frac{\chi_{t}^{2}}{d f_{t}}\right)/\left({\frac{\chi_{i}^{2}}{d f_{i}}-1}\right) = \left(\frac{583.039}{45}-\frac{51.433}{29}\right)/\left({\frac{583.039}{45}-1}\right) = \frac{12.956-1.774}{12.956-1} = 0.935\)
\(AIC=-2(logL) + 2 \cdot t= -2 \cdot (-3427.76) + 2 \cdot 26 = 6907.52\)
\(BIC=-2(logL) + \log (n) \cdot t =-2 \cdot (-3427.76) + \log (255) \cdot 26= 6999.59\)
10.1.5 CFA with three factors
Model definition
Since a prior PCA suggested that 3 factors might be enough we want to check this using a CFA approach. Thus, we define an additional model with only three factors (friends and self factors are combined). (Ideally, the PCA should not have been carried out on the same data.)
model_3f <- "
school =~ school1 + school2 + school3
self_friends =~ self1 + self2 + friends1 + friends2
family =~ fam1 + fam2 + fam3
"
Model estimation
fit_mod3f <- cfa(model_3f, data = ls_clean)
summary(fit_mod3f, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 39 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 23
#>
#> Number of observations 255
#>
#> Estimator ML
#> Model Fit Test Statistic 79.522
#> Degrees of freedom 32
#> P-value (Chi-square) 0.000
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 583.039
#> Degrees of freedom 45
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.912
#> Tucker-Lewis Index (TLI) 0.876
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3441.804
#> Loglikelihood unrestricted model (H1) -3402.044
#>
#> Number of free parameters 23
#> Akaike (AIC) 6929.609
#> Bayesian (BIC) 7011.058
#> Sample-size adjusted Bayesian (BIC) 6938.142
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.076
#> 90 Percent Confidence Interval 0.055 0.098
#> P-value RMSEA <= 0.05 0.021
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.064
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> school =~
#> school1 1.000 0.577 0.424
#> school2 1.436 0.258 5.574 0.000 0.828 0.645
#> school3 1.954 0.393 4.971 0.000 1.127 0.847
#> self_friends =~
#> self1 1.000 0.686 0.629
#> self2 0.889 0.127 7.006 0.000 0.610 0.698
#> friends1 0.741 0.110 6.722 0.000 0.509 0.608
#> friends2 0.502 0.092 5.465 0.000 0.344 0.450
#> family =~
#> fam1 1.000 0.787 0.747
#> fam2 1.048 0.128 8.191 0.000 0.824 0.840
#> fam3 0.596 0.084 7.131 0.000 0.469 0.511
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> school ~~
#> self_friends 0.103 0.039 2.616 0.009 0.261 0.261
#> family 0.102 0.041 2.468 0.014 0.225 0.225
#> self_friends ~~
#> family 0.178 0.051 3.507 0.000 0.331 0.331
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .school1 1.522 0.147 10.379 0.000 1.522 0.821
#> .school2 0.962 0.139 6.926 0.000 0.962 0.584
#> .school3 0.501 0.206 2.429 0.015 0.501 0.283
#> .self1 0.718 0.087 8.236 0.000 0.718 0.604
#> .self2 0.393 0.057 6.907 0.000 0.393 0.513
#> .friends1 0.441 0.051 8.572 0.000 0.441 0.630
#> .friends2 0.466 0.046 10.154 0.000 0.466 0.797
#> .fam1 0.491 0.079 6.189 0.000 0.491 0.443
#> .fam2 0.283 0.077 3.700 0.000 0.283 0.295
#> .fam3 0.621 0.061 10.222 0.000 0.621 0.739
#> school 0.333 0.110 3.019 0.003 1.000 1.000
#> self_friends 0.470 0.103 4.571 0.000 1.000 1.000
#> family 0.619 0.110 5.607 0.000 1.000 1.000
Visualizing the model
semPaths(fit_mod3f, "par", weighted = FALSE, nCharNodes = 7, shapeMan = "rectangle",
sizeMan = 8, sizeMan2 = 5)
And now with standardized parameter estimates:
semPaths(fit_mod3f, "std", weighted = FALSE, nCharNodes = 7, shapeMan = "rectangle",
sizeMan = 8, sizeMan2 = 5)
Global model fit
CFI = 0.912 and NNFI/TLI = 0.876 do not reach the recommended cut-off criteria. The RMSEA = 0.076 now is also significantly higher than 0.05 (90 %-CI [0.055; 0.098]).
Alternative definition of the 3-factor model
A 3-factor model can alternatively be specified by restricting certain parameters of the 4-factor model. This allows us to show that the 3-factor model is nested in the 4-factor model.
To turn the 4-factor model into a 3-factor model with a combined self-and-friends-factor, we have to make sure that the factors friends
and self
behave like a single factor using parameter restrictions.
For these two factors to become one, the covariance between the two factors must be set to 1
(see syntax below). For a covariance of 1
to really represent an exact equality of the two factors, the variances of the two latent variables must also be set to 1 (thus the correlation between the latent variables becomes 1
). The easiest way to achieve this is to set the variances of all latent variables to the value 1 using the cfa()
argument std.lv = TRUE
, which at the same time ensures that the loadings of the first manifest variables of each factor are also estimated freely. This aspect is not defined in the model definition, but in the model estimation.
On the other hand, the relationships of the factors with all other factors must be identical for both factors (friends
and self
). We can achieve this by naming (i.e. explicitly specifying) the parameters of the factor covariances and at the same time giving the same name to the two parameters to be equated. For example, the covariance of friends
and school
should be estimated exactly the same as the covariance between self
and school
. If we name both parameters to be estimated with a
, lavaan recognizes that the same value should be estimated for both covariances.
We call this model model_4f_res
.
model_4f_res <- "
school =~ school1 + school2 + school3
self =~ self1 + self2
friends =~ friends1 + friends2
family =~ fam1 + fam2 + fam3
# Fixing the covariance to 1
friends ~~ 1*self
# Equality constraints: Covariances with equal parameter names
friends ~~ a*school
self ~~ a*school
friends ~~ b*family
self ~~ b*family
"
Estimating the alternative 3-factor model:
fit_mod4f_res <- cfa(model_4f_res, std.lv = TRUE, data = ls_clean)
summary(fit_mod4f_res, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 26 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 25
#> Number of equality constraints 2
#> Row rank of the constraints matrix 2
#>
#> Number of observations 255
#>
#> Estimator ML
#> Model Fit Test Statistic 79.522
#> Degrees of freedom 32
#> P-value (Chi-square) 0.000
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 583.039
#> Degrees of freedom 45
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.912
#> Tucker-Lewis Index (TLI) 0.876
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3441.804
#> Loglikelihood unrestricted model (H1) -3402.044
#>
#> Number of free parameters 23
#> Akaike (AIC) 6929.609
#> Bayesian (BIC) 7011.058
#> Sample-size adjusted Bayesian (BIC) 6938.142
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.076
#> 90 Percent Confidence Interval 0.055 0.098
#> P-value RMSEA <= 0.05 0.021
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.064
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> school =~
#> school1 0.577 0.096 6.037 0.000 0.577 0.424
#> school2 0.828 0.097 8.499 0.000 0.828 0.645
#> school3 1.127 0.111 10.109 0.000 1.127 0.847
#> self =~
#> self1 0.686 0.075 9.141 0.000 0.686 0.629
#> self2 0.610 0.060 10.126 0.000 0.610 0.698
#> friends =~
#> friends1 0.509 0.058 8.829 0.000 0.509 0.608
#> friends2 0.344 0.054 6.378 0.000 0.344 0.450
#> family =~
#> fam1 0.787 0.070 11.214 0.000 0.787 0.747
#> fam2 0.824 0.066 12.461 0.000 0.824 0.840
#> fam3 0.469 0.060 7.783 0.000 0.469 0.511
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> self ~~
#> friends 1.000 1.000 1.000
#> school ~~
#> friends (a) 0.261 0.081 3.216 0.001 0.261 0.261
#> self (a) 0.261 0.081 3.216 0.001 0.261 0.261
#> friends ~~
#> family (b) 0.331 0.077 4.304 0.000 0.331 0.331
#> self ~~
#> family (b) 0.331 0.077 4.304 0.000 0.331 0.331
#> school ~~
#> family 0.225 0.077 2.922 0.003 0.225 0.225
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .school1 1.522 0.147 10.379 0.000 1.522 0.821
#> .school2 0.962 0.139 6.926 0.000 0.962 0.584
#> .school3 0.501 0.206 2.429 0.015 0.501 0.283
#> .self1 0.718 0.087 8.236 0.000 0.718 0.604
#> .self2 0.393 0.057 6.907 0.000 0.393 0.513
#> .friends1 0.441 0.051 8.572 0.000 0.441 0.630
#> .friends2 0.466 0.046 10.154 0.000 0.466 0.797
#> .fam1 0.491 0.079 6.189 0.000 0.491 0.443
#> .fam2 0.283 0.077 3.700 0.000 0.283 0.295
#> .fam3 0.621 0.061 10.222 0.000 0.621 0.739
#> school 1.000 1.000 1.000
#> self 1.000 1.000 1.000
#> friends 1.000 1.000 1.000
#> family 1.000 1.000 1.000
Visualizing the alternative 3-factor model with standardized parameter estimates:
semPaths(fit_mod4f_res, "std", "par", weighted = FALSE, nCharNodes = 7,
shapeMan = "rectangle", sizeMan = 8, sizeMan2 = 5)
To obtain exactly the same standardized parameter estimates for all parameters as in the “normally” defined 3-factor model above, the latter must also be estimated with the option std.lv = TRUE
. If not, slight differences in loadings and residual variances will result due to the different scaling methods of the latent variables.
fit_mod3f_alt <- cfa(model_3f, std.lv = TRUE, data = ls_clean)
semPaths(fit_mod3f_alt, "std", "par", weighted = FALSE, nCharNodes = 7,
shapeMan = "rectangle", sizeMan = 8, sizeMan2 = 5)
Model comparison of the 3-factor model and the alternative 3-factor model
A model comparison should now show that the 3-factor model and the restricted 4-factor model do have the same model fit, i.e. are identical:
anova(fit_mod3f, fit_mod4f_res)
#> Warning in lavTestLRT(object = new("lavaan", version = "0.6.4", call =
#> lavaan::lavaan(model = model_3f, : lavaan WARNING: some models have the
#> same degrees of freedom
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_mod3f 32 6929.6 7011.1 79.522
#> fit_mod4f_res 32 6929.6 7011.1 79.522 2.2919e-10 0
Exactly! (The very small number at Chisq diff
is caused by minimal numerical inaccuracies in the ML estimation.)
Model comparison of the 3-factor model and the 4-factor model
Furthermore, we want to test the 3-factor model (it doesn’t matter which “version” we take, i.e. fit_mod3f
or fit_mod4f_res
) against the original 4-factor model.
This test examines whether the null hypothesis that the 3-factor model does not fit worse than the 4-factor model has to be rejected.
anova(fit_mod3f, fit_mod4f)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_mod4f 29 6907.5 6999.6 51.433
#> fit_mod3f 32 6929.6 7011.1 79.522 28.089 3 3.479e-06 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
The comparison is significant. The 3-factor model therefore fits the data significantly worse than the 4-factor model.
For the AIC, a value of 6907.52 was obtained for the 4-factor model and a value of 6929.609 for the 3-factor model. Thus, the 4-factor model should be preferred (smaller AIC).
A similar picture emerges for the BIC: BIC = 6999.593 for the 4-factor model and BIC = 7011.058 for the 3-factor model. Thus, even according to the more parsimonious BIC (favors models with fewer parameters as compared to the AIC), the 4-factor model should be selected.
10.1.6 Model with a second order factor
As we can see, the factors in the 4-factor model are all positively correlated and these correlations are also significant with one exception \((r_{SchoolSelf}=0.18, \; p = 0.052)\). This and the fact that life satisfaction in psychological research is conceptualized not only domain-specifically, but also (and even predominantly) globally, suggests that a 2nd order factor life satisfaction might exist. In other words: general life satisfaction factor might explain the inter-correlations among the domain-specific (first order) life satisfaction factors.
In CFA we can model such a second order factor. Another factor seems to make the model more complicated at first, but this can be misleading: In fact, in a model with one second order factor, there are two parameters less to be estimated than in a model with only four first order factors: Instead of six covariances among the factors, now four loadings (or three loadings and one second order factor variance) have to be estimated.
Model definition
model_4f_2order <- "
school =~ school1 + school2 + school3
self =~ self1 + self2
friends =~ friends1 + friends2
family =~ fam1 + fam2 + fam3
# Second order factor life_satisfaction
life_satisfaction =~ school + self + friends + family
"
Model estimation
fit_mod4f_2order <- cfa(model_4f_2order, ls_clean)
summary(fit_mod4f_2order, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 67 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 24
#>
#> Number of observations 255
#>
#> Estimator ML
#> Model Fit Test Statistic 53.372
#> Degrees of freedom 31
#> P-value (Chi-square) 0.008
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 583.039
#> Degrees of freedom 45
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.958
#> Tucker-Lewis Index (TLI) 0.940
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3428.730
#> Loglikelihood unrestricted model (H1) -3402.044
#>
#> Number of free parameters 24
#> Akaike (AIC) 6905.459
#> Bayesian (BIC) 6990.450
#> Sample-size adjusted Bayesian (BIC) 6914.364
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.053
#> 90 Percent Confidence Interval 0.027 0.077
#> P-value RMSEA <= 0.05 0.387
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.060
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv
#> school =~
#> school1 1.000 0.555
#> school2 1.439 0.261 5.508 0.000 0.799
#> school3 2.118 0.449 4.713 0.000 1.175
#> self =~
#> self1 1.000 0.736
#> self2 0.924 0.153 6.040 0.000 0.680
#> friends =~
#> friends1 1.000 0.662
#> friends2 0.612 0.117 5.229 0.000 0.405
#> family =~
#> fam1 1.000 0.780
#> fam2 1.068 0.131 8.136 0.000 0.833
#> fam3 0.595 0.084 7.106 0.000 0.465
#> life_satisfaction =~
#> school 1.000 0.322
#> self 2.720 0.985 2.763 0.006 0.661
#> friends 3.397 1.250 2.717 0.007 0.917
#> family 1.686 0.661 2.550 0.011 0.386
#> Std.all
#>
#> 0.407
#> 0.622
#> 0.883
#>
#> 0.675
#> 0.777
#>
#> 0.792
#> 0.530
#>
#> 0.741
#> 0.849
#> 0.507
#>
#> 0.322
#> 0.661
#> 0.917
#> 0.386
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .school1 1.547 0.148 10.481 0.000 1.547 0.834
#> .school2 1.011 0.139 7.278 0.000 1.011 0.613
#> .school3 0.390 0.231 1.689 0.091 0.390 0.220
#> .self1 0.647 0.100 6.442 0.000 0.647 0.544
#> .self2 0.303 0.075 4.020 0.000 0.303 0.396
#> .friends1 0.261 0.080 3.277 0.001 0.261 0.373
#> .friends2 0.420 0.047 8.958 0.000 0.420 0.719
#> .fam1 0.501 0.079 6.317 0.000 0.501 0.452
#> .fam2 0.268 0.078 3.429 0.001 0.268 0.279
#> .fam3 0.625 0.061 10.256 0.000 0.625 0.743
#> .school 0.276 0.095 2.915 0.004 0.896 0.896
#> .self 0.305 0.091 3.369 0.001 0.563 0.563
#> .friends 0.070 0.106 0.661 0.509 0.159 0.159
#> .family 0.518 0.097 5.360 0.000 0.851 0.851
#> life_satisfctn 0.032 0.021 1.536 0.125 1.000 1.000
Visualizing the model
With standardized parameter estimates:
semPaths(fit_mod4f_2order, "std", weighted = FALSE, nCharNodes = 7,
shapeMan = "rectangle", sizeMan = 8, sizeMan2 = 5)
The parameter estimates show that the strongest standardized loading of the domain-specific (first order) factors is that of the friends factor, while the lowest is that of the school factor. Overall, the pattern of loadings is quite heterogeneous.
Model fit and model comparisons
CFI = 0.958 and NNFI/TLI = 0.94 are very similar to the 4-factor model. The RMSEA = 0.053 is slightly lower than with the 4-factor model and not significantly higher than 0.05 (90 %-CI [0.027; 0.077]).
Now we compare all three models (in ascending order with regard to the number of estimated parameters: 3-factor model, 4-factor model with second-order factor, 4-factor model) using sequential likelihood-ratio tests. The prerequisite for the validity of these tests is the nesting of restricted models (with fewer parameters) in models with fewer restrictions (with more parameters). For the 3-factor and the 4-factor models we have demonstrated the nesting above. But also the 4-factor model with a second-order factor is nested in the 4-factor model (because actually all models that have the same four first order factors are nested in this model since it is a saturated model at the level of latent variables).
anova(fit_mod3f, fit_mod4f_2order, fit_mod4f)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_mod4f 29 6907.5 6999.6 51.433
#> fit_mod4f_2order 31 6905.5 6990.4 53.372 1.9395 2 0.3792
#> fit_mod3f 32 6929.6 7011.1 79.522 26.1494 1 3.16e-07 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
The model comparison shows that the 4-factor model with a second-order factor does not fit the data significantly worse than the less parsimonious 4-factor model (\(\Delta\chi^2=\) 1.9395, \(p =\) 0.3792). The second test, on the other hand, shows a significant model comparison of the 3-factor model with the 4-factor model with a second-order factor (\(\Delta\chi^2=\) 26.1494, \(p =\) 0).
The best of these three models is therefore the 4-factor model with a second order factor. This also has the lowest information criteria of all models (AIC = 6905.5, BIC = 6990.4).
10.2 Structural Equation Modelling (SEM)
10.2.1 Introduction
SEM represent a combination of CFA and regression models and allows to model complex regression structures (path models) at the level of latent variables. Indirect effects (mediation models) can also be estimated. The estimation theory does not differ from that of CFA.
As an example we will study the effects of emotional support by parents and friends as experienced by adolescents on their life satisfaction. The two self-efficacy domains “academic self-efficacy” and “social self-efficacy” will serve as mediators for these effects. Both direct and indirect effects will be investigated.
Theoretical basis and hypotheses: Both parental support and support from friends have a positive effect on life satisfaction. In addition, it is known from self-efficacy research that experienced support has a positive effect on the experience of self-efficacy, and that this in turn is related to life satisfaction. An important question, however, concerns the differential effects resulting resulting when these constructs with their respective domains are considered simultaneously.
The assumed effects can be summarized in the following structural model:
For the postulated structural model (relations between the latent variables) we need a measurement model (relations between the latent variables and the manifest variables, i.e. the factor structure). With a large number of measured variables the measurement model is often based “packages” of individual items rather than on the individual items themselves. Here we choose the “item-to-construct balance approach” to packaging (Little et al., 2002), in which individual items representing a certain construct are combined in such a way that the “packed” manifest variables load as homogeneously as possible on the respective latent factor. It is generally recommended to use three to four parcels per latent variable.
The following parcels were built:
Emotional support from parents (6 items): 3 parcels of 2 items (sup_parents_p1, sup_parents_p2, sup_parents_p3)
Emotional support from friends (6 items): 3 parcels of 2 items (sup_friends_p1, sup_friends_p2, sup_friends_p3)
Academic self-efficacy (20 items): 2 parcels of 7 items & 1 parcel of 6 items (se_acad_p1, se_acad_p2, se_acad_p3)
Social self-efficacy (16 items): 2 parcels of 5 items & 1 parcel of 6 items (se_social_p1, se_social_p2, se_social_p3)
Life satisfaction (11 items): 2 parcels of 4 items & 1 parcel of 3 items (ls_p1, ls_p2, ls_p3)
The SEM analysis is carried out in three steps:
We start with the measurement model. The measurement model is a multi-construct CFA with intercorrelations of all latent variables.
Then we consider the entire structural equation model (measurement and structural model combined).
In the last step we will show how to explicitly define indirect and total effects within the SEM.
10.2.2 Importing the data
data_sem <- read_csv("data/sem_data.csv") %>%
mutate(region = as.factor(region),
sex = as.factor(sex))
#> Parsed with column specification:
#> cols(
#> ID = col_double(),
#> region = col_character(),
#> sex = col_character(),
#> age = col_double(),
#> se_acad_p1 = col_double(),
#> se_acad_p2 = col_double(),
#> se_acad_p3 = col_double(),
#> se_social_p1 = col_double(),
#> se_social_p2 = col_double(),
#> se_social_p3 = col_double(),
#> sup_friends_p1 = col_double(),
#> sup_friends_p2 = col_double(),
#> sup_friends_p3 = col_double(),
#> sup_parents_p1 = col_double(),
#> sup_parents_p2 = col_double(),
#> sup_parents_p3 = col_double(),
#> ls_p1 = col_double(),
#> ls_p2 = col_double(),
#> ls_p3 = col_double()
#> )
As above with the CFA, we remove all persons with observations outside +/- 3 SD of the mean on one or more variables:
keep <- function(x) {
(x >= mean(x, na.rm = TRUE) - 3 * sd(x, na.rm = TRUE)) &
(x <= mean(x, na.rm = TRUE) + 3 * sd(x, na.rm = TRUE))
}
data_clean <- data_sem %>%
filter(
keep(se_acad_p1) &
keep(se_acad_p2) &
keep(se_acad_p3) &
keep(se_social_p1) &
keep(se_social_p2) &
keep(se_social_p3) &
keep(sup_parents_p1) &
keep(sup_parents_p2) &
keep(sup_parents_p3) &
keep(sup_friends_p1) &
keep(sup_friends_p2) &
keep(sup_friends_p3) &
keep(ls_p1) &
keep(ls_p2) &
keep(ls_p3))
data_clean
#> # A tibble: 255 x 19
#> ID region sex age se_acad_p1 se_acad_p2 se_acad_p3 se_social_p1
#> <dbl> <fct> <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 west fema… 13 4.86 5.57 4.5 5.8
#> 2 2 west male 14 4.57 4.29 4.67 5
#> 3 10 west fema… 14 4.14 6.14 5.33 5.2
#> 4 11 west fema… 14 5 5.43 4.83 6.4
#> 5 12 west fema… 14 5.17 5.6 4.8 5.25
#> 6 14 west male 14 4.86 4.86 4.17 5.2
#> # … with 249 more rows, and 11 more variables: se_social_p2 <dbl>,
#> # se_social_p3 <dbl>, sup_friends_p1 <dbl>, sup_friends_p2 <dbl>,
#> # sup_friends_p3 <dbl>, sup_parents_p1 <dbl>, sup_parents_p2 <dbl>,
#> # sup_parents_p3 <dbl>, ls_p1 <dbl>, ls_p2 <dbl>, ls_p3 <dbl>
10.2.3 Measurement model
In the measurement model, the relationships between the latent variables (factors) and the manifest variables are defined. We are already familiar with the lavaan
model definition from the CFA example above.
Error variances of the observed variables and variances of the exogenous latent variables do not have to be explicitly specified.
Operator for the measuring model:
=~
(“is measured by…”)
model_measurement <- "
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
"
Model estimation
The function sem()
is applied to the model model_measurement
specified above, the results are stored in an object (here with the name fit_measurement
). We could also use cfa()
here. The two functions differ only slightly in their default settings and are both equally suitable for estimating measurement models.
fit_measurement <- sem(model_measurement, data = data_clean)
summary(fit_measurement, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 49 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 40
#>
#> Number of observations 255
#>
#> Estimator ML
#> Model Fit Test Statistic 212.282
#> Degrees of freedom 80
#> P-value (Chi-square) 0.000
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 2238.104
#> Degrees of freedom 105
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.938
#> Tucker-Lewis Index (TLI) 0.919
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3510.025
#> Loglikelihood unrestricted model (H1) -3403.884
#>
#> Number of free parameters 40
#> Akaike (AIC) 7100.051
#> Bayesian (BIC) 7241.701
#> Sample-size adjusted Bayesian (BIC) 7114.892
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.081
#> 90 Percent Confidence Interval 0.067 0.094
#> P-value RMSEA <= 0.05 0.000
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.062
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sup_parents_p1 1.000 0.767 0.834
#> sup_parents_p2 1.127 0.070 16.029 0.000 0.865 0.898
#> sup_parents_p3 1.029 0.072 14.254 0.000 0.789 0.792
#> SUP_Friends =~
#> sup_friends_p1 1.000 0.816 0.867
#> sup_friends_p2 0.836 0.053 15.777 0.000 0.682 0.846
#> sup_friends_p3 0.924 0.059 15.584 0.000 0.753 0.835
#> SE_Academic =~
#> se_acad_p1 1.000 0.651 0.856
#> se_acad_p2 0.844 0.055 15.323 0.000 0.550 0.837
#> se_acad_p3 1.000 0.066 15.063 0.000 0.651 0.824
#> SE_Social =~
#> se_social_p1 1.000 0.558 0.816
#> se_social_p2 0.976 0.065 15.072 0.000 0.544 0.879
#> se_social_p3 0.968 0.078 12.398 0.000 0.540 0.732
#> LS =~
#> ls_p1 1.000 0.527 0.639
#> ls_p2 0.877 0.097 9.031 0.000 0.462 0.772
#> ls_p3 0.907 0.117 7.775 0.000 0.478 0.609
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents ~~
#> SUP_Friends 0.104 0.045 2.322 0.020 0.167 0.167
#> SE_Academic 0.199 0.039 5.090 0.000 0.397 0.397
#> SE_Social 0.191 0.035 5.503 0.000 0.446 0.446
#> LS 0.248 0.041 6.014 0.000 0.613 0.613
#> SUP_Friends ~~
#> SE_Academic 0.078 0.038 2.044 0.041 0.147 0.147
#> SE_Social 0.159 0.035 4.542 0.000 0.350 0.350
#> LS 0.148 0.037 4.021 0.000 0.345 0.345
#> SE_Academic ~~
#> SE_Social 0.226 0.032 7.013 0.000 0.621 0.621
#> LS 0.165 0.032 5.158 0.000 0.480 0.480
#> SE_Social ~~
#> LS 0.215 0.033 6.546 0.000 0.731 0.731
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.258 0.033 7.799 0.000 0.258 0.305
#> .sup_parents_p2 0.180 0.034 5.342 0.000 0.180 0.194
#> .sup_parents_p3 0.369 0.042 8.826 0.000 0.369 0.372
#> .sup_friends_p1 0.219 0.033 6.577 0.000 0.219 0.248
#> .sup_friends_p2 0.185 0.025 7.380 0.000 0.185 0.285
#> .sup_friends_p3 0.246 0.032 7.724 0.000 0.246 0.303
#> .se_acad_p1 0.155 0.022 7.005 0.000 0.155 0.268
#> .se_acad_p2 0.129 0.017 7.607 0.000 0.129 0.299
#> .se_acad_p3 0.200 0.025 7.983 0.000 0.200 0.321
#> .se_social_p1 0.156 0.019 8.098 0.000 0.156 0.334
#> .se_social_p2 0.087 0.014 6.037 0.000 0.087 0.227
#> .se_social_p3 0.253 0.027 9.529 0.000 0.253 0.465
#> .ls_p1 0.402 0.043 9.358 0.000 0.402 0.592
#> .ls_p2 0.145 0.021 6.991 0.000 0.145 0.404
#> .ls_p3 0.387 0.040 9.651 0.000 0.387 0.629
#> SUP_Parents 0.588 0.075 7.811 0.000 1.000 1.000
#> SUP_Friends 0.665 0.081 8.258 0.000 1.000 1.000
#> SE_Academic 0.424 0.052 8.096 0.000 1.000 1.000
#> SE_Social 0.311 0.041 7.539 0.000 1.000 1.000
#> LS 0.278 0.054 5.124 0.000 1.000 1.000
Path diagram
cols <- wes_palette(name = "Moonrise2", n = 4, type = "discrete")
colorlist <- list(man = cols[2], lat = cols[3])
semPaths(fit_measurement, what = "col", whatLabels = "std", style = "mx",
color = colorlist, rotation =1 , layout = "spring", nCharNodes = 7,
shapeMan = "rectangle", sizeMan = 8, sizeMan2 = 5)
As can be seen from the output and the path diagram the standardized loadings are all relatively high and also homogeneous. The factor correlations of this multi-construct measurement model are between \(r = 0.147\) (SUP_Friends
\(\leftrightarrow\) SE_Academic
) and \(r = 0.731\) (SE_Social
\(\leftrightarrow\) LS
).
Global model fit is not really good (CFI = 0.938, NNFI/TLI = 0.919, RMSEA = 0.081, 90 %-CI: [0.067; 0.094]) but can still be seen as acceptable according to commonly accepted criteria.
In order to determine where problems exist in the model fit, we can first consider the standardized residual variance-covariance matrix:
resid(fit_measurement, type = "standardized")$cov
#> sp_p_1 sp_p_2 sp_p_3 sp_f_1 sp_f_2 sp_f_3 s_cd_1 s_cd_2
#> sup_parents_p1 0.000
#> sup_parents_p2 2.058 0.000
#> sup_parents_p3 -1.325 -0.681 0.000
#> sup_friends_p1 -0.206 -0.825 -3.968 0.000
#> sup_friends_p2 1.598 1.876 -0.832 0.155 0.000
#> sup_friends_p3 1.786 0.669 -0.982 1.531 -1.703 0.000
#> se_acad_p1 0.191 -1.333 1.144 -0.342 0.697 0.926 0.000
#> se_acad_p2 0.663 0.536 1.354 1.240 1.536 1.042 -1.790 0.000
#> se_acad_p3 -0.765 -1.328 0.896 -2.929 -1.029 -1.327 1.150 0.467
#> se_social_p1 0.707 0.492 1.563 -3.450 -1.276 -1.381 3.946 2.006
#> se_social_p2 -0.009 0.130 -0.141 0.476 1.673 1.179 -1.211 -0.998
#> se_social_p3 -1.222 -0.996 -1.217 2.087 0.317 0.267 -0.661 1.423
#> ls_p1 -1.903 -1.605 0.875 -4.028 -1.760 -2.144 -0.497 3.392
#> ls_p2 -1.534 -2.798 -0.873 0.797 4.307 2.353 -3.750 -1.253
#> ls_p3 2.532 3.775 4.927 -1.629 0.172 -0.948 2.607 3.695
#> s_cd_3 s_sc_1 s_sc_2 s_sc_3 ls_p1 ls_p2 ls_p3
#> sup_parents_p1
#> sup_parents_p2
#> sup_parents_p3
#> sup_friends_p1
#> sup_friends_p2
#> sup_friends_p3
#> se_acad_p1
#> se_acad_p2
#> se_acad_p3 0.000
#> se_social_p1 0.754 0.000
#> se_social_p2 -3.101 0.651 0.000
#> se_social_p3 -0.724 -2.033 1.227 0.000
#> ls_p1 1.549 -1.480 -2.091 -0.892 0.000
#> ls_p2 -3.683 1.030 2.698 2.450 2.101 0.000
#> ls_p3 2.661 -1.025 -1.797 -1.568 1.913 -4.710 0.000
This shows that the variance-covariance matrix implied by the model deviates significantly from the empirical variance-covariance matrix at many points in the model. An accumulation of very high standardized residual covariances can be seen e.g. with respect to the ls_p3
parcel.
Modification indices
Another possibility for local fit diagnostics is offered by modification indices. These indicate which additional model parameters would result in a significant fit improvement (in terms of a reduction of \(\chi^2\) by the value of the corresponding MI). We will only display the MI \(\geq 5\), since usually only those are considered substantial.
modindices(fit_measurement, standardized = FALSE, minimum.value = 5)
#> lhs op rhs mi epc
#> 46 SUP_Parents =~ sup_friends_p1 5.806 -0.127
#> 56 SUP_Parents =~ ls_p2 10.805 -0.241
#> 57 SUP_Parents =~ ls_p3 26.005 0.450
#> 60 SUP_Friends =~ sup_parents_p3 7.412 -0.154
#> 63 SUP_Friends =~ se_acad_p3 6.796 -0.115
#> 64 SUP_Friends =~ se_social_p1 9.715 -0.132
#> 67 SUP_Friends =~ ls_p1 11.286 -0.221
#> 68 SUP_Friends =~ ls_p2 15.297 0.197
#> 76 SE_Academic =~ se_social_p1 13.160 0.258
#> 77 SE_Academic =~ se_social_p2 11.197 -0.219
#> 80 SE_Academic =~ ls_p2 21.078 -0.334
#> 81 SE_Academic =~ ls_p3 14.463 0.339
#> 92 SE_Social =~ ls_p2 10.964 0.473
#> 97 LS =~ sup_friends_p1 7.059 -0.233
#> 98 LS =~ sup_friends_p2 5.678 0.182
#> 101 LS =~ se_acad_p2 7.019 0.193
#> 133 sup_parents_p3 ~~ sup_friends_p1 9.759 -0.075
#> 144 sup_parents_p3 ~~ ls_p3 8.031 0.079
#> 150 sup_friends_p1 ~~ se_social_p1 7.693 -0.045
#> 152 sup_friends_p1 ~~ se_social_p3 16.979 0.080
#> 164 sup_friends_p2 ~~ ls_p2 5.829 0.035
#> 177 se_acad_p1 ~~ se_social_p1 12.599 0.048
#> 180 se_acad_p1 ~~ ls_p1 6.038 -0.050
#> 187 se_acad_p2 ~~ ls_p1 7.547 0.049
#> 206 se_social_p3 ~~ ls_p2 5.442 0.036
#> 208 ls_p1 ~~ ls_p2 5.076 0.063
#> 210 ls_p2 ~~ ls_p3 17.111 -0.105
A total of 27 modification indices are displayed. They refer either to possible cross-loadings (e.g. SUP_Parents =~ ls_p3
: MI = 26.005) or to residual covariances between manifest variables (e.g. sup_friends_p1 ~~ se_social_p3
: MI = 16.979). For theoretical reasons the addition of cross-loadings and of residual covariances (especially across different latent variables) is not recommended.
Such model fit problems often arise in self-report studies. Individual differences in scale use (response styles) can play a role: These can lead to generally increased correlations among the variables, which may not be adequately taken into account in a multi-construct measurement model. There are approaches (definition of method and response style factors) to deal with this issue.
Another reason for the model-fit problems in this study could be the general similarity of the constructs investigated with respect to life domains. For example, there are life satisfaction items with respect to friends, but the friends context also plays an important role for the items for social self-efficacy and, of course, for support received from friends.
Since the model fit is still acceptable, we continue to work with this measurement model. In the next step we will model the effects among latent variables in order to test our theoretical assumptions (structural model).
10.2.4 Structural model
Model definition
The structural model represents the relationships/effects among the latent variables. It is added to the measurement model definitions:
model <- "
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + SUP_Friends
SE_Social ~ SUP_Parents + SUP_Friends
LS ~ SE_Academic + SE_Social + SUP_Parents + SUP_Friends
# Residual covariances
SE_Academic ~~ SE_Social
"
Operator for the structural model (regressions of latent variables):
~
(“is predicted by…”)Operator for (residual) variances and covariances:
~~
(for variances, the same variable appears on the left and right; for covariances, different variables). As in the measurement model (CFA), variances and covariances of exogenous latent variables do not have to be specified (are automatically estimated). The residual variances of endogenous latent variables are also estimated automatically.
Therefore we only have to specify one parameter using ~~
: In this model we have two parallel latent mediator variables (SE_Academic
and SE_Social
) which have no effects on each other. However, it can be assumed that these two variables (or rather their residuals) co-vary since a general self-efficacy component is likely (cf. also the correlation of \(r=0.621\) in the measurement model above). Since SE_Academic
and SE_Social
are endogenous latent variables (both are predicted by both SUP_Parents
and SUP_Friends
), a residual covariance \(\psi =\) SE_Academic ~~ SE_Social
must be specified.
Model estimation
fit <- sem(model, data = data_clean)
summary(fit, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 46 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 40
#>
#> Number of observations 255
#>
#> Estimator ML
#> Model Fit Test Statistic 212.282
#> Degrees of freedom 80
#> P-value (Chi-square) 0.000
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 2238.104
#> Degrees of freedom 105
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.938
#> Tucker-Lewis Index (TLI) 0.919
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3510.025
#> Loglikelihood unrestricted model (H1) -3403.884
#>
#> Number of free parameters 40
#> Akaike (AIC) 7100.051
#> Bayesian (BIC) 7241.701
#> Sample-size adjusted Bayesian (BIC) 7114.892
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.081
#> 90 Percent Confidence Interval 0.067 0.094
#> P-value RMSEA <= 0.05 0.000
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.062
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sup_parents_p1 1.000 0.767 0.834
#> sup_parents_p2 1.127 0.070 16.029 0.000 0.865 0.898
#> sup_parents_p3 1.029 0.072 14.254 0.000 0.789 0.792
#> SUP_Friends =~
#> sup_friends_p1 1.000 0.816 0.867
#> sup_friends_p2 0.836 0.053 15.777 0.000 0.682 0.846
#> sup_friends_p3 0.924 0.059 15.584 0.000 0.753 0.835
#> SE_Academic =~
#> se_acad_p1 1.000 0.651 0.856
#> se_acad_p2 0.844 0.055 15.323 0.000 0.550 0.837
#> se_acad_p3 1.000 0.066 15.063 0.000 0.651 0.824
#> SE_Social =~
#> se_social_p1 1.000 0.558 0.816
#> se_social_p2 0.976 0.065 15.072 0.000 0.544 0.879
#> se_social_p3 0.968 0.078 12.398 0.000 0.540 0.732
#> LS =~
#> ls_p1 1.000 0.527 0.639
#> ls_p2 0.877 0.097 9.031 0.000 0.462 0.772
#> ls_p3 0.907 0.117 7.775 0.000 0.478 0.609
#>
#> Regressions:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SE_Academic ~
#> SUP_Parents 0.326 0.060 5.450 0.000 0.384 0.384
#> SUP_Friends 0.066 0.054 1.229 0.219 0.083 0.083
#> SE_Social ~
#> SUP_Parents 0.290 0.050 5.822 0.000 0.399 0.399
#> SUP_Friends 0.194 0.045 4.278 0.000 0.284 0.284
#> LS ~
#> SE_Academic -0.014 0.068 -0.211 0.833 -0.018 -0.018
#> SE_Social 0.519 0.099 5.260 0.000 0.549 0.549
#> SUP_Parents 0.247 0.052 4.772 0.000 0.359 0.359
#> SUP_Friends 0.061 0.042 1.461 0.144 0.095 0.095
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .SE_Academic ~~
#> .SE_Social 0.153 0.025 6.051 0.000 0.542 0.542
#> SUP_Parents ~~
#> SUP_Friends 0.104 0.045 2.322 0.020 0.167 0.167
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.258 0.033 7.799 0.000 0.258 0.305
#> .sup_parents_p2 0.180 0.034 5.342 0.000 0.180 0.194
#> .sup_parents_p3 0.369 0.042 8.826 0.000 0.369 0.372
#> .sup_friends_p1 0.219 0.033 6.577 0.000 0.219 0.248
#> .sup_friends_p2 0.185 0.025 7.380 0.000 0.185 0.285
#> .sup_friends_p3 0.246 0.032 7.724 0.000 0.246 0.303
#> .se_acad_p1 0.155 0.022 7.005 0.000 0.155 0.268
#> .se_acad_p2 0.129 0.017 7.607 0.000 0.129 0.299
#> .se_acad_p3 0.200 0.025 7.983 0.000 0.200 0.321
#> .se_social_p1 0.156 0.019 8.098 0.000 0.156 0.334
#> .se_social_p2 0.087 0.014 6.037 0.000 0.087 0.227
#> .se_social_p3 0.253 0.027 9.529 0.000 0.253 0.465
#> .ls_p1 0.402 0.043 9.358 0.000 0.402 0.592
#> .ls_p2 0.145 0.021 6.991 0.000 0.145 0.404
#> .ls_p3 0.387 0.040 9.651 0.000 0.387 0.629
#> SUP_Parents 0.588 0.075 7.811 0.000 1.000 1.000
#> SUP_Friends 0.665 0.081 8.258 0.000 1.000 1.000
#> .SE_Academic 0.354 0.045 7.849 0.000 0.835 0.835
#> .SE_Social 0.225 0.031 7.165 0.000 0.723 0.723
#> .LS 0.098 0.025 3.923 0.000 0.354 0.354
The model fit is exactly the same! We have already seen above that we have just as many parameters and degrees of freedom in the overall model as in the measurement model.
This means that the structural model is saturated!
In the measurement model we had 15 variance and covariance parameters of the latent variables, so the variance-covariance matrix of the latent variables (with 5 x 6/2 = 15 elements) was complete and unrestricted. We now also have 15 parameters in the structural model. The parameters of the structural model are estimable and we can thus check our postulated effects, but this part of the overall model is just identified (since \(n_{Info} = n_{Par}\) with regard to the latent variables) and thus does not contribute to the model fit of the overall model! In other words: We cannot check whether the structural model fits our data well, only the fit of the measurement model can be tested.
Interpretation of the estimated structural coefficients: Of the 8 postulated structural paths, 5 are significant and go in the expected direction. Not significant are the effects of SUP_Friends
on SE_Academic
(Std.all \(= 0.083,\ p = 0.219\)), from SE_Academic
to LS
(Std.all \(= -0.018,\ p = 0.833\)), and from SUP_Friends
to LS
(Stds.all \(= 0.095,\ p = 0.144\)).
It is particularly striking that the perceived support by the parents has a substantial direct effect on satisfaction, whereas the direct effect of the perceived support by the friends is not significant. It is also interesting that the academic self-efficacy no longer has a significant effect on satisfaction when social self-efficacy is held constant, even though the correlation between the two latent variables SE_Academic
and LS
was substantial in the measurement model (see above \(r = 0.480,\ p < 0.001\)).
Path diagram
Path diagram with non-standardized parameter estimates (layout = 'tree2'
):
semPaths(fit, what = "col", whatLabels = "par", style = "mx", color = colorlist,
rotation = 2, layout = "tree2", mar = c(1, 2, 1, 2), nCharNodes = 7,
shapeMan = "rectangle", sizeMan = 8, sizeMan2 = 5)
Path diagram with non-standardized parameter estimates (layout = 'spring'
):
semPaths(fit, what = "col", whatLabels = "std", style = "mx", color = colorlist,
rotation =1 , layout = "spring", nCharNodes = 7, shapeMan = "rectangle",
sizeMan = 8, sizeMan2 = 5)
Calculation of standardized indirect and total effects
Use the Std.all
estimates!
Specific indirect effects
SUP_Parents
\(\rightarrow\)SE_Academic
\(\rightarrow\)LS
:
\(0.384 \cdot -0.018 = -0.007\)
\(~\)
SUP_Parents
\(\rightarrow\)SE_Social
\(\rightarrow\)LS
:
\(0.399 \cdot 0.549 = 0.219\)
\(~\)
SUP_Friends
\(\rightarrow\)SE_Academic
\(\rightarrow\)LS
:
\(0.083 \cdot -0.018 = -0.001\)
\(~\)
SUP_Friends
\(\rightarrow\)SE_Social
\(\rightarrow\)LS
:
\(0.284 \cdot 0.549 = 0.156\)
\(~\)
Total indirect effects
SUP_Parents
\(\rightarrow\)LS
throughSE_Academic
andSE_Social
:**
\(0.384 \cdot -0.018 + 0.399 \cdot 0.549 = 0.212\)
\(~\)
SUP_Friends
\(\rightarrow\)LS
throughSE_Academic
andSE_Social
:
\(0.083 \cdot -0.018 + 0.284 \cdot 0.549 = 0.154\)
\(~\)
Total effects
SUP_Parents
\(\rightarrow\)LS
:
\(0.384 \cdot -0.018 + 0.399 \cdot 0.549 + 0.359 = 0.571\)
\(~\)
SUP_Friends
\(\rightarrow\)LS
:
\(0.083 \cdot -0.018 + 0.284 \cdot 0.549 + 0.095 = 0.249\)
\(~\)
We can also estimate indirect and total effects in lavaan
and get significance tests for them. This is our last step in the analysis of this SEM.
Significance tests for indirect and total effects
With one or more latent mediator variables present in the structural model the SEM turns into a latent mediation analysis. To estimate indirect and total effects, the parameters of the structural model must first be explicitly named in the model definition (multiplication of predictors with b1, b2, b3, etc.).
Specific and total indirect effects can then be defined as products (or sum of products) of the path parameters (operator:
:=
)Total effects can be defined equally as the sum of indirect and direct effects
When indirect and total effects are defined the model should always be estimated using the se = bootstrap
option. The reason for this is that other than the path coefficients themselves indirect effects (products of path coefficients) are not asymptotically normally distributed and therefore the z- or Wald-approximation should not be used for these defined parameters.
model_mediation <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ b1*SUP_Parents + b3*SUP_Friends
SE_Social ~ b2*SUP_Parents + b4*SUP_Friends
LS ~ b5*SUP_Parents + b6*SUP_Friends + b7*SE_Academic + b8*SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
# Indirect effects
b1b7 := b1*b7
b2b8 := b2*b8
totalind_eltern := b1*b7 + b2*b8
b3b7 := b3*b7
b4b8 := b4*b8
totalind_freunde := b3*b7 + b4*b8
# Total effects
total_eltern := b1*b7 + b2*b8 + b5
total_freunde := b3*b7 + b4*b8 + b6
'
fit_mediation <- sem(model_mediation, data = data_clean, se = "bootstrap")
summary(fit_mediation, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 46 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 40
#>
#> Number of observations 255
#>
#> Estimator ML
#> Model Fit Test Statistic 212.282
#> Degrees of freedom 80
#> P-value (Chi-square) 0.000
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 2238.104
#> Degrees of freedom 105
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.938
#> Tucker-Lewis Index (TLI) 0.919
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3510.025
#> Loglikelihood unrestricted model (H1) -3403.884
#>
#> Number of free parameters 40
#> Akaike (AIC) 7100.051
#> Bayesian (BIC) 7241.701
#> Sample-size adjusted Bayesian (BIC) 7114.892
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.081
#> 90 Percent Confidence Interval 0.067 0.094
#> P-value RMSEA <= 0.05 0.000
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.062
#>
#> Parameter Estimates:
#>
#> Standard Errors Bootstrap
#> Number of requested bootstrap draws 1000
#> Number of successful bootstrap draws 1000
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sup_parents_p1 1.000 0.767 0.834
#> sup_parents_p2 1.127 0.075 15.098 0.000 0.865 0.898
#> sup_parents_p3 1.029 0.094 10.983 0.000 0.789 0.792
#> SUP_Friends =~
#> sup_friends_p1 1.000 0.816 0.867
#> sup_friends_p2 0.836 0.052 16.209 0.000 0.682 0.846
#> sup_friends_p3 0.924 0.058 15.948 0.000 0.753 0.835
#> SE_Academic =~
#> se_acad_p1 1.000 0.651 0.856
#> se_acad_p2 0.844 0.053 15.886 0.000 0.550 0.837
#> se_acad_p3 1.000 0.065 15.375 0.000 0.651 0.824
#> SE_Social =~
#> se_social_p1 1.000 0.558 0.816
#> se_social_p2 0.976 0.076 12.927 0.000 0.544 0.879
#> se_social_p3 0.968 0.080 12.047 0.000 0.540 0.732
#> LS =~
#> ls_p1 1.000 0.527 0.639
#> ls_p2 0.877 0.151 5.795 0.000 0.462 0.772
#> ls_p3 0.907 0.148 6.123 0.000 0.478 0.609
#>
#> Regressions:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SE_Academic ~
#> SUP_Prnts (b1) 0.326 0.070 4.639 0.000 0.384 0.384
#> SUP_Frnds (b3) 0.066 0.057 1.163 0.245 0.083 0.083
#> SE_Social ~
#> SUP_Prnts (b2) 0.290 0.058 5.018 0.000 0.399 0.399
#> SUP_Frnds (b4) 0.194 0.043 4.537 0.000 0.284 0.284
#> LS ~
#> SUP_Prnts (b5) 0.247 0.065 3.791 0.000 0.359 0.359
#> SUP_Frnds (b6) 0.061 0.043 1.444 0.149 0.095 0.095
#> SE_Acadmc (b7) -0.014 0.106 -0.135 0.893 -0.018 -0.018
#> SE_Social (b8) 0.519 0.131 3.971 0.000 0.549 0.549
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .SE_Academic ~~
#> .SE_Social 0.153 0.026 5.866 0.000 0.542 0.542
#> SUP_Parents ~~
#> SUP_Friends 0.104 0.043 2.402 0.016 0.167 0.167
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.258 0.036 7.171 0.000 0.258 0.305
#> .sup_parents_p2 0.180 0.040 4.517 0.000 0.180 0.194
#> .sup_parents_p3 0.369 0.058 6.362 0.000 0.369 0.372
#> .sup_friends_p1 0.219 0.051 4.298 0.000 0.219 0.248
#> .sup_friends_p2 0.185 0.028 6.518 0.000 0.185 0.285
#> .sup_friends_p3 0.246 0.049 5.039 0.000 0.246 0.303
#> .se_acad_p1 0.155 0.031 4.949 0.000 0.155 0.268
#> .se_acad_p2 0.129 0.021 6.171 0.000 0.129 0.299
#> .se_acad_p3 0.200 0.032 6.206 0.000 0.200 0.321
#> .se_social_p1 0.156 0.025 6.220 0.000 0.156 0.334
#> .se_social_p2 0.087 0.016 5.365 0.000 0.087 0.227
#> .se_social_p3 0.253 0.026 9.682 0.000 0.253 0.465
#> .ls_p1 0.402 0.050 8.000 0.000 0.402 0.592
#> .ls_p2 0.145 0.037 3.958 0.000 0.145 0.404
#> .ls_p3 0.387 0.061 6.336 0.000 0.387 0.629
#> SUP_Parents 0.588 0.087 6.722 0.000 1.000 1.000
#> SUP_Friends 0.665 0.080 8.332 0.000 1.000 1.000
#> .SE_Academic 0.354 0.040 8.838 0.000 0.835 0.835
#> .SE_Social 0.225 0.032 7.094 0.000 0.723 0.723
#> .LS 0.098 0.029 3.387 0.001 0.354 0.354
#>
#> Defined Parameters:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> b1b7 -0.005 0.036 -0.128 0.898 -0.007 -0.007
#> b2b8 0.150 0.048 3.119 0.002 0.219 0.219
#> totalind_eltrn 0.146 0.039 3.744 0.000 0.212 0.212
#> b3b7 -0.001 0.009 -0.104 0.917 -0.001 -0.001
#> b4b8 0.101 0.033 3.095 0.002 0.156 0.156
#> totalind_frend 0.100 0.029 3.380 0.001 0.154 0.154
#> total_eltern 0.392 0.080 4.932 0.000 0.571 0.571
#> total_freunde 0.161 0.048 3.380 0.001 0.249 0.249
Note: Now the standard errors of all parameters were bootstrap-estimated. Therefore, all p-values have changed slightly.
10.2.5 Summary
Acceptable model fit of the measurement model
Structural model saturated, model fit not verifiable
- Support by parents most important for the life satisfaction of young people
- Total effect more than twice as large compared to support from friends
- Direct effect strongest, but also substantial indirect effect via social self-efficacy
Support from friends with only an indirect effect on life satisfaction through social self-efficacy
Social self-efficacy strongest predictor of life satisfaction
Academic self-efficacy irrelevant for life satisfaction when controlling for social self-efficacy
\(~\)
Summary of the effects in the structural model:
10.3 CFA and SEM with multiple groups
10.3.1 Measurement invariance analysis across multiple groups
Configural invariance
In a first step, the model is estimated with separate parameters for the two regional groups (“west”" and “east”), i.e. with twice as many model parameters. The overall model fit thus informs about a cross-group invariance with respect to the configural structure (e.g. a factor model with a certain number of factors and certain loadings etc.).
fit_configural <- sem(model_measurement, data = data_clean, group = "region")
summary(fit_configural, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 67 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 110
#>
#> Number of observations per group
#> west 119
#> east 136
#>
#> Estimator ML
#> Model Fit Test Statistic 328.060
#> Degrees of freedom 160
#> P-value (Chi-square) 0.000
#>
#> Chi-square for each group:
#>
#> west 155.493
#> east 172.567
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 2346.528
#> Degrees of freedom 210
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.921
#> Tucker-Lewis Index (TLI) 0.897
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3443.538
#> Loglikelihood unrestricted model (H1) -3279.508
#>
#> Number of free parameters 110
#> Akaike (AIC) 7107.077
#> Bayesian (BIC) 7496.616
#> Sample-size adjusted Bayesian (BIC) 7147.889
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.091
#> 90 Percent Confidence Interval 0.077 0.105
#> P-value RMSEA <= 0.05 0.000
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.070
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#>
#> Group 1 [west]:
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sup_parents_p1 1.000 0.800 0.852
#> sup_parents_p2 1.188 0.098 12.179 0.000 0.950 0.937
#> sup_parents_p3 0.994 0.102 9.760 0.000 0.795 0.761
#> SUP_Friends =~
#> sup_friends_p1 1.000 0.854 0.851
#> sup_friends_p2 0.835 0.083 10.030 0.000 0.713 0.814
#> sup_friends_p3 0.987 0.094 10.530 0.000 0.843 0.862
#> SE_Academic =~
#> se_acad_p1 1.000 0.610 0.869
#> se_acad_p2 0.856 0.079 10.808 0.000 0.522 0.832
#> se_acad_p3 1.020 0.093 10.938 0.000 0.622 0.840
#> SE_Social =~
#> se_social_p1 1.000 0.533 0.819
#> se_social_p2 0.985 0.105 9.363 0.000 0.525 0.829
#> se_social_p3 0.967 0.117 8.240 0.000 0.515 0.732
#> LS =~
#> ls_p1 1.000 0.431 0.556
#> ls_p2 1.008 0.198 5.077 0.000 0.435 0.763
#> ls_p3 1.057 0.228 4.646 0.000 0.456 0.613
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents ~~
#> SUP_Friends 0.123 0.071 1.729 0.084 0.180 0.180
#> SE_Academic 0.190 0.054 3.486 0.000 0.390 0.390
#> SE_Social 0.160 0.049 3.280 0.001 0.374 0.374
#> LS 0.195 0.053 3.651 0.000 0.566 0.566
#> SUP_Friends ~~
#> SE_Academic 0.079 0.055 1.443 0.149 0.152 0.152
#> SE_Social 0.136 0.051 2.666 0.008 0.300 0.300
#> LS 0.115 0.048 2.414 0.016 0.313 0.313
#> SE_Academic ~~
#> SE_Social 0.215 0.043 5.009 0.000 0.663 0.663
#> LS 0.110 0.036 3.018 0.003 0.418 0.418
#> SE_Social ~~
#> LS 0.149 0.039 3.835 0.000 0.650 0.650
#>
#> Intercepts:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 6.130 0.086 71.283 0.000 6.130 6.535
#> .sup_parents_p2 5.992 0.093 64.422 0.000 5.992 5.906
#> .sup_parents_p3 5.748 0.096 60.005 0.000 5.748 5.501
#> .sup_friends_p1 5.887 0.092 64.022 0.000 5.887 5.869
#> .sup_friends_p2 6.050 0.080 75.395 0.000 6.050 6.911
#> .sup_friends_p3 6.059 0.090 67.650 0.000 6.059 6.201
#> .se_acad_p1 5.022 0.064 78.053 0.000 5.022 7.155
#> .se_acad_p2 5.159 0.058 89.621 0.000 5.159 8.216
#> .se_acad_p3 4.922 0.068 72.499 0.000 4.922 6.646
#> .se_social_p1 5.306 0.060 88.965 0.000 5.306 8.155
#> .se_social_p2 5.436 0.058 93.646 0.000 5.436 8.585
#> .se_social_p3 5.367 0.065 83.203 0.000 5.367 7.627
#> .ls_p1 5.314 0.071 74.718 0.000 5.314 6.849
#> .ls_p2 5.847 0.052 111.929 0.000 5.847 10.261
#> .ls_p3 5.124 0.068 75.135 0.000 5.124 6.888
#> SUP_Parents 0.000 0.000 0.000
#> SUP_Friends 0.000 0.000 0.000
#> SE_Academic 0.000 0.000 0.000
#> SE_Social 0.000 0.000 0.000
#> LS 0.000 0.000 0.000
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.241 0.046 5.187 0.000 0.241 0.273
#> .sup_parents_p2 0.126 0.050 2.505 0.012 0.126 0.123
#> .sup_parents_p3 0.460 0.070 6.614 0.000 0.460 0.421
#> .sup_friends_p1 0.277 0.059 4.733 0.000 0.277 0.275
#> .sup_friends_p2 0.258 0.047 5.544 0.000 0.258 0.337
#> .sup_friends_p3 0.245 0.055 4.450 0.000 0.245 0.256
#> .se_acad_p1 0.121 0.026 4.668 0.000 0.121 0.245
#> .se_acad_p2 0.121 0.022 5.495 0.000 0.121 0.308
#> .se_acad_p3 0.162 0.030 5.336 0.000 0.162 0.294
#> .se_social_p1 0.139 0.027 5.140 0.000 0.139 0.329
#> .se_social_p2 0.126 0.025 4.949 0.000 0.126 0.313
#> .se_social_p3 0.230 0.037 6.292 0.000 0.230 0.464
#> .ls_p1 0.416 0.062 6.675 0.000 0.416 0.691
#> .ls_p2 0.136 0.031 4.373 0.000 0.136 0.418
#> .ls_p3 0.346 0.055 6.296 0.000 0.346 0.624
#> SUP_Parents 0.639 0.115 5.560 0.000 1.000 1.000
#> SUP_Friends 0.729 0.134 5.456 0.000 1.000 1.000
#> SE_Academic 0.372 0.065 5.700 0.000 1.000 1.000
#> SE_Social 0.284 0.056 5.105 0.000 1.000 1.000
#> LS 0.186 0.064 2.885 0.004 1.000 1.000
#>
#>
#> Group 2 [east]:
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sup_parents_p1 1.000 0.756 0.837
#> sup_parents_p2 1.030 0.093 11.092 0.000 0.779 0.854
#> sup_parents_p3 1.022 0.096 10.671 0.000 0.773 0.820
#> SUP_Friends =~
#> sup_friends_p1 1.000 0.781 0.887
#> sup_friends_p2 0.837 0.065 12.861 0.000 0.654 0.885
#> sup_friends_p3 0.851 0.074 11.430 0.000 0.665 0.802
#> SE_Academic =~
#> se_acad_p1 1.000 0.664 0.855
#> se_acad_p2 0.749 0.077 9.756 0.000 0.497 0.795
#> se_acad_p3 0.831 0.087 9.510 0.000 0.552 0.774
#> SE_Social =~
#> se_social_p1 1.000 0.581 0.822
#> se_social_p2 0.920 0.077 11.908 0.000 0.535 0.912
#> se_social_p3 0.907 0.100 9.033 0.000 0.527 0.714
#> LS =~
#> ls_p1 1.000 0.621 0.718
#> ls_p2 0.799 0.100 7.967 0.000 0.497 0.800
#> ls_p3 0.735 0.119 6.179 0.000 0.457 0.591
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents ~~
#> SUP_Friends 0.069 0.058 1.194 0.232 0.116 0.116
#> SE_Academic 0.213 0.055 3.868 0.000 0.425 0.425
#> SE_Social 0.215 0.050 4.344 0.000 0.490 0.490
#> LS 0.294 0.062 4.737 0.000 0.625 0.625
#> SUP_Friends ~~
#> SE_Academic 0.061 0.051 1.201 0.230 0.118 0.118
#> SE_Social 0.176 0.048 3.688 0.000 0.388 0.388
#> LS 0.184 0.055 3.345 0.001 0.379 0.379
#> SE_Academic ~~
#> SE_Social 0.216 0.045 4.768 0.000 0.560 0.560
#> LS 0.205 0.051 4.046 0.000 0.498 0.498
#> SE_Social ~~
#> LS 0.277 0.052 5.299 0.000 0.768 0.768
#>
#> Intercepts:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 6.077 0.077 78.469 0.000 6.077 6.729
#> .sup_parents_p2 6.107 0.078 78.057 0.000 6.107 6.693
#> .sup_parents_p3 5.926 0.081 73.344 0.000 5.926 6.289
#> .sup_friends_p1 5.941 0.076 78.655 0.000 5.941 6.745
#> .sup_friends_p2 6.125 0.063 96.590 0.000 6.125 8.283
#> .sup_friends_p3 6.143 0.071 86.427 0.000 6.143 7.411
#> .se_acad_p1 5.355 0.067 80.372 0.000 5.355 6.892
#> .se_acad_p2 5.553 0.054 103.479 0.000 5.553 8.873
#> .se_acad_p3 5.547 0.061 90.668 0.000 5.547 7.775
#> .se_social_p1 5.418 0.061 89.381 0.000 5.418 7.664
#> .se_social_p2 5.667 0.050 112.734 0.000 5.667 9.667
#> .se_social_p3 5.662 0.063 89.378 0.000 5.662 7.664
#> .ls_p1 5.289 0.074 71.317 0.000 5.289 6.115
#> .ls_p2 5.898 0.053 110.743 0.000 5.898 9.496
#> .ls_p3 5.520 0.066 83.384 0.000 5.520 7.150
#> SUP_Parents 0.000 0.000 0.000
#> SUP_Friends 0.000 0.000 0.000
#> SE_Academic 0.000 0.000 0.000
#> SE_Social 0.000 0.000 0.000
#> LS 0.000 0.000 0.000
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.244 0.044 5.502 0.000 0.244 0.299
#> .sup_parents_p2 0.226 0.044 5.110 0.000 0.226 0.271
#> .sup_parents_p3 0.290 0.050 5.855 0.000 0.290 0.327
#> .sup_friends_p1 0.165 0.037 4.491 0.000 0.165 0.213
#> .sup_friends_p2 0.119 0.026 4.574 0.000 0.119 0.217
#> .sup_friends_p3 0.245 0.038 6.536 0.000 0.245 0.357
#> .se_acad_p1 0.163 0.036 4.480 0.000 0.163 0.270
#> .se_acad_p2 0.144 0.025 5.802 0.000 0.144 0.368
#> .se_acad_p3 0.204 0.033 6.155 0.000 0.204 0.401
#> .se_social_p1 0.162 0.027 6.067 0.000 0.162 0.324
#> .se_social_p2 0.058 0.016 3.588 0.000 0.058 0.168
#> .se_social_p3 0.268 0.037 7.263 0.000 0.268 0.491
#> .ls_p1 0.362 0.056 6.438 0.000 0.362 0.484
#> .ls_p2 0.139 0.027 5.159 0.000 0.139 0.360
#> .ls_p3 0.388 0.053 7.360 0.000 0.388 0.650
#> SUP_Parents 0.572 0.100 5.719 0.000 1.000 1.000
#> SUP_Friends 0.611 0.097 6.297 0.000 1.000 1.000
#> SE_Academic 0.441 0.077 5.740 0.000 1.000 1.000
#> SE_Social 0.338 0.060 5.623 0.000 1.000 1.000
#> LS 0.386 0.087 4.447 0.000 1.000 1.000
Metric (weak) measurement invariance
In the second step, the loading parameters of the measurement model are restricted to equality between the groups. The model fit and a model comparison with the previous model allow conclusions regarding the hypothesis of a “weak” (metric) measurement invariance across groups.
fit_metric <- sem(model_measurement,
data = data_clean,
group = "region",
group.equal = "loadings")
summary(fit_metric, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 62 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 110
#> Number of equality constraints 10
#> Row rank of the constraints matrix 10
#>
#> Number of observations per group
#> west 119
#> east 136
#>
#> Estimator ML
#> Model Fit Test Statistic 336.607
#> Degrees of freedom 170
#> P-value (Chi-square) 0.000
#>
#> Chi-square for each group:
#>
#> west 159.965
#> east 176.642
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 2346.528
#> Degrees of freedom 210
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.922
#> Tucker-Lewis Index (TLI) 0.904
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3447.812
#> Loglikelihood unrestricted model (H1) -3279.508
#>
#> Number of free parameters 100
#> Akaike (AIC) 7095.624
#> Bayesian (BIC) 7449.750
#> Sample-size adjusted Bayesian (BIC) 7132.726
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.088
#> 90 Percent Confidence Interval 0.074 0.101
#> P-value RMSEA <= 0.05 0.000
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.072
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#>
#> Group 1 [west]:
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sp_pr_1 1.000 0.822 0.864
#> sp_pr_2 (.p2.) 1.117 0.067 16.548 0.000 0.918 0.921
#> sp_pr_3 (.p3.) 1.016 0.070 14.472 0.000 0.835 0.780
#> SUP_Friends =~
#> sp_fr_1 1.000 0.876 0.862
#> sp_fr_2 (.p5.) 0.837 0.051 16.328 0.000 0.733 0.825
#> sp_fr_3 (.p6.) 0.910 0.058 15.669 0.000 0.797 0.839
#> SE_Academic =~
#> s_cd_p1 1.000 0.635 0.885
#> s_cd_p2 (.p8.) 0.812 0.056 14.525 0.000 0.515 0.826
#> s_cd_p3 (.p9.) 0.932 0.065 14.384 0.000 0.592 0.820
#> SE_Social =~
#> s_scl_1 1.000 0.545 0.829
#> s_scl_2 (.11.) 0.946 0.063 15.087 0.000 0.516 0.821
#> s_scl_3 (.12.) 0.933 0.076 12.211 0.000 0.509 0.726
#> LS =~
#> ls_p1 1.000 0.495 0.616
#> ls_p2 (.14.) 0.863 0.092 9.403 0.000 0.427 0.756
#> ls_p3 (.15.) 0.836 0.107 7.829 0.000 0.414 0.570
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents ~~
#> SUP_Friends 0.133 0.075 1.767 0.077 0.184 0.184
#> SE_Academic 0.203 0.057 3.539 0.000 0.389 0.389
#> SE_Social 0.171 0.050 3.399 0.001 0.382 0.382
#> LS 0.229 0.055 4.195 0.000 0.562 0.562
#> SUP_Friends ~~
#> SE_Academic 0.089 0.058 1.522 0.128 0.160 0.160
#> SE_Social 0.144 0.053 2.714 0.007 0.301 0.301
#> LS 0.129 0.053 2.440 0.015 0.297 0.297
#> SE_Academic ~~
#> SE_Social 0.231 0.044 5.274 0.000 0.668 0.668
#> LS 0.129 0.040 3.260 0.001 0.411 0.411
#> SE_Social ~~
#> LS 0.175 0.039 4.530 0.000 0.649 0.649
#>
#> Intercepts:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 6.130 0.087 70.247 0.000 6.130 6.440
#> .sup_parents_p2 5.992 0.091 65.562 0.000 5.992 6.010
#> .sup_parents_p3 5.748 0.098 58.553 0.000 5.748 5.368
#> .sup_friends_p1 5.887 0.093 63.187 0.000 5.887 5.792
#> .sup_friends_p2 6.050 0.081 74.269 0.000 6.050 6.808
#> .sup_friends_p3 6.059 0.087 69.566 0.000 6.059 6.377
#> .se_acad_p1 5.022 0.066 76.371 0.000 5.022 7.001
#> .se_acad_p2 5.159 0.057 90.170 0.000 5.159 8.266
#> .se_acad_p3 4.922 0.066 74.357 0.000 4.922 6.816
#> .se_social_p1 5.306 0.060 88.019 0.000 5.306 8.069
#> .se_social_p2 5.436 0.058 94.397 0.000 5.436 8.653
#> .se_social_p3 5.367 0.064 83.561 0.000 5.367 7.660
#> .ls_p1 5.314 0.074 72.061 0.000 5.314 6.606
#> .ls_p2 5.847 0.052 112.918 0.000 5.847 10.351
#> .ls_p3 5.124 0.067 76.916 0.000 5.124 7.051
#> SUP_Parents 0.000 0.000 0.000
#> SUP_Friends 0.000 0.000 0.000
#> SE_Academic 0.000 0.000 0.000
#> SE_Social 0.000 0.000 0.000
#> LS 0.000 0.000 0.000
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.230 0.045 5.151 0.000 0.230 0.254
#> .sup_parents_p2 0.151 0.045 3.353 0.001 0.151 0.152
#> .sup_parents_p3 0.449 0.069 6.516 0.000 0.449 0.392
#> .sup_friends_p1 0.265 0.056 4.703 0.000 0.265 0.257
#> .sup_friends_p2 0.252 0.046 5.513 0.000 0.252 0.319
#> .sup_friends_p3 0.268 0.051 5.227 0.000 0.268 0.296
#> .se_acad_p1 0.111 0.026 4.349 0.000 0.111 0.217
#> .se_acad_p2 0.124 0.022 5.703 0.000 0.124 0.318
#> .se_acad_p3 0.171 0.030 5.798 0.000 0.171 0.328
#> .se_social_p1 0.135 0.026 5.172 0.000 0.135 0.313
#> .se_social_p2 0.129 0.024 5.332 0.000 0.129 0.326
#> .se_social_p3 0.232 0.036 6.454 0.000 0.232 0.473
#> .ls_p1 0.402 0.062 6.466 0.000 0.402 0.621
#> .ls_p2 0.136 0.028 4.805 0.000 0.136 0.428
#> .ls_p3 0.357 0.053 6.738 0.000 0.357 0.675
#> SUP_Parents 0.676 0.110 6.171 0.000 1.000 1.000
#> SUP_Friends 0.768 0.124 6.176 0.000 1.000 1.000
#> SE_Academic 0.403 0.065 6.214 0.000 1.000 1.000
#> SE_Social 0.297 0.051 5.826 0.000 1.000 1.000
#> LS 0.245 0.058 4.210 0.000 1.000 1.000
#>
#>
#> Group 2 [east]:
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sp_pr_1 1.000 0.732 0.823
#> sp_pr_2 (.p2.) 1.117 0.067 16.548 0.000 0.817 0.874
#> sp_pr_3 (.p3.) 1.016 0.070 14.472 0.000 0.743 0.804
#> SUP_Friends =~
#> sp_fr_1 1.000 0.769 0.882
#> sp_fr_2 (.p5.) 0.837 0.051 16.328 0.000 0.644 0.879
#> sp_fr_3 (.p6.) 0.910 0.058 15.669 0.000 0.700 0.820
#> SE_Academic =~
#> s_cd_p1 1.000 0.625 0.826
#> s_cd_p2 (.p8.) 0.812 0.056 14.525 0.000 0.507 0.806
#> s_cd_p3 (.p9.) 0.932 0.065 14.384 0.000 0.583 0.796
#> SE_Social =~
#> s_scl_1 1.000 0.570 0.814
#> s_scl_2 (.11.) 0.946 0.063 15.087 0.000 0.539 0.917
#> s_scl_3 (.12.) 0.933 0.076 12.211 0.000 0.532 0.717
#> LS =~
#> ls_p1 1.000 0.580 0.688
#> ls_p2 (.14.) 0.863 0.092 9.403 0.000 0.501 0.801
#> ls_p3 (.15.) 0.836 0.107 7.829 0.000 0.485 0.616
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents ~~
#> SUP_Friends 0.071 0.055 1.297 0.195 0.126 0.126
#> SE_Academic 0.191 0.049 3.866 0.000 0.417 0.417
#> SE_Social 0.205 0.046 4.477 0.000 0.492 0.492
#> LS 0.269 0.055 4.919 0.000 0.634 0.634
#> SUP_Friends ~~
#> SE_Academic 0.058 0.047 1.228 0.219 0.121 0.121
#> SE_Social 0.172 0.046 3.779 0.000 0.393 0.393
#> LS 0.171 0.050 3.400 0.001 0.383 0.383
#> SE_Academic ~~
#> SE_Social 0.198 0.041 4.853 0.000 0.554 0.554
#> LS 0.182 0.044 4.136 0.000 0.503 0.503
#> SE_Social ~~
#> LS 0.255 0.046 5.508 0.000 0.772 0.772
#>
#> Intercepts:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 6.077 0.076 79.717 0.000 6.077 6.836
#> .sup_parents_p2 6.107 0.080 76.131 0.000 6.107 6.528
#> .sup_parents_p3 5.926 0.079 74.718 0.000 5.926 6.407
#> .sup_friends_p1 5.941 0.075 79.423 0.000 5.941 6.810
#> .sup_friends_p2 6.125 0.063 97.480 0.000 6.125 8.359
#> .sup_friends_p3 6.143 0.073 83.996 0.000 6.143 7.203
#> .se_acad_p1 5.355 0.065 82.538 0.000 5.355 7.078
#> .se_acad_p2 5.553 0.054 102.864 0.000 5.553 8.821
#> .se_acad_p3 5.547 0.063 88.339 0.000 5.547 7.575
#> .se_social_p1 5.418 0.060 90.268 0.000 5.418 7.740
#> .se_social_p2 5.667 0.050 112.343 0.000 5.667 9.633
#> .se_social_p3 5.662 0.064 89.030 0.000 5.662 7.634
#> .ls_p1 5.289 0.072 73.142 0.000 5.289 6.272
#> .ls_p2 5.898 0.054 110.019 0.000 5.898 9.434
#> .ls_p3 5.520 0.068 81.762 0.000 5.520 7.011
#> SUP_Parents 0.000 0.000 0.000
#> SUP_Friends 0.000 0.000 0.000
#> SE_Academic 0.000 0.000 0.000
#> SE_Social 0.000 0.000 0.000
#> LS 0.000 0.000 0.000
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.255 0.043 5.952 0.000 0.255 0.322
#> .sup_parents_p2 0.207 0.043 4.758 0.000 0.207 0.236
#> .sup_parents_p3 0.303 0.048 6.264 0.000 0.303 0.354
#> .sup_friends_p1 0.169 0.035 4.882 0.000 0.169 0.223
#> .sup_friends_p2 0.122 0.025 4.968 0.000 0.122 0.228
#> .sup_friends_p3 0.238 0.037 6.348 0.000 0.238 0.327
#> .se_acad_p1 0.182 0.033 5.426 0.000 0.182 0.317
#> .se_acad_p2 0.139 0.024 5.810 0.000 0.139 0.350
#> .se_acad_p3 0.196 0.033 5.982 0.000 0.196 0.366
#> .se_social_p1 0.165 0.026 6.336 0.000 0.165 0.337
#> .se_social_p2 0.055 0.015 3.575 0.000 0.055 0.160
#> .se_social_p3 0.267 0.037 7.300 0.000 0.267 0.486
#> .ls_p1 0.375 0.055 6.809 0.000 0.375 0.527
#> .ls_p2 0.140 0.027 5.225 0.000 0.140 0.359
#> .ls_p3 0.385 0.053 7.290 0.000 0.385 0.620
#> SUP_Parents 0.536 0.085 6.300 0.000 1.000 1.000
#> SUP_Friends 0.592 0.089 6.647 0.000 1.000 1.000
#> SE_Academic 0.391 0.063 6.197 0.000 1.000 1.000
#> SE_Social 0.325 0.053 6.091 0.000 1.000 1.000
#> LS 0.337 0.072 4.663 0.000 1.000 1.000
anova(fit_configural, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_configural 160 7107.1 7496.6 328.06
#> fit_metric 170 7095.6 7449.7 336.61 8.5466 10 0.5756
The comparison is not significant, thus metric measurement invariance can be assumed.
Scalar (strong) measurement invariance
In the next step, the intercepts of the manifest variables are additionally restricted to equality. Model fit and a model comparison with the previous model allow conclusions regarding the hypothesis of scalar (strong) measurement invariance. Scalar measurement invariance means that there is no differential item-functioning across groups.
However, this does not mean that a complete measure invariance is given, because the procedure is not able to determine group-specific uniform response styles that are invariant across the items of a construct.
fit_scalar <- sem(model_measurement,
data = data_clean,
group = "region",
group.equal = c("loadings", "intercepts"))
summary(fit_scalar, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 136 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 115
#> Number of equality constraints 25
#> Row rank of the constraints matrix 25
#>
#> Number of observations per group
#> west 119
#> east 136
#>
#> Estimator ML
#> Model Fit Test Statistic 385.181
#> Degrees of freedom 180
#> P-value (Chi-square) 0.000
#>
#> Chi-square for each group:
#>
#> west 181.030
#> east 204.151
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 2346.528
#> Degrees of freedom 210
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.904
#> Tucker-Lewis Index (TLI) 0.888
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3472.099
#> Loglikelihood unrestricted model (H1) -3279.508
#>
#> Number of free parameters 90
#> Akaike (AIC) 7124.198
#> Bayesian (BIC) 7442.912
#> Sample-size adjusted Bayesian (BIC) 7157.590
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.095
#> 90 Percent Confidence Interval 0.082 0.108
#> P-value RMSEA <= 0.05 0.000
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.078
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#>
#> Group 1 [west]:
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sp_pr_1 1.000 0.816 0.858
#> sp_pr_2 (.p2.) 1.129 0.069 16.376 0.000 0.922 0.923
#> sp_pr_3 (.p3.) 1.026 0.072 14.348 0.000 0.838 0.779
#> SUP_Friends =~
#> sp_fr_1 1.000 0.875 0.862
#> sp_fr_2 (.p5.) 0.838 0.051 16.348 0.000 0.734 0.825
#> sp_fr_3 (.p6.) 0.911 0.058 15.689 0.000 0.797 0.839
#> SE_Academic =~
#> s_cd_p1 1.000 0.601 0.858
#> s_cd_p2 (.p8.) 0.869 0.057 15.365 0.000 0.522 0.833
#> s_cd_p3 (.p9.) 1.049 0.068 15.423 0.000 0.630 0.839
#> SE_Social =~
#> s_scl_1 1.000 0.531 0.813
#> s_scl_2 (.11.) 0.981 0.065 15.102 0.000 0.521 0.826
#> s_scl_3 (.12.) 0.980 0.079 12.428 0.000 0.521 0.736
#> LS =~
#> ls_p1 1.000 0.484 0.602
#> ls_p2 (.14.) 0.874 0.094 9.249 0.000 0.422 0.749
#> ls_p3 (.15.) 0.881 0.113 7.768 0.000 0.426 0.568
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents ~~
#> SUP_Friends 0.131 0.074 1.757 0.079 0.183 0.183
#> SE_Academic 0.195 0.054 3.585 0.000 0.397 0.397
#> SE_Social 0.165 0.049 3.380 0.001 0.380 0.380
#> LS 0.223 0.053 4.181 0.000 0.566 0.566
#> SUP_Friends ~~
#> SE_Academic 0.080 0.055 1.440 0.150 0.151 0.151
#> SE_Social 0.141 0.052 2.733 0.006 0.304 0.304
#> LS 0.127 0.052 2.448 0.014 0.300 0.300
#> SE_Academic ~~
#> SE_Social 0.212 0.041 5.210 0.000 0.664 0.664
#> LS 0.123 0.037 3.306 0.001 0.424 0.424
#> SE_Social ~~
#> LS 0.169 0.037 4.518 0.000 0.656 0.656
#>
#> Intercepts:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sp_pr_1 (.46.) 6.067 0.083 73.139 0.000 6.067 6.375
#> .sp_pr_2 (.47.) 6.007 0.090 66.697 0.000 6.007 6.016
#> .sp_pr_3 (.48.) 5.814 0.088 65.881 0.000 5.814 5.406
#> .sp_fr_1 (.49.) 5.873 0.088 66.461 0.000 5.873 5.781
#> .sp_fr_2 (.50.) 6.058 0.075 80.708 0.000 6.058 6.814
#> .sp_fr_3 (.51.) 6.067 0.082 74.180 0.000 6.067 6.383
#> .s_cd_p1 (.52.) 4.969 0.062 79.914 0.000 4.969 7.102
#> .s_cd_p2 (.53.) 5.156 0.055 93.905 0.000 5.156 8.233
#> .s_cd_p3 (.54.) 4.991 0.066 75.571 0.000 4.991 6.646
#> .s_scl_1 (.55.) 5.259 0.057 93.043 0.000 5.259 8.051
#> .s_scl_2 (.56.) 5.454 0.055 99.893 0.000 5.454 8.640
#> .s_scl_3 (.57.) 5.412 0.059 91.915 0.000 5.412 7.647
#> .ls_p1 (.58.) 5.237 0.063 82.545 0.000 5.237 6.519
#> .ls_p2 (.59.) 5.820 0.049 118.918 0.000 5.820 10.325
#> .ls_p3 (.60.) 5.276 0.059 90.141 0.000 5.276 7.034
#> SUP_Prn 0.000 0.000 0.000
#> SUP_Frn 0.000 0.000 0.000
#> SE_Acdm 0.000 0.000 0.000
#> SE_Socl 0.000 0.000 0.000
#> LS 0.000 0.000 0.000
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.239 0.045 5.266 0.000 0.239 0.264
#> .sup_parents_p2 0.147 0.045 3.246 0.001 0.147 0.147
#> .sup_parents_p3 0.454 0.070 6.510 0.000 0.454 0.393
#> .sup_friends_p1 0.266 0.056 4.713 0.000 0.266 0.257
#> .sup_friends_p2 0.252 0.046 5.510 0.000 0.252 0.319
#> .sup_friends_p3 0.268 0.051 5.226 0.000 0.268 0.296
#> .se_acad_p1 0.129 0.026 5.036 0.000 0.129 0.263
#> .se_acad_p2 0.120 0.022 5.553 0.000 0.120 0.305
#> .se_acad_p3 0.167 0.031 5.448 0.000 0.167 0.296
#> .se_social_p1 0.144 0.027 5.423 0.000 0.144 0.338
#> .se_social_p2 0.127 0.024 5.217 0.000 0.127 0.318
#> .se_social_p3 0.230 0.036 6.359 0.000 0.230 0.459
#> .ls_p1 0.411 0.063 6.534 0.000 0.411 0.638
#> .ls_p2 0.139 0.029 4.863 0.000 0.139 0.438
#> .ls_p3 0.381 0.057 6.728 0.000 0.381 0.677
#> SUP_Parents 0.667 0.109 6.128 0.000 1.000 1.000
#> SUP_Friends 0.766 0.124 6.176 0.000 1.000 1.000
#> SE_Academic 0.361 0.059 6.111 0.000 1.000 1.000
#> SE_Social 0.282 0.049 5.753 0.000 1.000 1.000
#> LS 0.234 0.057 4.129 0.000 1.000 1.000
#>
#>
#> Group 2 [east]:
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sp_pr_1 1.000 0.725 0.816
#> sp_pr_2 (.p2.) 1.129 0.069 16.376 0.000 0.819 0.875
#> sp_pr_3 (.p3.) 1.026 0.072 14.348 0.000 0.745 0.803
#> SUP_Friends =~
#> sp_fr_1 1.000 0.769 0.881
#> sp_fr_2 (.p5.) 0.838 0.051 16.348 0.000 0.644 0.879
#> sp_fr_3 (.p6.) 0.911 0.058 15.689 0.000 0.700 0.820
#> SE_Academic =~
#> s_cd_p1 1.000 0.582 0.786
#> s_cd_p2 (.p8.) 0.869 0.057 15.365 0.000 0.506 0.809
#> s_cd_p3 (.p9.) 1.049 0.068 15.423 0.000 0.611 0.807
#> SE_Social =~
#> s_scl_1 1.000 0.553 0.799
#> s_scl_2 (.11.) 0.981 0.065 15.102 0.000 0.543 0.921
#> s_scl_3 (.12.) 0.980 0.079 12.428 0.000 0.542 0.723
#> LS =~
#> ls_p1 1.000 0.568 0.675
#> ls_p2 (.14.) 0.874 0.094 9.249 0.000 0.496 0.796
#> ls_p3 (.15.) 0.881 0.113 7.768 0.000 0.501 0.617
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents ~~
#> SUP_Friends 0.071 0.054 1.300 0.194 0.127 0.127
#> SE_Academic 0.175 0.046 3.821 0.000 0.414 0.414
#> SE_Social 0.197 0.044 4.455 0.000 0.491 0.491
#> LS 0.263 0.054 4.896 0.000 0.637 0.637
#> SUP_Friends ~~
#> SE_Academic 0.055 0.044 1.247 0.212 0.124 0.124
#> SE_Social 0.169 0.044 3.814 0.000 0.398 0.398
#> LS 0.168 0.049 3.401 0.001 0.385 0.385
#> SE_Academic ~~
#> SE_Social 0.177 0.037 4.779 0.000 0.548 0.548
#> LS 0.169 0.041 4.134 0.000 0.510 0.510
#> SE_Social ~~
#> LS 0.243 0.045 5.468 0.000 0.775 0.775
#>
#> Intercepts:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sp_pr_1 (.46.) 6.067 0.083 73.139 0.000 6.067 6.826
#> .sp_pr_2 (.47.) 6.007 0.090 66.697 0.000 6.007 6.419
#> .sp_pr_3 (.48.) 5.814 0.088 65.881 0.000 5.814 6.270
#> .sp_fr_1 (.49.) 5.873 0.088 66.461 0.000 5.873 6.734
#> .sp_fr_2 (.50.) 6.058 0.075 80.708 0.000 6.058 8.265
#> .sp_fr_3 (.51.) 6.067 0.082 74.180 0.000 6.067 7.111
#> .s_cd_p1 (.52.) 4.969 0.062 79.914 0.000 4.969 6.709
#> .s_cd_p2 (.53.) 5.156 0.055 93.905 0.000 5.156 8.243
#> .s_cd_p3 (.54.) 4.991 0.066 75.571 0.000 4.991 6.596
#> .s_scl_1 (.55.) 5.259 0.057 93.043 0.000 5.259 7.589
#> .s_scl_2 (.56.) 5.454 0.055 99.893 0.000 5.454 9.254
#> .s_scl_3 (.57.) 5.412 0.059 91.915 0.000 5.412 7.213
#> .ls_p1 (.58.) 5.237 0.063 82.545 0.000 5.237 6.229
#> .ls_p2 (.59.) 5.820 0.049 118.918 0.000 5.820 9.340
#> .ls_p3 (.60.) 5.276 0.059 90.141 0.000 5.276 6.502
#> SUP_Prn 0.072 0.103 0.699 0.485 0.099 0.099
#> SUP_Frn 0.077 0.110 0.694 0.488 0.100 0.100
#> SE_Acdm 0.461 0.082 5.630 0.000 0.791 0.791
#> SE_Socl 0.210 0.074 2.834 0.005 0.379 0.379
#> LS 0.115 0.077 1.489 0.136 0.203 0.203
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.264 0.044 6.051 0.000 0.264 0.334
#> .sup_parents_p2 0.204 0.044 4.677 0.000 0.204 0.234
#> .sup_parents_p3 0.305 0.049 6.247 0.000 0.305 0.355
#> .sup_friends_p1 0.170 0.035 4.897 0.000 0.170 0.223
#> .sup_friends_p2 0.122 0.025 4.964 0.000 0.122 0.227
#> .sup_friends_p3 0.238 0.037 6.345 0.000 0.238 0.327
#> .se_acad_p1 0.210 0.035 6.058 0.000 0.210 0.382
#> .se_acad_p2 0.135 0.024 5.660 0.000 0.135 0.346
#> .se_acad_p3 0.200 0.035 5.692 0.000 0.200 0.348
#> .se_social_p1 0.174 0.027 6.556 0.000 0.174 0.362
#> .se_social_p2 0.053 0.016 3.373 0.001 0.053 0.151
#> .se_social_p3 0.269 0.037 7.268 0.000 0.269 0.478
#> .ls_p1 0.384 0.056 6.894 0.000 0.384 0.544
#> .ls_p2 0.142 0.027 5.273 0.000 0.142 0.366
#> .ls_p3 0.408 0.056 7.275 0.000 0.408 0.619
#> SUP_Parents 0.526 0.084 6.253 0.000 1.000 1.000
#> SUP_Friends 0.591 0.089 6.645 0.000 1.000 1.000
#> SE_Academic 0.339 0.056 6.082 0.000 1.000 1.000
#> SE_Social 0.306 0.051 6.025 0.000 1.000 1.000
#> LS 0.323 0.070 4.577 0.000 1.000 1.000
anova(fit_metric, fit_scalar)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_scalar 180 7124.2 7442.9 385.18 48.575 10 4.874e-07 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
This time the comparison is highly significant. The assumption of identical intercepts and thus “strong” (scalar) measurement invariance must therefore be rejected. However, according to the information criterion BIC the “strong” measurement invariance model may be preferred. Another criterion frequently cited in the literature is that the more restrictive model (despite the significant chi-square value) should only have a CFI/TLI that is less 0.01 lower than the CFI/TLI of the less restrictive model.
m <- fitMeasures(fit_metric)[names = c("cfi", "tli")]
s <- fitMeasures(fit_scalar)[names = c("cfi", "tli")]
round(m - s, 3)
#> cfi tli
#> 0.018 0.016
Here we are above this cut-off value. Thus, strong measurement invariance is not supported.
Automated measurement invariance analysis using semTools
measurementInvariance(model = model_measurement,
data = data_clean,
group = "region")
#>
#> Measurement invariance models:
#>
#> Model 1 : fit.configural
#> Model 2 : fit.loadings
#> Model 3 : fit.intercepts
#> Model 4 : fit.means
#>
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit.configural 160 7107.1 7496.6 328.06
#> fit.loadings 170 7095.6 7449.7 336.61 8.547 10 0.5756
#> fit.intercepts 180 7124.2 7442.9 385.18 48.575 10 4.874e-07 ***
#> fit.means 185 7146.5 7447.6 417.53 32.350 5 5.065e-06 ***
#> ---
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#>
#>
#> Fit measures:
#>
#> cfi rmsea cfi.delta rmsea.delta
#> fit.configural 0.921 0.091 NA NA
#> fit.loadings 0.922 0.088 0.001 0.003
#> fit.intercepts 0.904 0.095 0.018 0.007
#> fit.means 0.891 0.099 0.013 0.005
Here the measurement invariance of the latent means is added in a last step (fit.means
). It is not supported (significant difference to the fit.intercepts
or strong MI model, but note that the latter already had to be rejected). Furthermore, questions regarding differences of latent means across groups are usually substantial research questions (with regard to hypothesized differences), thus rendering them rather unsuitable for a measurement invariance analysis.
10.3.2 Multi-group analyses for the structural model (moderation analyses)
In addition to measuring invariance, multi-group analysis can also be used to check the invariance of structural paths. This allows to check moderator hypotheses (group variables as moderators) for single or multiple structural paths.
First, however, a procedure is presented that checks the entire structural model (structure paths, correlations between exogenous latent variables, and residual covariances) for equivalence (in addition to the weak measurement invariance).
Overall moderation test / equivalence of the structural model across groups
fit_allequal <- sem(model,
data = data_clean,
group = "region",
group.equal = c("loadings", "regressions", "lv.covariances"))
summary(fit_allequal, fit.measures = TRUE, standardized = TRUE)
#> lavaan 0.6-4 ended normally after 51 iterations
#>
#> Optimization method NLMINB
#> Number of free parameters 110
#> Number of equality constraints 20
#> Row rank of the constraints matrix 20
#>
#> Number of observations per group
#> west 119
#> east 136
#>
#> Estimator ML
#> Model Fit Test Statistic 347.297
#> Degrees of freedom 180
#> P-value (Chi-square) 0.000
#>
#> Chi-square for each group:
#>
#> west 165.128
#> east 182.169
#>
#> Model test baseline model:
#>
#> Minimum Function Test Statistic 2346.528
#> Degrees of freedom 210
#> P-value 0.000
#>
#> User model versus baseline model:
#>
#> Comparative Fit Index (CFI) 0.922
#> Tucker-Lewis Index (TLI) 0.909
#>
#> Loglikelihood and Information Criteria:
#>
#> Loglikelihood user model (H0) -3453.157
#> Loglikelihood unrestricted model (H1) -3279.508
#>
#> Number of free parameters 90
#> Akaike (AIC) 7086.314
#> Bayesian (BIC) 7405.028
#> Sample-size adjusted Bayesian (BIC) 7119.706
#>
#> Root Mean Square Error of Approximation:
#>
#> RMSEA 0.085
#> 90 Percent Confidence Interval 0.072 0.099
#> P-value RMSEA <= 0.05 0.000
#>
#> Standardized Root Mean Square Residual:
#>
#> SRMR 0.083
#>
#> Parameter Estimates:
#>
#> Information Expected
#> Information saturated (h1) model Structured
#> Standard Errors Standard
#>
#>
#> Group 1 [west]:
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sp_pr_1 1.000 0.811 0.860
#> sp_pr_2 (.p2.) 1.115 0.068 16.494 0.000 0.905 0.916
#> sp_pr_3 (.p3.) 1.014 0.070 14.482 0.000 0.822 0.777
#> SUP_Friends =~
#> sp_fr_1 1.000 0.867 0.860
#> sp_fr_2 (.p5.) 0.835 0.051 16.318 0.000 0.724 0.821
#> sp_fr_3 (.p6.) 0.908 0.058 15.663 0.000 0.788 0.835
#> SE_Academic =~
#> s_cd_p1 1.000 0.625 0.879
#> s_cd_p2 (.p8.) 0.812 0.056 14.511 0.000 0.508 0.823
#> s_cd_p3 (.p9.) 0.932 0.065 14.350 0.000 0.583 0.817
#> SE_Social =~
#> s_scl_1 1.000 0.558 0.832
#> s_scl_2 (.11.) 0.941 0.063 15.005 0.000 0.525 0.828
#> s_scl_3 (.12.) 0.929 0.076 12.182 0.000 0.518 0.731
#> LS =~
#> ls_p1 1.000 0.549 0.653
#> ls_p2 (.14.) 0.860 0.093 9.246 0.000 0.473 0.783
#> ls_p3 (.15.) 0.848 0.108 7.853 0.000 0.466 0.621
#>
#> Regressions:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SE_Academic ~
#> SUP_Prn (.16.) 0.318 0.057 5.582 0.000 0.412 0.412
#> SUP_Frn (.17.) 0.063 0.052 1.210 0.226 0.087 0.087
#> SE_Social ~
#> SUP_Prn (.18.) 0.283 0.049 5.788 0.000 0.412 0.412
#> SUP_Frn (.19.) 0.194 0.045 4.307 0.000 0.302 0.302
#> LS ~
#> SE_Acdm (.20.) -0.018 0.071 -0.249 0.804 -0.020 -0.020
#> SE_Socl (.21.) 0.528 0.099 5.352 0.000 0.536 0.536
#> SUP_Prn (.22.) 0.246 0.052 4.736 0.000 0.363 0.363
#> SUP_Frn (.23.) 0.064 0.043 1.496 0.135 0.101 0.101
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .SE_Academic ~~
#> .SE_Socl (.24.) 0.145 0.024 5.931 0.000 0.549 0.549
#> SUP_Parents ~~
#> SUP_Frn (.45.) 0.095 0.045 2.128 0.033 0.135 0.135
#>
#> Intercepts:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 6.130 0.086 70.879 0.000 6.130 6.497
#> .sup_parents_p2 5.992 0.091 66.182 0.000 5.992 6.067
#> .sup_parents_p3 5.748 0.097 59.250 0.000 5.748 5.431
#> .sup_friends_p1 5.887 0.092 63.689 0.000 5.887 5.838
#> .sup_friends_p2 6.050 0.081 74.822 0.000 6.050 6.859
#> .sup_friends_p3 6.059 0.087 70.002 0.000 6.059 6.417
#> .se_acad_p1 5.022 0.065 77.045 0.000 5.022 7.063
#> .se_acad_p2 5.159 0.057 91.208 0.000 5.159 8.361
#> .se_acad_p3 4.922 0.065 75.262 0.000 4.922 6.899
#> .se_social_p1 5.306 0.061 86.335 0.000 5.306 7.914
#> .se_social_p2 5.436 0.058 93.560 0.000 5.436 8.577
#> .se_social_p3 5.367 0.065 82.634 0.000 5.367 7.575
#> .ls_p1 5.314 0.077 68.930 0.000 5.314 6.319
#> .ls_p2 5.847 0.055 105.674 0.000 5.847 9.687
#> .ls_p3 5.124 0.069 74.444 0.000 5.124 6.824
#> SUP_Parents 0.000 0.000 0.000
#> SUP_Friends 0.000 0.000 0.000
#> .SE_Academic 0.000 0.000 0.000
#> .SE_Social 0.000 0.000 0.000
#> .LS 0.000 0.000 0.000
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.232 0.045 5.211 0.000 0.232 0.261
#> .sup_parents_p2 0.157 0.045 3.522 0.000 0.157 0.161
#> .sup_parents_p3 0.444 0.068 6.503 0.000 0.444 0.396
#> .sup_friends_p1 0.264 0.056 4.709 0.000 0.264 0.260
#> .sup_friends_p2 0.253 0.046 5.547 0.000 0.253 0.326
#> .sup_friends_p3 0.271 0.051 5.274 0.000 0.271 0.303
#> .se_acad_p1 0.115 0.026 4.409 0.000 0.115 0.226
#> .se_acad_p2 0.123 0.022 5.663 0.000 0.123 0.322
#> .se_acad_p3 0.169 0.029 5.765 0.000 0.169 0.333
#> .se_social_p1 0.139 0.027 5.231 0.000 0.139 0.308
#> .se_social_p2 0.126 0.024 5.306 0.000 0.126 0.314
#> .se_social_p3 0.233 0.036 6.466 0.000 0.233 0.465
#> .ls_p1 0.405 0.063 6.453 0.000 0.405 0.573
#> .ls_p2 0.141 0.029 4.877 0.000 0.141 0.387
#> .ls_p3 0.347 0.052 6.656 0.000 0.347 0.615
#> SUP_Parents 0.658 0.106 6.202 0.000 1.000 1.000
#> SUP_Friends 0.752 0.121 6.215 0.000 1.000 1.000
#> .SE_Academic 0.318 0.050 6.421 0.000 0.813 0.813
#> .SE_Social 0.219 0.038 5.845 0.000 0.706 0.706
#> .LS 0.111 0.036 3.103 0.002 0.367 0.367
#>
#>
#> Group 2 [east]:
#>
#> Latent Variables:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SUP_Parents =~
#> sp_pr_1 1.000 0.743 0.828
#> sp_pr_2 (.p2.) 1.115 0.068 16.494 0.000 0.829 0.878
#> sp_pr_3 (.p3.) 1.014 0.070 14.482 0.000 0.754 0.807
#> SUP_Friends =~
#> sp_fr_1 1.000 0.777 0.884
#> sp_fr_2 (.p5.) 0.835 0.051 16.318 0.000 0.649 0.880
#> sp_fr_3 (.p6.) 0.908 0.058 15.663 0.000 0.706 0.823
#> SE_Academic =~
#> s_cd_p1 1.000 0.636 0.832
#> s_cd_p2 (.p8.) 0.812 0.056 14.511 0.000 0.516 0.811
#> s_cd_p3 (.p9.) 0.932 0.065 14.350 0.000 0.592 0.799
#> SE_Social =~
#> s_scl_1 1.000 0.559 0.813
#> s_scl_2 (.11.) 0.941 0.063 15.005 0.000 0.527 0.909
#> s_scl_3 (.12.) 0.929 0.076 12.182 0.000 0.520 0.708
#> LS =~
#> ls_p1 1.000 0.532 0.655
#> ls_p2 (.14.) 0.860 0.093 9.246 0.000 0.458 0.773
#> ls_p3 (.15.) 0.848 0.108 7.853 0.000 0.451 0.589
#>
#> Regressions:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> SE_Academic ~
#> SUP_Prn (.16.) 0.318 0.057 5.582 0.000 0.371 0.371
#> SUP_Frn (.17.) 0.063 0.052 1.210 0.226 0.076 0.076
#> SE_Social ~
#> SUP_Prn (.18.) 0.283 0.049 5.788 0.000 0.376 0.376
#> SUP_Frn (.19.) 0.194 0.045 4.307 0.000 0.269 0.269
#> LS ~
#> SE_Acdm (.20.) -0.018 0.071 -0.249 0.804 -0.021 -0.021
#> SE_Socl (.21.) 0.528 0.099 5.352 0.000 0.555 0.555
#> SUP_Prn (.22.) 0.246 0.052 4.736 0.000 0.343 0.343
#> SUP_Frn (.23.) 0.064 0.043 1.496 0.135 0.093 0.093
#>
#> Covariances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .SE_Academic ~~
#> .SE_Socl (.24.) 0.145 0.024 5.931 0.000 0.511 0.511
#> SUP_Parents ~~
#> SUP_Frn (.45.) 0.095 0.045 2.128 0.033 0.165 0.165
#>
#> Intercepts:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 6.077 0.077 78.993 0.000 6.077 6.774
#> .sup_parents_p2 6.107 0.081 75.454 0.000 6.107 6.470
#> .sup_parents_p3 5.926 0.080 74.014 0.000 5.926 6.347
#> .sup_friends_p1 5.941 0.075 78.906 0.000 5.941 6.766
#> .sup_friends_p2 6.125 0.063 96.921 0.000 6.125 8.311
#> .sup_friends_p3 6.143 0.074 83.553 0.000 6.143 7.165
#> .se_acad_p1 5.355 0.065 81.775 0.000 5.355 7.012
#> .se_acad_p2 5.553 0.055 101.713 0.000 5.553 8.722
#> .se_acad_p3 5.547 0.064 87.248 0.000 5.547 7.481
#> .se_social_p1 5.418 0.059 91.882 0.000 5.418 7.879
#> .se_social_p2 5.667 0.050 114.129 0.000 5.667 9.786
#> .se_social_p3 5.662 0.063 89.979 0.000 5.662 7.716
#> .ls_p1 5.289 0.070 75.996 0.000 5.289 6.517
#> .ls_p2 5.898 0.051 116.261 0.000 5.898 9.969
#> .ls_p3 5.520 0.066 84.001 0.000 5.520 7.203
#> SUP_Parents 0.000 0.000 0.000
#> SUP_Friends 0.000 0.000 0.000
#> .SE_Academic 0.000 0.000 0.000
#> .SE_Social 0.000 0.000 0.000
#> .LS 0.000 0.000 0.000
#>
#> Variances:
#> Estimate Std.Err z-value P(>|z|) Std.lv Std.all
#> .sup_parents_p1 0.252 0.043 5.873 0.000 0.252 0.314
#> .sup_parents_p2 0.203 0.044 4.641 0.000 0.203 0.228
#> .sup_parents_p3 0.304 0.049 6.233 0.000 0.304 0.349
#> .sup_friends_p1 0.168 0.035 4.809 0.000 0.168 0.218
#> .sup_friends_p2 0.122 0.025 4.940 0.000 0.122 0.225
#> .sup_friends_p3 0.237 0.038 6.327 0.000 0.237 0.323
#> .se_acad_p1 0.179 0.033 5.387 0.000 0.179 0.308
#> .se_acad_p2 0.139 0.024 5.804 0.000 0.139 0.343
#> .se_acad_p3 0.199 0.033 6.011 0.000 0.199 0.362
#> .se_social_p1 0.160 0.026 6.202 0.000 0.160 0.338
#> .se_social_p2 0.058 0.016 3.675 0.000 0.058 0.173
#> .se_social_p3 0.268 0.037 7.282 0.000 0.268 0.498
#> .ls_p1 0.376 0.055 6.793 0.000 0.376 0.570
#> .ls_p2 0.141 0.027 5.225 0.000 0.141 0.402
#> .ls_p3 0.384 0.053 7.245 0.000 0.384 0.653
#> SUP_Parents 0.552 0.087 6.378 0.000 1.000 1.000
#> SUP_Friends 0.603 0.090 6.708 0.000 1.000 1.000
#> .SE_Academic 0.342 0.053 6.442 0.000 0.847 0.847
#> .SE_Social 0.235 0.038 6.229 0.000 0.753 0.753
#> .LS 0.108 0.033 3.278 0.001 0.380 0.380
This model is often compared to the weak (and not the strong) measurement invariance model because for CFAs/SEMs where the mean structure is not of interest the metric measurement invariance (equivalence of factor loadings) is sufficient.
anova(fit_metric, fit_allequal)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_allequal 180 7086.3 7405.0 347.30 10.691 10 0.3821
The model fit is not significantly different from the weak measurement invariance model. Therefore, the \(H_0\) that all parameters related to the structural model are equal across East and West German adolescents cannot be rejected and thus overall no moderation exists.
Moderated mediation analysis
We can conduct a moderated mediation analysis by using a group variable (factor) as a moderator variable for the paths in the structural model.
In order to test the differences of individual paths between the groups (moderation), we need an alternative method for equality constraints (explicit naming of the individual parameters).
We will show this first for all 8 regression paths individually, and then for the 4 combined paths representing the specific indirect effects in the model.
Moderation tests for the 8 individual paths
1) Support from Parents \(\rightarrow\) Academic Self-Efficacy
model_b1 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ c(b1, b1)*SUP_Parents + SUP_Friends
SE_Social ~ SUP_Parents + SUP_Friends
LS ~ SUP_Parents + SUP_Friends + SE_Academic + SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b1 <- sem(model_b1,
data = data_clean,
group = "region", group.equal = "loadings")
anova(fit_b1, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b1 171 7093.9 7444.5 336.91 0.30114 1 0.5832
2) Support from Parents \(\rightarrow\) Social Self-Efficacy
model_b2 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + SUP_Friends
SE_Social ~ c(b2, b2)*SUP_Parents + SUP_Friends
LS ~ SUP_Parents + SUP_Friends + SE_Academic + SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b2 <- sem(model_b2,
data = data_clean,
group = "region",
group.equal = "loadings")
anova(fit_b2, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b2 171 7095.5 7446.1 338.46 1.8496 1 0.1738
3) Support from Friends \(\rightarrow\) Academic Self-Efficacy
model_b3 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + c(b3, b3)*SUP_Friends
SE_Social ~ SUP_Parents + SUP_Friends
LS ~ SUP_Parents + SUP_Friends + SE_Academic + SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b3 <- sem(model_b3, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b3, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b3 171 7093.6 7444.2 336.62 0.008247 1 0.9276
4) Support from Friends \(\rightarrow\) Social Self-Efficacy
model_b4 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + SUP_Friends
SE_Social ~ SUP_Parents + c(b4, b4)*SUP_Friends
LS ~ SUP_Parents + SUP_Friends + SE_Academic + SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b4 <- sem(model_b4, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b4, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b4 171 7094.9 7445.5 337.91 1.3069 1 0.253
5) Support from Parents \(\rightarrow\) Life Satisfaction
model_b5 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + SUP_Friends
SE_Social ~ SUP_Parents + SUP_Friends
LS ~ c(b5, b5)*SUP_Parents + SUP_Friends + SE_Academic + SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b5 <- sem(model_b5, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b5, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b5 171 7093.8 7444.3 336.74 0.13528 1 0.713
6) Support from Friends \(\rightarrow\) Life Satisfaction
model_b6 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + SUP_Friends
SE_Social ~ SUP_Parents + SUP_Friends
LS ~ SUP_Parents + c(b6, b6)*SUP_Friends + SE_Academic + SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b6 <- sem(model_b6, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b6, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b6 171 7094.0 7444.6 336.97 0.36542 1 0.5455
7) Academic Self-Efficacy \(\rightarrow\) Life Satisfaction
model_b7 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + SUP_Friends
SE_Social ~ SUP_Parents + SUP_Friends
LS ~ SUP_Parents + SUP_Friends + c(b7, b7)*SE_Academic + SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b7 <- sem(model_b7, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b7, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b7 171 7094.5 7445.1 337.51 0.89933 1 0.343
8) Social Self-Efficacy \(\rightarrow\) Life Satisfaction
model_b8 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + SUP_Friends
SE_Social ~ SUP_Parents + SUP_Friends
LS ~ SUP_Parents + SUP_Friends + SE_Academic + c(b8, b8)*SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b8 <- sem(model_b8, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b8, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b8 171 7093.6 7444.2 336.62 0.012505 1 0.911
The results show that none of the 8 individual paths is significantly different across groups. We could have expected that already because of the overall non-significance of the group comparison of the structural model (see above).
Moderation tests for the 4 combined paths (indirect effects)
1) Support from Parents \(\rightarrow\) Academic Self-Efficacy \(\rightarrow\) Life Satisfaction
model_b1b7 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ c(b1, b1)*SUP_Parents + SUP_Friends
SE_Social ~ SUP_Parents + SUP_Friends
LS ~ SUP_Parents + SUP_Friends + c(b7, b7)*SE_Academic + SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b1b7 <- sem(model_b1b7, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b1b7, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b1b7 172 7092.9 7439.9 337.84 1.2315 2 0.5402
2) Support from Parents \(\rightarrow\) Social Self-Efficacy \(\rightarrow\) Life Satisfaction
model_b2b8 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + SUP_Friends
SE_Social ~ c(b2, b2)*SUP_Parents + SUP_Friends
LS ~ SUP_Parents + SUP_Friends + SE_Academic + c(b8, b8)*SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b2b8 <- sem(model_b2b8, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b2b8, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b2b8 172 7093.5 7440.5 338.48 1.8761 2 0.3914
3) Support from Friends \(\rightarrow\) Academic Self-Efficacy \(\rightarrow\) Life Satisfaction
model_b3b7 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + c(b3, b3)*SUP_Friends
SE_Social ~ SUP_Parents + SUP_Friends
LS ~ SUP_Parents + SUP_Friends + c(b7, b7)*SE_Academic + SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b3b7 <- sem(model_b3b7, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b3b7, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b3b7 172 7092.5 7439.6 337.51 0.90598 2 0.6357
4) Support from Friends \(\rightarrow\) Social Self-Efficacy \(\rightarrow\) Life Satisfaction
model_b4b8 <- '
# Measurement model
SUP_Parents =~ sup_parents_p1 + sup_parents_p2 + sup_parents_p3
SUP_Friends =~ sup_friends_p1 + sup_friends_p2 + sup_friends_p3
SE_Academic =~ se_acad_p1 + se_acad_p2 + se_acad_p3
SE_Social =~ se_social_p1 + se_social_p2 + se_social_p3
LS =~ ls_p1 + ls_p2 + ls_p3
# Structural model
# Regressions
SE_Academic ~ SUP_Parents + SUP_Friends
SE_Social ~ SUP_Parents + c(b4, b4)*SUP_Friends
LS ~ SUP_Parents + SUP_Friends + SE_Academic + c(b8, b8)*SE_Social
# Residual covariances
SE_Academic ~~ SE_Social
'
fit_b4b8 <- sem(model_b4b8, data = data_clean, group = "region",
group.equal = "loadings")
anova(fit_b4b8, fit_metric)
#> Chi Square Difference Test
#>
#> Df AIC BIC Chisq Chisq diff Df diff Pr(>Chisq)
#> fit_metric 170 7095.6 7449.7 336.61
#> fit_b4b8 172 7092.9 7440.0 337.93 1.3228 2 0.5161
The results show that none of the four specific indirect effects are significantly different across groups.
We can thus conclude that the groups do not differ with regard to the relations among latent variables and we can therefore interpret the effects found for the full sample. There is no need to differentiate between East and West German youths with regard to the mediated effects of social support (parents and friends) on life satisfaction via self-efficacy (academic and social).
10.4 References
Rosseel, Y. (2012). lavaan: An R Package for Structural Equation Modeling. Journal of Statistical Software, 48(2), 1-36. URL http://www.jstatsoft.org/v48/i02/.
Little, T. D., Cunningham, W. A., Shahar, G., & Widaman, K. F. (2002). To parcel or not to parcel: Exploring the question, weighing the merits. Structural Equation Modelling, 9(2), 151–173.