Welcome to the OpenMx SEM modeling forum.

9 replies [Last post]
Steve's picture
Offline
Joined: 07/30/2009

This forum is designed for discussions about how to create and fit SEM models with OpenMx. This forum is designed to be about the nuts and bolts of how to use OpenMx rather than a general purpose SEM modeling forum. For questions about the models themselves, rather than how to implement them in OpenMx, please see the OpenSEM forums where models are split by many different types.

kpreacher's picture
Offline
Joined: 08/23/2009
Esteemed developers - Forgive

Esteemed developers -

Forgive the novice question. In the course of trying to learn OpenMx I have been adapting working code to fit new models and new data. Below is a model for what ought to be a simple saturated path model with 5 variables:

helpful -> politics, people, perform, jobsat
politics -> jobsat
people -> jobsat
perform -> jobsat

...with covarying residuals for politics, people, and perform, and therefore 20 parameters (7 paths, 5 variances, 3 covariances, 1 mean, 4 intercepts). I tried specifying a LISREL-type model with each MV serving as a perfect indicator of its corresponding LV (Fhelpful, etc.) and regressing the LVs on each other. OpenMx returns a "non-positive definite" error. I think I am specifying the model incorrectly, but cannot figure out how.

The error codes:

  $status
  $status[[1]]
  [1] -1
 
  $status[[2]]
  [1] -1
 
  $status[[3]]
  [CHARSXP: "Covariance matrix is not positive-definite."]

Output also claims only 13 parameters are estimated rather than 20.

Many thanks,
Kris

require(OpenMx)
multmedData <- read.table("http://www.kspot.org/multmed.dat", header = TRUE)
manifests <- names(multmedData)
latents <- c("Fhelp","Fpol","Fpeo","Fper","Fjob")
multmedModel <- mxModel("Multiple Mediator Model",
    type="RAM",
    mxData(multmedData, type="raw"),
    manifestVars = manifests,
    latentVars = latents,
 
    # residual variances
    mxPath(from=c("helpful","politics","people","perform","jobsat"),
        arrows=2,
        free=c(FALSE,FALSE,FALSE,FALSE,FALSE),
        values=c(0,0,0,0,0),
        labels=as.character(c(NA,NA,NA,NA,NA))
    ),
 
    # latent variances and covariances
    mxPath(from=c("Fhelp","Fpol","Fpeo","Fper","Fjob"),
        arrows=2,
        free=c(TRUE,FALSE,FALSE,FALSE,FALSE,
               FALSE,TRUE,TRUE,TRUE,FALSE,
               FALSE,TRUE,TRUE,TRUE,FALSE,
               FALSE,TRUE,TRUE,TRUE,FALSE,
               FALSE,FALSE,FALSE,FALSE,TRUE),
        values=c(1,0,0,0,0,
                 0,1,1,1,0,
                 0,1,1,1,0,
                 0,1,1,1,0,
                 0,0,0,0,1),
        labels=as.character(c("var11",NA,NA,NA,NA,
                 NA,"var22","cov32","cov42",NA,
                 NA,"cov32","var33","cov43",NA,
                 NA,"cov42","cov43","var44",NA,
                 NA,NA,NA,NA,"var55"))
    ),
 
    # factor loadings
    mxPath(from=c("Fhelp","Fpol","Fpeo","Fper","Fjob"),
        to=c("helpful","politics","people","perform","jobsat"),
        arrows=1,
        free=c(FALSE,FALSE,FALSE,FALSE,FALSE),
        values=c(1,1,1,1,1),
        labels=as.character(c(NA,NA,NA,NA,NA))
    ),
 
    # structural path coefficients
    mxPath(from=c("Fhelp","Fhelp","Fhelp","Fhelp","Fpol","Fpeo","Fper"),
         to=c("Fpol","Fpeo","Fper","Fjob","Fjob","Fjob","Fjob"),
         arrows=1,
         free=c(TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE),
         values=c(1,1,1,1,1,1,1),
         labels=as.character(c("a1","a2","a3","cp","b1","b2","b3"))
    ),
 
    # means and intercepts
    mxPath(from="one",
        to=c("helpful","politics","people","perform","jobsat","Fhelp","Fpol","Fpeo","Fper","Fjob"),
        arrows=1,
        free=c(FALSE,FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE),
        values=c(0,0,0,0,0,1,1,1,1,1),
        labels=c("nu1","nu2","nu3","nu4","nu5","mean1","mean2","mean3","mean4","mean5")
    )
)
multmedFit <- mxRun(multmedModel)
multmedFit@output
summary(multmedFit)

Any suggestions?

Many thanks,
Kris

mspiegel's picture
Offline
Joined: 07/31/2009
It looks like when specifying

It looks like when specifying the paths under the line "# latent variances and covariances", you are expecting to specify 25 paths. Use the parameter all = TRUE to specify 5 x 5 paths. The default value for the 'all' parameter is FALSE, which makes 5 paths given 5 entries in the 'from' argument. Only if 'all' equals TRUE, then all sources are connected to all sinks.

kpreacher's picture
Offline
Joined: 08/23/2009
Thanks! This gets me the

Thanks! This gets me the proper number of parameters, but still bad output:

  $status
  $status[[1]]
  [1] -1
 
  $status[[2]]
  [1] -1
 
  $status[[3]]
  [CHARSXP: "Covariance matrix is not positive-definite."]

and now:

  Error in solve.default(model@output$hessian) : 
    Lapack routine dgesv: system is exactly singular

or:

  Error in solve.default(model@output$hessian) : 
    system is computationally singular: reciprocal condition number = 0

the only other modification I made to the code above was to add "labels=as.character()" to the final mxPath statement, but that isn't the source of this problem.

tbates's picture
Offline
Joined: 07/31/2009
might help to debug this by

might help to debug this by laying out the code into smaller chunks
just dashed this off, but i think it reflects the tasks you want

require(OpenMx) 
multmedData = read.table("http://www.kspot.org/multmed.dat",header = TRUE) 
manifests   = names(multmedData) 
latents     = c("Fhelp","Fpol","Fpeo","Fper","Fjob") 
 
multmedModel <- mxModel("Multiple Mediator Model", type="RAM", 
	mxData(multmedData, type="raw"), 
	manifestVars =manifests, 
	latentVars = latents, 
 
	# Residual variances
	# Fix variance of measured vars to 0
	mxPath(from=c("helpful","politics","people","perform","jobsat"), arrows=2, free=FALSE, values=0),
	# Latent variances
	mxPath(from=latents, arrows=2, free=TRUE, values=1),
	# Latent covariances
	mxPath(from=latents, arrows=2, free=TRUE, values=1, All=TRUE),
	# Factor loadings
	mxPath(from=latents, to=c("helpful","politics","people","perform","jobsat"), arrows=1, free=FALSE, values=1),
 
	# Structural path coefficients
	# helpful -> politics, people, perform, jobsat
	mxPath(from="Fhelp", to=c("Fpol","Fpeo","Fper","Fjob"), arrows=1, free=TRUE, values=1, labels=as.character(c("a1","a2","a3","cp")), # means and intercepts 
	# politics -> jobsat; people -> jobsat; perform -> jobsat
	mxPath(from=c("Fpol","Fpeo","Fper"), to=c("Fjob","Fjob","Fjob"), arrows=1, free=TRUE, values=1, labels=as.character(c("b1","b2","b3")), # means and intercepts 
 
	# Set means
	mxPath(from="one", to=c("helpful","politics","people","perform","jobsat"),arrows=1, free=FALSE,values=0, labels=c("nu1","nu2","nu3","nu4","nu5") ),
	mxPath(from="one", to=c("Fhelp","Fpol","Fpeo","Fper","Fjob"),             arrows=1, free=TRUE, values=1, labels=c("mean1","mean2","mean3","mean4","mean5") )
) 
multmedFit <- mxRun(multmedModel) multmedFit@output summary(multmedFit)

kpreacher's picture
Offline
Joined: 08/23/2009
Thanks Tim. I made the code

Thanks Tim. I made the code as bare-bones as possible, ran it, and still I do not receive the expected output. Does it matter that the model is just-identified?

require(OpenMx)
multmedData = read.table("http://www.kspot.org/multmed.dat",header = TRUE)
manifests = names(multmedData)
latents = c("Fhelp","Fpol","Fpeo","Fper","Fjob")
multmedModel <- mxModel("Multiple Mediator Model", type="RAM",
mxData(multmedData, type="raw"),
manifestVars = manifests,
latentVars = latents,
mxPath(from=c("helpful","politics","people","perform","jobsat"), arrows=2, free=FALSE, values=0),
mxPath(from=c("Fhelp","Fpol","Fpeo","Fper","Fjob"), arrows=2, free=TRUE, values=1),
mxPath(from=c("Fpol","Fpol","Fpeo"), to=c("Fpeo","Fper","Fper"), arrows=2, free=TRUE, values=1),
mxPath(from=latents, to=c("helpful","politics","people","perform","jobsat"), arrows=1, free=FALSE, values=1),
mxPath(from="Fhelp", to=c("Fpol","Fpeo","Fper","Fjob"), arrows=1, free=TRUE, values=1, labels=as.character(c("a1","a2","a3","cp"))),
mxPath(from=c("Fpol","Fpeo","Fper"), to=c("Fjob","Fjob","Fjob"), arrows=1, free=TRUE, values=1, labels=as.character(c("b1","b2","b3"))),
mxPath(from="one", to=c("helpful","politics","people","perform","jobsat"), arrows=1, free=FALSE, values=0, labels=as.character(c("nu1","nu2","nu3","nu4","nu5"))),
mxPath(from="one", to=c("Fhelp","Fpol","Fpeo","Fper","Fjob"), arrows=1, free=TRUE, values=1, labels=as.character(c("mean1","mean2","mean3","mean4","mean5"))))
 
multmedFit <- mxRun(multmedModel)
multmedFit@output
summary(multmedFit)

(sorry, my code runneth over)

Kris

Ryne's picture
Offline
Joined: 07/31/2009
It could be your starting

It could be your starting values. You've built a set of starting values of all 1s, which should build an expected covariance that is exactly singular. At the first iteration, OpenMx can't invert the expected covariance matrix, and crashes.

Try changing your starting values (say, by making all of the covariances and free regressions .5) and see if it runs.

kpreacher's picture
Offline
Joined: 08/23/2009
That did the trick! Thanks

That did the trick! Thanks Ryne.

klang's picture
Offline
Joined: 08/23/2009
Hi All, I am wondering if it

Hi All,
I am wondering if it is possible to place constraints on lambda loadings (i.e., constraining the loadings of a two indicator construct to be equal, or constraining the average of a construct's loadings to equal 1 to set the scale by the effects coding method). I've been working primarily with the path specification approach, and I can't see an obvious way that this could be implemented, nor can I find any mention or suggestions in the documentation. Would this be something more easily achieved under the matrix specification approach? Any insight would be greatly appreciated.

Steve's picture
Offline
Joined: 07/30/2009
Constraining free parameters

Constraining free parameters to be equal to one another is easy: just set their labels to be the same. For instance, starting with the script on the front page of the website, we could constrain two of the loadings to be the same by giving them both the label "lambda1".

require(OpenMx)
data(demoOneFactor)
manifests <- names(demoOneFactor)
latents <- c("G")
factorModel <- mxModel("One Factor", type="RAM",
      manifestVars = manifests,
      latentVars = latents,
      mxPath(from=latents, to=manifests, labels=c("L1", "L1", "L3", "L4", "L5")),
      mxPath(from=manifests, arrows=2),
      mxPath(from=latents, arrows=2,
            free=F, values=1.0),
      mxData(cov(demoOneFactor), type="cov",
            numObs=500))
summary(mxRun(factorModel))

Note that the vector of labels needs have the same number of elements as the number of paths (or be a single element in order to constrain all paths to be equal to one another).

One can create the kind of sum constraints you want by using the mxConstraint() function. This is a little more involved since you need to create an algebraic expression using mxAlgebra and a 1x1 constant matrix to hold your constant.

I won't write that example in this Forum just yet because we expect the syntax for this to be drastically simplified within the next week or so. Right now you would need to construct a matrix for each parameter, add all of those parameters together in an algebra, and then construct another 1x1 matrix with the number 5 in it and then use mxConstraint to enforce the equality constraint between the number 5 and the sum of the loadings.