Time Invariant Predictor of Slope and Intercept in Latent Growth Curve Model in OpenMx

862 Views Asked by At

I'm trying to figure out how to properly add a predictor of the slope and intercept in a latent growth curve model in the OpenMx package for R.

I would like to predict the slope and intercept from, say, gender in a very simple growth curve model. For the sake of this question, let's say it's the model described in the documentation here.

What would I add to include a time-invariant predictor of the slope and intercept? In MPlus I would write i on male; and I would get an estimate of the path from the gender variable to the latent intercept. To do the same thing in OpenMx would I simply add that path specification? Would I need override any defaults so that I don't estimate a variance or mean path for this manifest variable (or so I do)?

For easy reference, below is the code for the simple growth curve, and what I've added for the predictor. However, when I add the predictor I get the error 'covariance matrix is not positive-definite'. This is what I'm seeing in real data too.

n.b., this question is cross posted on the OpenMx forum.

myLongitudinalData=data.frame(x1=rnorm(100),
                              x2=rnorm(100),
                              x3=rnorm(100),
                              x4=rnorm(100),
                              x5=rnorm(100),
                              male=round(runif(100,0,1)))
require(OpenMx)

growthCurveModel <- mxModel("Linear Growth Curve Model Path Specification",
                            type="RAM",
                            mxData(
                              myLongitudinalData,
                              type="raw"
                            ),
                            manifestVars=c("x1","x2","x3","x4","x5"),
                            latentVars=c("intercept","slope"),
                            # residual variances
                            mxPath(
                              from=c("x1","x2","x3","x4","x5"),
                              arrows=2,
                              free=TRUE,
                              values = c(1, 1, 1, 1, 1),
                              labels=c("residual","residual","residual","residual","residual")
                            ),
                            # latent variances and covariance
                            mxPath(
                              from=c("intercept","slope"),
                              arrows=2,
                              connect="unique.pairs",
                              free=TRUE,
                              values=c(1, 1, 1),
                              labels=c("vari", "cov", "vars")
                            ),
                            # intercept loadings
                            mxPath(
                              from="intercept",
                              to=c("x1","x2","x3","x4","x5"),
                              arrows=1,
                              free=FALSE,
                              values=c(1, 1, 1, 1, 1)
                            ),
                            # slope loadings
                            mxPath(
                              from="slope",
                              to=c("x1","x2","x3","x4","x5"),
                              arrows=1,
                              free=FALSE,
                              values=c(0, 1, 2, 3, 4)
                            ),
                            # manifest means
                            mxPath(
                              from="one",
                              to=c("x1", "x2", "x3", "x4", "x5"),
                              arrows=1,
                              free=FALSE,
                              values=c(0, 0, 0, 0, 0)
                            ),
                            # latent means
                            mxPath(
                              from="one",
                              to=c("intercept", "slope"),
                              arrows=1,
                              free=TRUE,
                              values=c(1, 1),
                              labels=c("meani", "means")
                            )
) # close model

growthCurveFit <- mxRun(growthCurveModel)

summary(growthCurveFit)

My attempt to add a predictor--I add the gender variable to the manifest variables, and then create a path definition from it to the latent variables (toward the bottom):

growthCurveModel2 <- mxModel("Linear Growth Curve Model Path Specification",
                            type="RAM",
                            mxData(
                              myLongitudinalData,
                              type="raw"
                            ),
                            manifestVars=c("x1","x2","x3","x4","x5","male"),
                            latentVars=c("intercept","slope"),
                            # residual variances
                            mxPath(
                              from=c("x1","x2","x3","x4","x5"),
                              arrows=2,
                              free=TRUE,
                              values = c(1, 1, 1, 1, 1),
                              labels=c("residual","residual","residual","residual","residual")
                            ),
                            # latent variances and covariance
                            mxPath(
                              from=c("intercept","slope"),
                              arrows=2,
                              connect="unique.pairs",
                              free=TRUE,
                              values=c(1, 1, 1),
                              labels=c("vari", "cov", "vars")
                            ),
                            # intercept loadings
                            mxPath(
                              from="intercept",
                              to=c("x1","x2","x3","x4","x5"),
                              arrows=1,
                              free=FALSE,
                              values=c(1, 1, 1, 1, 1)
                            ),
                            # slope loadings
                            mxPath(
                              from="slope",
                              to=c("x1","x2","x3","x4","x5"),
                              arrows=1,
                              free=FALSE,
                              values=c(0, 1, 2, 3, 4)
                            ),
                            # manifest means
                            mxPath(
                              from="one",
                              to=c("x1", "x2", "x3", "x4", "x5"),
                              arrows=1,
                              free=FALSE,
                              values=c(0, 0, 0, 0, 0)
                            ),
                            # latent means
                            mxPath(
                              from="one",
                              to=c("intercept", "slope"),
                              arrows=1,
                              free=TRUE,
                              values=c(1, 1),
                              labels=c("meani", "means")
                            ),
                            mxPath(
                              from="male",
                              to=c("intercept", "slope"),
                              arrows=1,
                              free=TRUE,
                              values=c(1,1),
                              labels=c("iOnMale", "sOnMale"))
) # close model

growthCurveFit2 <- mxRun(growthCurveModel2)

summary(growthCurveFit2)
1

There are 1 best solutions below

0
On

I believe I figured it out--one must specify the predictor's variance and mean structure paths, in line with this diagram from Kline's SEM book (2011): LGC model with two predictors

In MPlus, I think that the default for regressing the latent slope and intercept on a predictor is to set the mean structure path to 0 and the variance path to 1. I'm not 100% sure about this, but this gave me an identical parameterization and very similar estimates. So, I added this snippet to the second model above:

                         #Predictor mean structure
                         mxPath(
                           from="one",
                           to="male",
                           arrows=1,
                           free=FALSE,
                           values = 0
                         ),
                         #Predictor Variance
                         mxPath(
                           from="male",
                           arrows=2,
                           free=FALSE,
                           values = 1
                         )

Kline, R. B. (2011). Principles and practice of structural equation modeling. Guilford press.