The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.

Models with Second-Order Factors

Shu Fai Cheung & Mark Hok Chio Lai

2023-10-15

Introduction

This article illustrates how to use set_sem_layout() from the package semptools (CRAN page) for a model with second-order factors. Readers are assumed to have learned how to use set_sem_layout() (see vignette("quick_start_sem")).

The Initial semPaths Plot

We will use sem_2nd_order_example, a sample SEM dataset from semptools with 21 variables for illustration.

library(semptools)
head(round(sem_2nd_order_example, 3), 3)
#>     x01    x02   x03   x04    x05    x06    x07    x08    x09    x10    x11
#> 1 0.773  0.246 0.959 1.819 -0.193  3.025  2.311  0.403  1.722  0.758  0.645
#> 2 0.757  0.303 0.139 0.516  0.514  2.145 -0.589  1.667 -0.001  2.513  2.381
#> 3 0.665 -1.135 0.199 0.764 -0.098 -1.293  1.481 -3.501 -1.215 -1.614 -0.073
#>      x12    x13    x14   x15    x16    x17    x18    x19    x20   x21
#> 1 -0.813  0.609  1.323 1.852  0.428 -0.284 -1.106  0.509  1.111 0.483
#> 2  2.102 -0.805  2.567 1.097 -0.288 -1.007  0.530 -0.722 -0.590 1.164
#> 3 -0.150  0.639 -1.507 0.860 -0.899 -0.882 -1.275 -0.616 -0.975 0.007

This is the SEM model to be fitted:

mod <-
  'f1 =~ x01 + x02 + x03
   f2 =~ x04 + x05 + x06 + x07
   f3 =~ x08 + x09 + x10
   f4 =~ x11 + x12 + x13 + x14
   f5 =~ x15 + x16 + x17 + x18
   f6 =~ x19 + x20 + x21
   f21 =~ 1*f1 + f3 + f4
   f22 =~ 1*f2 + f5 + f6
   f22 ~ f21
  '

Fitting the model using lavaan::sem():

library(lavaan)
fit <- lavaan::sem(mod, sem_2nd_order_example)

This is the plot from semPaths:

library(semPlot)
p <- semPaths(fit, whatLabels = "est",
              sizeMan = 5,
              nCharNodes = 0, nCharEdges = 0,
              edge.width = 0.8, node.width = 0.7,
              edge.label.cex = 0.6,
              style = "ram",
              mar = c(5, 5, 5, 5))

Modify the Plot

As described in vignette("set_sem_layout"), the plot can be modified by set_sem_layout(), with these special treatment:

Special Treatment

To modify a plot with second order factors:

In the example below, f1 to f6, though latent factors themselves, are included in the vector for indicator_order.

Example

indicator_order  <- c("x01", "x03", "x02",
                      "x05", "x06", "x04", "x07",
                      "x08", "x09", "x10",
                      "x12", "x11", "x13", "x14",
                      "x16", "x15", "x18", "x17",
                      "x20", "x19", "x21",
                      "f1", "f3", "f4",
                      "f5", "f6", "f2")
indicator_factor <- c("f1", "f1", "f1",
                      "f2", "f2", "f2", "f2",
                      "f3", "f3", "f3",
                      "f4", "f4", "f4", "f4",
                      "f5", "f5", "f5", "f5",
                      "f6", "f6", "f6",
                      "f21", "f21", "f21",
                      "f22", "f22", "f22")
factor_layout <- matrix(c(  NA, "f21",   NA, NA,  NA, "f22",   NA,
                          "f1",  "f4", "f3", NA, "f2",  "f6", "f5"),
                          byrow = TRUE, 2, 7)
factor_layout <- matrix(c("f1",    NA,    NA, "f2",
                          "f4", "f21", "f22", "f6",
                          "f3",    NA,    NA, "f5"),
                          byrow = TRUE, 3, 4)
factor_point_to <- matrix(c("left",     NA,      NA, "right",
                            "left", "left", "right", "right",
                            "left",     NA,      NA, "right"),
                            byrow = TRUE, 3, 4)
indicator_spread <- c(f4 = 1.25,
                      f2 = 1.25,
                      f5 = 1.25)
p2 <- set_sem_layout(p,
                     indicator_order = indicator_order,
                     indicator_factor = indicator_factor,
                     factor_layout = factor_layout,
                     factor_point_to = factor_point_to,
                     indicator_spread = indicator_spread)

This is the result:

plot(p2)

The layout is acceptable. It can be further modified by other functions described in vignette("semptools"). For example, the residuals can be rotated:

my_rotate_resid_list <- c(f4  =  45,
                          f21 =   0,
                          f22 =   0,
                          f6  = -45)
p3 <- rotate_resid(p2, my_rotate_resid_list)
plot(p3)

Further information

Please refer to vignette("quick_start_sem") on other options of set_sem_layout() and how to use it with other functions in the package.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.