knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
knitr::opts_chunk$set(echo = TRUE)

Estimation

Maximum Likelihood

Maximum Likelihood

Maximum Likelihood

Maximum Likelihood

Other Methods

Generalized Least Squares

Unweighted Least Squares

Other Methods

Asymptotically Distribution Free

Errors

Why Errors Happen

Path Models

Path Models

Path Models

Solutions

Let's do it!

install.packages("lavaan")
install.packages("semPlot")

Syntax

Syntax

A Path Example

library(rio)
eval.data <- import("data/lecture_evals.csv")

A Path Example

knitr::include_graphics("pictures/lecture_evals.png")

Estimate df

Build the model

knitr::include_graphics("pictures/lecture_evals.png")
library(lavaan)
eval.model <- '
q4 ~ q12 + q2
q1 ~ q4 + q12
'

Important Notes

eval.model

Run the Model

eval.output <- sem(model = eval.model,
                   data = eval.data)

View the Output

summary(eval.output)

Output

Improved Output

summary(eval.output, 
        standardized = TRUE, # for the standardized solution
        fit.measures = TRUE, # for model fit
        rsquare = TRUE) # for SMCs

Create a Picture

library(semPlot)
semPaths(eval.output, # the analyzed model 
         whatLabels = "par", # what to add as the numbers, std for standardized
         edge.label.cex = 1, # make the font bigger
         layout = "spring") # change the layout tree, circle, spring, tree2, circle2

Another Example

regression.cor <- lav_matrix_lower2full(c(1.00,
                                         0.20,1.00,
                                         0.24,0.30,1.00,
                                         0.70,0.80,0.30,1.00))

# name the variables in the matrix
colnames(regression.cor) <-
  rownames(regression.cor) <-
  c("X1", "X2", "X3", "Y") 

Build the Model

regression.model <- '
# structural model for Y
Y ~ a*X1 + b*X2 + c*X3 
# label the residual variance of Y
Y ~~ z*Y 
'

Analyze the Model

regression.fit <- sem(model = regression.model,
                      sample.cov = regression.cor, # instead of data
                      sample.nobs = 1000) # number of data points

View the Summary

summary(regression.fit, 
        standardized = TRUE,
        fit.measures = TRUE,
        rsquare = TRUE)

Create a Picture

semPaths(regression.fit, 
         whatLabels="par", 
         edge.label.cex = 1,
         layout="tree")

Mediation Models

beaujean.cov <- lav_matrix_lower2full(c(648.07, 
                                        30.05, 8.64, 
                                        140.18, 25.57, 233.21))
colnames(beaujean.cov) <-
  rownames(beaujean.cov) <-
  c("salary", "school", "iq")

Build the Model

beaujean.model <- '
salary ~ a*school + c*iq
iq ~ b*school # this is reversed in first printing of the book 
ind:= b*c # this is the mediation part 
'

Analyze the Model

beaujean.fit <- sem(model = beaujean.model, 
                    sample.cov = beaujean.cov, 
                    sample.nobs = 300)

View the Summary

summary(beaujean.fit, 
        standardized = TRUE,
        fit.measures = TRUE,
        rsquare = TRUE)

Create a Picture

semPaths(beaujean.fit, 
         whatLabels="par", 
         edge.label.cex = 1,
         layout="tree")

Fit Indices

Limitations

"Rules"

Model Test Statistic

Model Test Statistic

Model Test Statistic

Model Test Statistic

Model Test Statistic

Alternative Fit Indices

Alternative Fit Indices

Absolute fit indices

Absolute Fit Indices

knitr::include_graphics("pictures/srmr_formula.png")

Incremental Fit Indices

Incremental Fit Indices

Incremental Fit Indices

Parsimony Adjusted Indices

Predictive Fit Indices

Model Comparisons

Model Comparisons

Model Comparisons Nested Models

chi_difference <- 12.6 - 4.3
df_difference <- 14 - 12
pchisq(chi_difference, df_difference, lower.tail = F)

Model Comparisons Nested Models

Model Comparisons Nested Models

Model Comparisons Nested Models

Model Comparisons Non-Nested Models

Model Comparisons Non-Nested Models

So what to report?

Path Comparison Example

compare.data <- lav_matrix_lower2full(c(1.00,
                                        .53,    1.00,   
                                        .15,    .18,    1.00,       
                                        .52,    .29,    -.05,   1.00,   
                                        .30,    .34,    .23,    .09,    1.00))

colnames(compare.data) <- 
  rownames(compare.data) <- 
  c("morale", "illness", "neuro", "relationship", "SES") 

Build a Model

#model 1
compare.model1 = '
illness ~ morale
relationship ~ morale
morale ~ SES + neuro
'

#model 2
compare.model2 = '
SES ~ illness + neuro
morale ~ SES + illness
relationship ~ morale + neuro
'

Analyze the Model

compare.model1.fit <- sem(compare.model1, 
                          sample.cov = compare.data, 
                          sample.nobs = 469)

summary(compare.model1.fit, 
        standardized = TRUE,
        fit.measures = TRUE,
        rsquare = TRUE)

Analyze the Model

compare.model2.fit <- sem(compare.model2, 
                          sample.cov = compare.data, 
                          sample.nobs = 469)

summary(compare.model2.fit, 
        standardized = TRUE,
        fit.measures = TRUE,
        rsquare = TRUE)

View the Model

semPaths(compare.model1.fit, 
         whatLabels="par", 
         edge.label.cex = 1,
         layout="spring")
semPaths(compare.model2.fit, 
         whatLabels="par", 
         edge.label.cex = 1,
         layout="spring")

Compare the Models

anova(compare.model1.fit, compare.model2.fit)
fitmeasures(compare.model1.fit, c("aic", "ecvi"))
fitmeasures(compare.model2.fit, c("aic", "ecvi"))

Summary



doomlab/learnSEM documentation built on Jan. 25, 2024, 2 p.m.