Skip to contents

Overview

This example demonstrates how to use the muppet() package to perform MUPPET modeling for a structural equation modeling (SEM) example. This example has 4 fragments. Fragment 1 is the measurement model for 3 latent variables. Fragment 2 defines a measurement model for 2 other latent variables. Fragment 3 then adds to the measurement model in Fragment 2, by adding some indicators to one of the latent variables. Fragment 4 is a structural model relating the latent variables from Fragment 1 to the latent variables in Fragment 3 (and 2).

Data Prepration

Load the package and extract the data for this example.

library(muppet)
data(sim.POWER, package = "muppet")
data.for.mplus <- sim.POWER.data

Look through the data and check if any of the column names have more than 8 characters. Owing to Mplus’s naming conventions for parameters, variable names should be 8 characters or fewer. For variables that are discrete (categorical), the length of the names should be 6 characters or fewer. (This holds as long as there are fewer than 10 thresholds for the categorical variables. If you’re using a variable with 10 or more thresholds, you will likely need an even shorter variable name.)

# * Check if any column names are more than 8 characters
if(!all(nchar(colnames(data.for.mplus)) <= 8)){
  print("Do not proceed. Rename Mplus variables to have <= 8 characters")
  print("See Permissive Norms Example R file for code on renaming variables")
}

Specify Fragment 1

The key specification for Fragment 1 is the Mplus syntax for the factor analytic measurement model. In this specification, there are 3 latent variables. All the latent variable means and variances are fixed, and all the loadings and intercepts are estimated.

Mplus.MODEL.syntax.fragment.1 <- "
  ! Working Memory Factor Model
  ! Central Executive
  CE BY NBAA* NBVA CeNmUp_I;

  ! Focus of Attention
  FOA BY VsSpnR_I* LcSpnR_I VsSpnW_I LcSpnW_I BndVBW BndCmBW DgSpnR_I BndPBSW;

  ! Phonological Storage Rehearsal
  PSR BY BndCmBW* DgSpnR_I BndPBSW DgSpnW_I PlNWWW;

  ! Factor Variances
  CE@1;
  FOA@1;
  PSR@1;

  ! Factor Correlations
  CE WITH FOA PSR;
  FOA WITH PSR;

  ! Factor Means
  [CE@0];
  [FOA@0];
  [PSR@0];
  "

Now define the specifications for the fragment. In this list we are passing along the syntax and data from above.

fragment.1.specs <- list(
  name = "Working Memory Measurement Model",
  model.syntax = Mplus.MODEL.syntax.fragment.1,
  conditioning = 0,
  data = data.for.mplus
)

Specify Fragment 2

Fragment 2 is a factor analytic measurement model, similar to Fragment 1. Here again, the key specification is the Mplus syntax for the factor analytic measurement model, where as above, the means and variances for the (2) latent variables are fixed, and the loadings and intercepts are estimated.

Mplus.MODEL.syntax.fragment.2 <- "
    ! Word Learning Factor Model

  ! Phonological
  PHON BY
  ICPVL1gm* ICPVL2gm DIPVL1gm DIPVL2gm
  SIPVL1gm SIPVL2gm LTPVL1gm LTPVL2gm ICNT2P ICNT1P
  DINT1P DINT2P PINTGM
  PIPVLgm;

  ! Semantic
  SEM BY ICVDD2ap* SIVDD1ap SIVDD2ap PIVDD0ap PIVFRgmp
  ICVDD1ap SIVFR1gm SIVFR2gm LTVFR1gm LTVFR2gm;

  ! Factor Variances
  PHON@1;
  SEM@1;

  ! Factor Correlations
  PHON WITH SEM;

  ! Factor Means
  [PHON@0];
  [SEM@0];
  "

Now define the specifications for the fragment. In this list we are passing along the syntax and data from above. Note that even though this is Fragment 2, it is not conditional on Fragment 1. This is expressed by the argument that conditioning = 0.

fragment.2.specs <- list(
  name = "Word Learning Measurement Model",
  model.syntax = Mplus.MODEL.syntax.fragment.2,
  conditioning = 0,
  data = data.for.mplus
)

Specify Fragment 3

Fragment 3 is conditional on Fragment 2, and adds to it by including additional variables as indicators for one of the latent variables. Note that the syntax here also includes the specifications fixing the latent variable means and variances. These were included in Fragment 1 as well, but also need to be here to preserve this constraint. In effect, the function will bring in the results for the fitted parameters from Fragment 2. But the latent variable means and variances were not fitted parameters in Fragment 2. They were fixed in Fragment 2. So they will not be “brought forward” by looking at the fitted results from Fragment 2. So they need to be specified here as well.

Mplus.MODEL.syntax.fragment.3 <- "
  ! Word Learning Factor Model

  ! Phonological
  PHON BY PIMD0ap* ICMD2ap ICMD1ap DIMD1ap  DIMD2ap;

  ! Factor Variances
  PHON@1;
  SEM@1;

  ! Factor Means
  [PHON@0];
  [SEM@0];
  "

Now define the specifications for the fragment. In this list we are passing along the syntax and data, as we did for other fragments. By setting conditioning = 2 in this list of specifications, we are instructing the functions to condition on the results from Fragment 2.

fragment.3.specs <- list(
  name = "Including More Word Learning Indicators",
  model.syntax = Mplus.MODEL.syntax.fragment.3,
  conditioning = 2,
  data = data.for.mplus
)

Specify Fragment 4

Fragment 4 contains the structural portion relating the latent variables from Fragment 1 to those in Fragment 3 (which were also a part of Fragment 2). The latent variables from Fragment 1 are were exogenous in that fragment, and remain so here. Accordingly, in the Mplus syntax their factor means and variances are fixed, as they were in Fragment 1. In contrast, the latent variables from Fragment 3 were exogenous in Fragment 3, but are now endogenous (being predicted by the latent variables from Fragment 1). Accordingly, Even though their means and variances were fixed in Fragment 3, those parameters are now functions of other parameters, and we estimate intercepts and latent disturbance variances for those latent variables as part of the structural model. Note also that the correlation between the latent disturbances is part of the fitted model here. This is for the same reason.

Mplus.MODEL.syntax.fragment.4 <- "

  ! Structural relations
  PHON ON CE FOA PSR;
  SEM ON CE FOA PSR;

  ! Structural intercepts
  [PHON];
  [SEM];

  ! Latent correlations (disturbances)
  PHON WITH SEM;

  ! Factor Variances
  CE@1;
  FOA@1;
  PSR@1;

  ! Factor Means
  [CE@0];
  [FOA@0];
  [PSR@0];
  "

Now define the specifications for the fragment. The first key element here is conditioning = c(1,2,3). This communicates that Fragment 4 is conditional on Fragments 1, 2, and 3. The next key element here is parameters.to.exclude.in.conditioning. This is a list with 3 entries, corresponding to the 3 fragments that we are conditioning on. The entries in the list express which parameters from that antecedent fragment to ignore (i.e., not carry forward to Fragment 4). In this example, we want to carry forward all the fitted parameters from Fragment 1, so the first element in the list is none. But we do want to ignore some of the fitted parameters from Fragment 2 and 3. In particular, we want to ignore the fitted covariances among the latent variables in those fragments, because those fragments are now endogenous, and we wish to estimate their latent disturbance covariance, as mentioned above. .

fragment.4.specs <- list(
  name = "Working Memory Predict Word Learning",
  model.syntax = Mplus.MODEL.syntax.fragment.4,
  conditioning = c(1,2,3),
  parameters.to.exclude.in.conditioning = list(
    # fragment 1
    "none",

    # fragment 2
    c("(co)variances of latent variables"),

    # fragment 3
    c("(co)variances of latent variables")

  ),
  data = data.for.mplus
)

Conduct MUPPET modeling

The code below demonstrates conducting MUPPET modeling. The fragments argument contains the specifications for the model fragments defined above. The rest of the arguments communicate specifications for running MCMC and saving output. Running this code will write out output files.

MUPPET.modular(
  fragments = list(fragment.1.specs, fragment.2.specs, fragment.3.specs, fragment.4.specs),
  n.chains = 2,
  n.warmup = 0,
  n.burnin = 500,
  n.iters.per.chain.after.warmup.and.burnin = 100,
  n.estimation.batches = 25,
  convergence.assessment = "none",
  save.summary.plots.from.MUPPET = "none"
)