# Confirmatory Factor Analysis Using OpenMx

To use 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)

This 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. The present task is to focus on the measurement model for intelligence only; the television variables will be set aside for now.

Before calling the OpenMx function to estimate the confirmatory factor 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<-c("reading","writing","math","analytic") > latents<-c("intelligence")

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

> cfa<-mxModel("Intelligence Model", type="RAM", + manifestVars=observed, + latentVars=latents, + mxPath(from=latents, to=observed, + free=c(F,T,T,T),values=c(1,1,1,1),labels=c("l1","l2","l3","l4")), + mxPath(from=observed, arrows=2,labels=c("d1","d2","d3","d4")), + mxPath(from=latents, arrows=2,labels=c("p1")), + mxData(cov(intell[,1:4]),type="cov",numObs=100) + )

The model is saved as an object named `cfa`. 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 three commands specify the paths for the model. In the first, one arrow is drawn from the latent variable to each of the observed variables. The `free` argument is used to identify the model by defining which parameters will be constrained. In this case, `free` is set equal to `F` (false) for the first loading and `T` (true) for the remaining three. The subsequent argument, `values`, sets the value of the constraint. Where `free` was set to `F`, the corrsponding number in `values` is the constraint. Where `free` is set equal to `T`, the value is understood to be the starting value for the numeric optimizer. The final argument to `mxPath` is optional and supplies labels for each of the parameters, which will facilitate reading the output. In this case, the “l” is short for lambda, and the numbers are meant to subscript the particular loading.

The next two `mxPath` functions specify the variances for the model variables. There is no `to` argument; instead there is an `arrows` argument set equal to two. This reflects a common convention in drawing path diagrams in which variances are represented with a two-headed arrow. The names “d1” through “d4” are used to label the variances for the observed variables, and the label “p1” is used to label the variance for the latent variable. Because the model is identified by constraining one factor loading, it is not necessary to constrain the variance of the latent variable (the `free` argument defaults to `T`).

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 brackets following the name of the data object subset the file to include only columns one through four (that is, `intell[,1:4]`), which correspond to the variables used in the model. 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. When a covariance matrix is analyzed, it is necessary to also specify the number of observations (`numObs`) in the sample.

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(cfa) Running Intelligence Model

View the results using the `summary` function.

> summary(results) reading writing math analytic Min. :0.8187 Min. :0.7063 Min. :0.7718 Min. :0.7063 1st Qu.:0.8190 1st Qu.:0.7554 1st Qu.:0.7918 1st Qu.:0.7754 Median :0.8309 Median :0.7952 Median :0.8205 Median :0.8088 Mean :0.8993 Mean :0.8071 Mean :0.8520 Mean :0.8182 3rd Qu.:0.9112 3rd Qu.:0.8469 3rd Qu.:0.8808 3rd Qu.:0.8516 Max. :1.1169 Max. :0.9316 Max. :0.9953 Max. :0.9491 name matrix row col Estimate Std.Error 1 l2 A writing intelligence 0.8945761 0.04914923 2 l3 A math intelligence 0.9617760 0.05006481 3 l4 A analytic intelligence 0.9127264 0.05106145 4 d1 S reading reading 0.2234038 0.03110367 5 d2 S writing writing 0.2165773 0.02805356 6 d3 S math math 0.1687708 0.02551314 7 d4 S analytic analytic 0.2047159 0.02713080 8 p1 S intelligence intelligence 0.8935367 0.11400820 Observed statistics: 10 Estimated parameters: 8 Degrees of freedom: 2 -2 log likelihood: 42.523 Saturated -2 log likelihood: 39.02569 numObs: 100 Chi-Square: 3.49731 p: 0.1740078 AIC (Mx): -0.5026897 BIC (Mx): -2.856515 adjusted BIC: RMSEA: 0.08652486 frontend elapsed time: 0.1000688 secs backend elapsed time: 0.003484011 secs

An example of a full structural equation model using OpenMx can be found on the next page.

Still have questions? Contact us!