# Structural Equation Modeling Using OpenMx

The intial steps to run a full structural equation model using OpenMx mirror those used to run a confirmatory factor analysis using OpenMx. It is necessary to have R installed on your computer and to have downloaded OpenMX.

The present tutorial relies on this running example. To use the OpenMx package, launch R and load the library.

> library(OpenMx)

The present example will rely on a raw data file saved in SPSS format. The `foreign` library is used to read in SPSS data.

> library(foreign) > intell<-read.spss("http://www.methodsconsultants.com/data/intelligence.sav", to.data.frame=TRUE)

This reads in the data from a remote server and saves the file as an object named `intell`. The `names` function can be used to preview the variable names in the file.

> names(intell) [1] "reading" "writing" "math" "analytic" "simpsons" "familyguy" "amerdad"

The first four variables represent test scores meant to tap latent intelligence. The last three variables represent reviews of three televsion shows. Before calling the OpenMx function that will estimate the structural equation model, it is helpful to collect the names of the observed variables into one vector (name it “observed”) and the names of the latent variables into another (name it “latents”).

> observed<-names(intell) > latents<-c("intelligence","humor")

The function used to specify the model is `mxModel`. The SEM is described as follows:

> sem<-mxModel("Full SEM Model", type="RAM", + manifestVars=observed, + latentVars=latents, + mxPath(from="humor", to=c("simpsons","familyguy","amerdad"), + free=c(F,T,T), values=c(1,1,1), labels=c("l1","l2","l3"), ), + mxPath(from="intelligence", to=c("reading","writing","math","analytic"), + labels=c("l4","l5","l6","l7")), + mxPath(from="intelligence", to="humor",labels="g1"), + mxPath(from=observed,arrows=2,labels=c("d1","d2","d3","d4","e1","e2","e3")), + mxPath(from=latents, arrows=2,free=c(F,T),values=c(1,1)), + mxData(cov(intell),type="cov",numObs=100) + )

The model is saved as an object named `sem`. The first argument in this example names the model. The second argument, `type="RAM"`, tells R that the user is thinking in terms of a path model (RAM stands for “reticular action model”). Alternatively, OpenMx can understand more explicit matrix programming.

The next two arguments, `manifestVars` and `latentVars`, assign the names of the observed and unobserved variables, respectively.

The subsequent five commands specify the paths for the model. In the first, one arrow is drawn from the latent variable `humor` to each of the observed variables `simpsons`, `familyguy`, and `amerdad`. In order to help identify the model, the first loading (from `Humor` to `Simpsons`) is constrained to equal one. This is done by specifying `free=c(F,T,T)`, which means that the first loading will not be left as a free parameter but the remaining two will be. The next argument, `values=c(1,1,1)`, is used to 1) specify the value of a constraint for the elements in `free` set to `F` (for `FALSE`); and 2) specify the starting values for the numeric optimizer for the elements in `free` that were set to `T` (for `TRUE`). The `labels` argument specifies a shorthand name for each parameter to facilitate reading the output.

The next call to `mxPath` specifies the paths between the latent variable `intelligence` and the observed variables `reading`, `writing`, `math`, and `analytic`. Labels are again assigned to name each path. Because all of the respective loadings are left free, no additional arguments are necessary (the `free` argument defaults to `T`). An additional call to `mxPath` specifies the arrow running from `intelligence` to `humor`.

The final two calls to `mxPath` specify the variances for the observed and latent variables. In each case, there is a `from` argument but no `to`, and the `arrows` argument is set equal to 2. This reflects a common convention in drawing path diagrams in which variances are represented with a two-headed arrow. The first of the final two `mxPath` functions specifies the variances for the observed variables, and the second specifies the variances for the latent variables. In this example, a second model identifying assumption is that the variance for `intelligence` is constrained to equal 1 using the `free` and `values` arguments, while the variance for `humor` is left free.

The final function, `mxData` specifies the data source. Although the data were read in raw from a PASW file, the `cov` function converts the variables into a covariance matrix. The `type` argument is then set to `"cov"`, for covariance. The reason for this conversion is to keep the estimation in line with LISREL and other packages that default to analyzing a covariance matrix. However, it is possible to leave the data in raw format and specify `type="raw"`. Doing so then defaults to FIML estimation, which is appropriate when there are missing observations in the data file.

To run the model, use the name of the model object as the sole argument to the function `mxRun`. Save the results into an object named `results`.

> results<-mxRun(sem) Running Full SEM Model

View the results using the `summary` function.

> summary(results) reading writing math analytic simpsons Min. :0.1884 Min. :0.1413 Min. :0.2737 Min. :0.2147 Min. :0.1413 1st Qu.:0.2237 1st Qu.:0.1681 1st Qu.:0.2847 1st Qu.:0.2367 1st Qu.:0.2210 Median :0.8187 Median :0.7063 Median :0.7718 Median :0.7063 Median :0.2777 Mean :0.6047 Mean :0.5294 Mean :0.6073 Mean :0.5659 Mean :0.3943 3rd Qu.:0.8309 3rd Qu.:0.7952 3rd Qu.:0.8205 3rd Qu.:0.8088 3rd Qu.:0.6049 Max. :1.1169 Max. :0.9316 Max. :0.9953 Max. :0.9491 Max. :0.6897 familyguy amerdad Min. :0.1826 Min. :0.1536 1st Qu.:0.2395 1st Qu.:0.2016 Median :0.2737 Median :0.2917 Mean :0.4297 Mean :0.4233 3rd Qu.:0.6098 3rd Qu.:0.6353 Max. :0.8527 Max. :0.8443 name matrix row col Estimate Std.Error 1 l4 A reading intelligence 0.9426912 0.05852687 2 l5 A writing intelligence 0.8426396 0.05440416 3 l6 A math intelligence 0.9128734 0.05377982 4 l7 A analytic intelligence 0.8636460 0.05451091 5 g1 A humor intelligence 0.2417027 0.05744189 6 l2 A familyguy humor 1.0150916 0.06320135 7 l3 A amerdad humor 1.0995753 0.05726605 8 d1 S reading reading 0.2282711 0.03119336 9 d2 S writing writing 0.2216014 0.02622611 10 d3 S math math 0.1619638 0.02504869 11 d4 S analytic analytic 0.2032078 0.02675401 12 e1 S simpsons simpsons 0.1169711 0.02202420 13 e2 S familyguy familyguy 0.2625278 0.03379653 14 e3 S amerdad amerdad 0.1518444 0.02795843 15 S humor humor 0.5143109 0.06382999 Observed statistics: 28 Estimated parameters: 15 Degrees of freedom: 13 -2 log likelihood: 50.62404 Saturated -2 log likelihood: 36.94575 numObs: 100 Chi-Square: 13.67829 p: 0.3968841 AIC (Mx): -12.32171 BIC (Mx): -23.09446 adjusted BIC: RMSEA: 0.0228421 frontend elapsed time: 0.250772 secs backend elapsed time: 0.1482589 secs

The results mirror those produced by LISREL for the same model.

Still have questions? Contact us!