--- title: "Getting Started with mxmmod" author: "Kyle Husmann" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting Started with mxmmod} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} %\VignetteDepends{tidyverse} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) eval_semplots <- F ``` ## Overview This tutorial introduces the `mxmmod` package, for building Measurement Model of Derivatives (MMOD; Estabrook, 2015) with OpenMx. ## Outline A. Introduction to the Measurement Model of Derivatives (MMOD) B. Data set C. Example 1: One factor model D. Example 2: Two factor model E. Discussion ### Prelim: Prepare environment First, let's load the required libraries for this tutorial: ```{r, message=F, warning=F} library(tidyverse) library(OpenMx) library(mxmmod) ``` ## A. Introduction to the Measurement Model of Derivatives (MMOD) The Measurement Model of Derivatives (MMOD; Estabrook, 2015) is a method for evaluating test item structures that includes the temporal dynamics of item responses. Unlike traditional confirmatory factor analysis which only evaluates factor structures cross-sectionally at a single time point, an MMOD operates longitudinally, taking into account how latent factors and their associated items change over time. The MMOD makes the assumption that items from the same construct will exhibit similar temporal dynamcs (as defined by their deratives). In doing so, the MMOD can uniquely identify factor structures that would otherwise be indistinguishable cross-sectionally. By reducing the ambiguity in factor structure, the MMOD is a powerful tool to validate and sharpen theoretical distinctions among constructs in longitudinal data. ## B. Data set This tutorial follows the example in Estabrook (2015) and makes use of data from the National Longitudinal Survey of Youth. The NLSY 1997 sample ([NLSY97](https://www.bls.gov/nls/nlsy97.htm)) has a 5-item depression scale that was administered at three occasions. The five items are all on a 4-point Likert scale. Participants were asked how often they felt "like a nervous person", "calm and peaceful", "down or blue", "like a happy person", and "depressed" in the last month. These example data are included in the `mxmmod` package: ```{r} data(nlsy97depression) summary(nlsy97depression) ``` Before building any models, we first plot a few example trajectories and mean trajectories for the five items assessed: ```{r, fig.width=6, fig.height=6, fig.align='center'} set.seed(1000) subset <- sample(unique(nlsy97depression$pid), 9) nlsy97depression %>% filter(pid %in% subset) %>% gather(measure, val, -pid, -occasion) %>% ggplot(aes(x=occasion, group=measure, color=measure, y=val)) + geom_line(position=position_jitter(w=0.1, h=0.1)) + facet_wrap(~pid) ``` ```{r, fig.width=6, fig.height=4, fig.align='center'} nlsy97depression %>% gather(measure, val, -occasion, -pid) %>% na.omit() %>% ggplot(aes(x=occasion, color=measure, y=val)) + stat_summary(fun.y = mean, geom='line') + stat_summary(fun.y = mean, geom='point') + stat_summary(fun.data = mean_se, geom='errorbar', width=0.2) ``` ## C. Example 1: One factor model We'll start by building a 1-factor MMOD, with all items loading onto a single latent factor. ```{r} structure <- list( F1 = c('nervous', 'down', 'depressed', 'calm', 'happy') ) mmod_model <- mxMmodModel(data=nlsy97depression, modelName='1 Factor MMOD', idvar='pid', timevar='occasion', structure=structure, fiml=F) mmod_fit <- mxRun(mmod_model) (mmod_summary <- summary(mmod_fit)) ``` The path diagram of this MMOD can be rendered by `semPlot::semPaths` ```{r, eval=eval_semplots, fig.width=6, fig.height=4, fig.align='center'} # Note: This can take a while to draw... semPlot::semPaths(mmod_fit, 'est') ``` ## D. Example 2: Two factor model Next, let's build a two-factor MMOD with one latent factor for negative items (nervous, down, depressed), and the other for positive items (happy, calm): ```{r} structure2 <- list( F1 = c('nervous', 'down', 'depressed'), F2 = c('happy', 'calm') ) mmod_model2 <- mxMmodModel(data=nlsy97depression, modelName='2 Factor MMOD', idvar='pid', timevar='occasion', structure=structure2) mmod_fit2 <- mxRun(mmod_model2) (mmod_summary2 <- summary(mmod_fit2)) ``` The path diagram of this MMOD can be rendered by `semPlot::semPaths` ```{r, eval=eval_semplots, fig.width=6, fig.height=4, fig.align='center'} # Note: This can take a while to draw... semPlot::semPaths(mmod_fit2, 'est') ``` ## E. Discussion Finally, let's create a summary table of the fits from the two models so we can compare: ```{r} fits <- list(mmod_summary, mmod_summary2) (compare_models <- tibble( name=map_chr(fits, 'modelName'), chisq=map_dbl(fits, 'Chi'), dof=map_dbl(fits, 'ChiDoF'), `-2ll`=map_dbl(fits, 'Minus2LogLikelihood'), aic=map_dbl(fits, 'AIC.Mx'), bic=map_dbl(fits, 'BIC.Mx'), rmsea=map_dbl(fits, 'RMSEA'), cfi=map_dbl(fits, 'CFI'), tli=map_dbl(fits, 'TLI') )) ``` The two-factor model is superior, across every fit metric.