Mplus Automation: Dynamic Models & Documents with R

Joshua Wiley, M.A.

Senior Analyst — Elkhart Group

Why Automate?

“model building feels more like building stuff using legos now”

B. B.

Examples

Examples

We could estimate a latent growth model for the factors, and compare different residual structures

LGM fit with different residual structures
Homogenous CS Toeplitz Heterogenous
Chi square 1382.98 378.52 340.79 1354.50
df 276.00 270.00 258.00 258.00
p value 0.00 0.00 0.00 0.00
CFI 0.79 0.98 0.98 0.79
RMSEA 0.08 0.03 0.02 0.08
SRMR 0.06 0.04 0.04 0.06

Examples

How long would you estimate writing and running four models and putting the results into a table would take?

plot of chunk unnamed-chunk-3

Examples

Or plotting individual estimated growth curves from Mplus?

Individual growth curves using estimated latent scores with additive smooth

Overview

With the right tools, these examples take less than 30 minutes

  1. Write literal text, like you are reading now (e.g., using \(\LaTeX\), HTML)
  2. Write code within text, for analyses or graphs
    • Use R and the MplusAutomation package to automate communicating with Mplus
  3. Compile your document so that the code is run and results are inserted back into the text
    • using the knitr package to automate
  4. Share your awesome work!

Overview

  1. Background and introduction
  2. An example using MplusAutomation
    1. Creating the model
    2. Creating the output
  3. Knit it together
  4. Advanced example - this presentation

1. Background

Dynamic documents combine literal text with source code

They include reports, manuscripts, books, or presentations (like this one)

The source code may be shown or hidden, but when documents are compiled, the results are automatically included with the literal text

Dynamic documents grew out of the idea of literate programming introduced by Donald Knuth

By taking out the "human factor" between code and final document, time and error are reduced and results are more reproducible

1. Background

1. Background

MplusAutomation package connects R and Mplus

Both R and Mplus are written on the R side

R passes appropriate code to Mplus and parses the output files back into R

R has all the results and information we might want to report

1. Background

Documents can be written in virtually any markup language

Popular examples include markdown, HTML (this presentation) and \(\LaTeX\)

R source code is written in with the literal text, so the document and the code to analyze and report results are side by side

The R package knitr processes the document, extracts and runs the R code, and knits the results back into the original document

Aside on knitr

Written by Yihui Xie

Official website: http://yihui.name/knitr/

The book: Dynamic Documents with R and knitr, is coming out July from CRC Press

I am giving a longer presentation on knitr to the LA R User Group in June, check http://elkhartgroup.com/ for details

1. Background

1. Background

Text + R + Mplus

processed by MplusAutomation and knitr

Document text, actual source code to do the analyses, and the results are all together in one file

2. MplusAutomation

2. MplusAutomation

Heatmap of the correlation matrix among study variables at each time point

2. MplusAutomation

Descriptive Statistics at Time 3
N M SD 1. 2. 3. 4. 5. 6.
1. prc1T3 618 3.42 1.23 - 0.57 0.39 -0.25 -0.04 -0.11
2. prc2T3 618 3.25 1.28 - 0.49 -0.23 -0.08 -0.13
3. prc4T3 617 2.78 1.28 - -0.32 -0.16 -0.17
4. prc7T3 618 3.27 1.16 - 0.53 0.51
5. prc8T3 617 3.54 1.13 - 0.66
6. prc9T3 617 3.61 1.14 -

2.1 Creating the model

str(wdat, list.len = 3)  # see the dataset
## 'data.frame':	619 obs. of  44 variables:
##  $ prc1T3 : int  5 5 2 5 4 4 5 3 5 2 ...
##  $ prc2T3 : int  5 4 2 5 2 4 5 3 5 3 ...
##  $ prc3T3 : int  1 3 4 5 4 4 3 3 5 3 ...
##   [list output truncated]
prcvars  # vector of variable stubs
## [1] "prc1" "prc2" "prc4" "prc7" "prc8" "prc9"
# setup a temporary directory to write Mplus files in
base <- tempdir()
pre <- "cfa"

2.1 Creating the model

t3cfa.body <- mplusObject(
  TITLE = "CFA for PRC Control and Threat at T3;",
  ANALYSIS = "ESTIMATOR = MLR;",
  MODEL = "Threat BY prc1T3* prc2T3 prc4T3 prc7T3;
  Control BY prc7T3* prc8T3 prc9T3;
  Threat@1 Control@1;
  Threat WITH Control;",
  OUTPUT = "STDYX;
  MODINDICES (ALL 10);",
  usevariables = paste0(prcvars, "T3"),
  rdata = wdat)

2.1 Creating the model

mplusObject has similar sections to Mplus

There are other sections available not shown because they are not needed by default

The last two, in lower case, are R specific

Everything else Mplus needs is created automatically

2.1 Creating the model

str(t3cfa.body, max.level = 1, nchar.max = 30)
## List of 12
##  $ TITLE       : chr "CFA for PRC Control and Threa"| __truncated__
##  $ DATA        : NULL
##  $ VARIABLE    : NULL
##  $ DEFINE      : NULL
##  $ ANALYSIS    : chr "ESTIMATOR = MLR;"
##  $ MODEL       : chr "Threat BY prc1T3* prc2T3 prc4"| __truncated__
##  $ OUTPUT      : chr "STDYX;\n  MODINDICES (ALL 10)"| __truncated__
##  $ SAVEDATA    : NULL
##  $ PLOT        : NULL
##  $ results     : NULL
##  $ usevariables: chr [1:6] "prc1T3" "prc2T3" "prc4T3" "prc7T3" ...
##  $ rdata       :'data.frame':	619 obs. of  44 variables:
##  - attr(*, "class")= chr [1:2] "list" "mplusObject"

2.1 Creating the model

mplusModeler is a high level function that creates the data and input files for Mplus, runs it, and reads the results back into R

Besides the model object, there are a few additional arguments

2.1 Creating the model

cd(base, pre, num <- "prct3")
t3cfa <- mplusModeler(t3cfa.body,
  dataout = paste0(pre, num, ".dat"),
  modelout = paste0(pre, num, ".inp"), run=TRUE)
summary(t3cfa)
##  CFA for PRC Control and Threat at T3 
## 
## Estimated using MLR 
## Number of obs: 618, number of (free) parameters: 20 
## 
## Model: Chi2(df = 7) = 28.522, p = 2e-04 
## Baseline model: Chi2(df = 15) = 910.318, p = 0 
## 
## Fit Indices: 
## 
## CFI = 0.976, TLI = 0.948, SRMR = 0.035 
## RMSEA = 0.071, 90% CI [0.045, 0.098], p < .05 = 0.09 
## AIC = 10819.947, BIC = 10908.477

2.1 Creating the model

str(t3cfa, max.level = 1, nchar.max = 30)
## List of 12
##  $ TITLE       : chr "CFA for PRC Control and Threa"| __truncated__
##  $ DATA        : NULL
##  $ VARIABLE    : NULL
##  $ DEFINE      : NULL
##  $ ANALYSIS    : chr "ESTIMATOR = MLR;"
##  $ MODEL       : chr "Threat BY prc1T3* prc2T3 prc4"| __truncated__
##  $ OUTPUT      : chr "STDYX;\n  MODINDICES (ALL 10)"| __truncated__
##  $ SAVEDATA    : NULL
##  $ PLOT        : NULL
##  $ results     :List of 14
##   ..- attr(*, "class")= chr [1:2] "list" "mplus.model"
##   ..- attr(*, "filename")= chr "cfaprct3.out"
##  $ usevariables: chr [1:6] "prc1T3" "prc2T3" "prc4T3" "prc7T3" ...
##  $ rdata       :'data.frame':	619 obs. of  44 variables:
##  - attr(*, "class")= chr [1:2] "list" "mplusObject"

2.1 Creating the model

t3cfa containing original input the results from estimation

Methods exist for some standard functions like summary, coef (send me requests!)

It is also possible to update existing models, adding to or replacing sections

2.1 Creating the model

cd(base, pre, num <- "prct4")

t4cfa.body <- update(t3cfa.body,
 TITLE = ~ "CFA for PRC Control and Threat at T4;",
 MODEL = ~ "Threat BY prc1T4* prc2T4 prc4T4 prc7T4;
  Control BY prc7T4* prc8T4 prc9T4;
  Threat@1 Control@1;
  Threat WITH Control;",
 usevariables = paste0(prcvars, "T4"))

t4cfa <- mplusModeler(t4cfa.body, paste0(pre, num, ".dat"),
  paste0(pre, num, ".inp"), run=TRUE)

2.2 Creating the output

Next we do the same for the last two time points, but hide the results and do not echo the code

With a few lines of code, we can extract the summary statistics we want from each model, store them in table, and label the rows and columns.

cfa <- list(t3cfa, t4cfa, t5cfa, t6cfa)
res <- sapply(cfa, function(m) m$results$summaries)

out <- res[c("ChiSqM_Value", "ChiSqM_DF",
 "ChiSqM_PValue", "CFI", "RMSEA_Estimate", "SRMR"), ]

rownames(out) <- c("Chi square", "df", "p value",
  "CFI", "RMSEA", "SRMR")
colnames(out) <- paste("Time", 3:6)

2.2 Creating the output

The table in R looks like

print(out, digits = 7)
##            Time 3 Time 4 Time 5 Time 6
## Chi square 28.522 17.259 7.974  17.283
## df         7      7      7      7     
## p value    2e-04  0.0158 0.3349 0.0157
## CFI        0.976  0.985  0.999  0.982 
## RMSEA      0.071  0.054  0.017  0.059 
## SRMR       0.035  0.022  0.017  0.026

2.2 Creating the output

print(xtable(out,
 caption = "CFA fit statistics at each time point"),
 type = "html", file = "", html.table.attributes=NULL,
 comment=FALSE, caption.placement="top")
CFA fit statistics at each time point
Time 3 Time 4 Time 5 Time 6
Chi square 28.52 17.26 7.97 17.28
df 7.00 7.00 7.00 7.00
p value 0.00 0.02 0.33 0.02
CFI 0.98 0.98 1.00 0.98
RMSEA 0.07 0.05 0.02 0.06
SRMR 0.04 0.02 0.02 0.03

2.2 Creating the output

t3cfa$results$parameters$stdyx.standardized
##           paramHeader   param   est    se est_se  pval
## 1           THREAT.BY  PRC1T3  0.70 0.032   21.5 0e+00
## 2           THREAT.BY  PRC2T3  0.81 0.031   26.0 0e+00
## 3           THREAT.BY  PRC4T3  0.61 0.036   16.9 0e+00
## 4           THREAT.BY  PRC7T3 -0.24 0.041   -6.0 0e+00
## 5          CONTROL.BY  PRC7T3  0.60 0.037   16.0 0e+00
## 6          CONTROL.BY  PRC8T3  0.83 0.029   28.4 0e+00
## 7          CONTROL.BY  PRC9T3  0.80 0.033   24.3 0e+00
## 8         THREAT.WITH CONTROL -0.18 0.054   -3.3 1e-03
## 9          Intercepts  PRC1T3  2.79 0.078   35.7 0e+00
## 10         Intercepts  PRC2T3  2.54 0.070   36.2 0e+00
## 11         Intercepts  PRC4T3  2.16 0.051   42.2 0e+00
## 12         Intercepts  PRC7T3  2.82 0.083   34.0 0e+00
## 13         Intercepts  PRC8T3  3.12 0.094   33.3 0e+00
## 14         Intercepts  PRC9T3  3.18 0.096   33.0 0e+00
## 15          Variances  THREAT  1.00 0.000  999.0 1e+03
## 16          Variances CONTROL  1.00 0.000  999.0 1e+03
## 17 Residual.Variances  PRC1T3  0.52 0.045   11.5 0e+00
## 18 Residual.Variances  PRC2T3  0.35 0.050    6.9 0e+00
## 19 Residual.Variances  PRC4T3  0.63 0.044   14.5 0e+00
## 20 Residual.Variances  PRC7T3  0.54 0.044   12.3 0e+00
## 21 Residual.Variances  PRC8T3  0.31 0.048    6.4 0e+00
## 22 Residual.Variances  PRC9T3  0.36 0.052    6.9 0e+00

2.2 Creating the output

Loop through the models, creating nicely formatted results into a matrix

res <- lapply(cfa, function(m) {
  d <- m$results$parameters$stdyx.standardized[1:8, ]
  matrix(sprintf("%0.2f%s (%0.2f)", d$est,
    ifelse(d$pval < .05, "*", ""), d$se), dimnames = list(
    paste(d$paramHeader, d$param), "Est. (SE)"))
})

out <- do.call(cbind, res)
colnames(out) <- paste("Time", 3:6, colnames(out))

2.2 Creating the output

print(xtable(out,
 caption = "CFA standardized loadings at each time point"),
 type = "html", file = "", html.table.attributes=NULL,
 comment=FALSE, caption.placement="top")
CFA standardized loadings at each time point
Time 3 Est. (SE) Time 4 Est. (SE) Time 5 Est. (SE) Time 6 Est. (SE)
THREAT.BY PRC1T3 0.70* (0.03) 0.67* (0.04) 0.74* (0.04) 0.70* (0.04)
THREAT.BY PRC2T3 0.81* (0.03) 0.79* (0.04) 0.77* (0.04) 0.77* (0.04)
THREAT.BY PRC4T3 0.61* (0.04) 0.66* (0.04) 0.62* (0.04) 0.61* (0.04)
THREAT.BY PRC7T3 -0.24* (0.04) -0.24* (0.05) -0.27* (0.05) -0.29* (0.06)
CONTROL.BY PRC7T3 0.60* (0.04) 0.62* (0.05) 0.58* (0.05) 0.61* (0.05)
CONTROL.BY PRC8T3 0.83* (0.03) 0.77* (0.04) 0.85* (0.04) 0.81* (0.04)
CONTROL.BY PRC9T3 0.80* (0.03) 0.70* (0.04) 0.69* (0.03) 0.77* (0.04)
THREAT.WITH CONTROL -0.18* (0.05) -0.34* (0.06) -0.34* (0.06) -0.23* (0.07)

3. Knit it together

3. Knit it together

Now that we have seen how to use MplusAutomation, we can look at a complete example, mixing HTML + R code

We could also use \(\LaTeX\) + R, but HTML is a little easier

3. Knit it together

The actual source code is hosted here

3. Knit it together

Write HTML code with R code in comments (<--)

Save that in a file,

simpleknitr.Rhtml

Start R and use the commands:

  require(knitr)
  knit("simpleknitr.Rhtml")

knitr processes the .Rhtml and returns the results in simpleknitr.html

3. Knit it together

The actual page is hosted here

4. This presentation

4. This presentation

The basic steps used to create this procedure were already covered, however often for presentation we want to customize things

Almost anything is possible

Here is an example of the preamble, customize the size and location of figures

opts_chunk$set(fig.width=7, fig.height=5, out.width=700,
  out.height=500, fig.path="figures/r_mplus-",
  warning=FALSE, message=FALSE, width.cutoff=60)

4. This presentation

Beyond global settings, you may need to customize each chunk of code a bit

I used special flags like these:

begin.rcode results='hide', echo=FALSE

to have code in the presentation that was run and evaluated, but the code and results were hidden

You can also customize other aspects

begin.rcode echo=FALSE, fig.width=12, fig.height=10,
  out.width=800, out.height=667,
  fig.cap="Heatmap of the correlation matrix among study variables at each time point"

4. This presentation

The actual slides were written using HTML5 and the deck.js slides

For math, and here just for the \(\LaTeX\) name, http://www.mathjax.org/

Check out the source code here

## R version 3.0.0 (2013-04-03)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## 
## attached base packages:
## [1] grid      tcltk     stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] animation_2.2         gridExtra_0.9.1       semutils_0.1.1       
##  [4] ggplot2_0.9.3.1       lavaan_0.5-13         quadprog_1.5-5       
##  [7] pbivnorm_0.5-1        mnormt_1.4-5          MASS_7.3-26          
## [10] MplusAutomation_0.6-1 boot_1.3-9            plyr_1.8             
## [13] mgcv_1.7-22           xtable_1.7-1          reshape2_1.2.2       
## [16] knitr_1.2

Review

Packages

MplusAutomation

R Functions

Questions?

Email me feature requests

/

#
authentic louis vuitton on sale Chloe handbags crossbody fake outlet official authentic Heels men authentic best christian louboutin outlet fake Official 2015 handbags wallet celine store outlet Best wholesale replica cheap christian louboutin heels boots Handbags purse celine fake outlet authentic official Outlet store handbags usa fake celine Herm├Ęs Pas Cher bags birkin shop Cheap hermes Official Wholesale bags louis vuitton outlet online Official celine outlet replica handbags mini luggage tote Wholesale handbags phantom celine outlet replica Belt wallet fake prada outlet store Celine fake replica online handbags price Canada goose online women outlet chateau parka chloe designer handbag cheap canada goose salecheap canada gooseceline boston bagcheap canada goose
Official 2015 bags handbags store sale yves saint laurent prada handbags Authentic yves saint laurent outlet sale women clutch purse yves saint laurent crossbody purses replica chloe wallets Prada bags clutch online real replica fake Cheap replica online bags mini luggage tote celine Best outlet replica celine bags mini luggage Christian louboutin heels sandals best price outlet replica bags louis vuitton 2015 ceinture hermes pas cher 2015 yves saint laurent women belt outlet replica authentic louis vuitton for men christian louboutin flats in brighton england Handbags mini luggage outlet online fake celine Replica outlet bags wallet wholesale celine yves saint laurent Billige outlet prada bags & wallets sales & deals chloe cheap handbags wholesale Belt wallet fake prada outlet store Fake outlet soldes heels shoes christian louboutin Men outlet expedition parka canada goose authentic sale celine cabas cheap canda goosecheap canada gooseceline outletcanada goose uk
red bottoms sneakers hermes wallet outlet prada handbags outlet celine mini luggage tote outlet hermes sale prada sunglasses on sale prada handbags on sale hermes bags prada shoes cheap cheap chloe online sale hermes bag for sale prada wallet cheap chloe bag hermes belt replica prada sunglasses cheap hermes bags replica prada bags cheap red bottoms boots yves saint laurent shoulder bags prada handbags cheap prada wallet outlet birkin hermes handabgs
birkin bag outlet celine handbags outlet christian louboutin wedding shoes hermes replica canada christian louboutin pumps red bottoms heels cheap chloe outlet cheap chloe handbag 2015 christian louboutin wedding shoes chloe cheap bags 2015 hermes sale celine luggage tote sale hermes replica belt hermes replica belt prada sunglasses red bottoms sandals chloe handbags outlet online christian louboutin heels prada wallet cheap prada wallet cheap hermes handbags designer red bottoms sneakers