Getting Started with mxmmod

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:

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) 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:

data(nlsy97depression)
summary(nlsy97depression)

Before building any models, we first plot a few example trajectories and mean trajectories for the five items assessed:

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)
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.

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

# 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):

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

# 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:

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.



Try the mxmmod package in your browser

Any scripts or data that you put into this service are public.

mxmmod documentation built on May 18, 2021, 5:09 p.m.