# umxCP with two latent variables that loads in only part of the indicators

This is the first time I am playing with real data, and since I understand lavaans syntax better than openMx's I decided to start with umx.

I am trying to specify a CP model with two latents, but my measured indicators represents parenting style and personality (big5), 10 variables in total. See fig 1. I think they are better conceptualized as two latents that can correlate, but only loads in part of the variables, the five personality traits and the five parenting styles.

Initially I thought that I could either use umx_make_Twins or remove the unwanted paths with umxModify( update = ). However, it seems that with umxModify I can only remove the paths, but I cant add the correlation between latents. I ended up with fig 2.

- What should be the best approach to allow the two latents in fig 2 to correlate?

Below is a minimal working example to facilitate discussion:

dt <- ZA6701_en_add_scales_wid1_v4.0.0 %>%

left_join(ZA6701_en_master_v4.0.0, by = "pid") %>%

transmute(zygosity = zyg0102,

parcontt1 = as.numeric(parcontt),

parcontt2 = as.numeric(parcontt),

parincot1 = as.numeric(parincot),

parincot2 = as.numeric(parincot),

parmonit1 = as.numeric(parmonit),

parmonit2 = as.numeric(parmonit),

parnegct1 = as.numeric(parnegct),

parnegct2 = as.numeric(parnegct),

parwarmt1 = as.numeric(parwarmt),

parwarmt2 = as.numeric(parwarmt),

peragre1 = as.numeric(peragre),

peragre2 = as.numeric(peragre),

percons1 = as.numeric(percons),

percons2 = as.numeric(percons),

perneur1 = as.numeric(perneur),

perneur2 = as.numeric(perneur),

perextr1 = as.numeric(perextr),

perextr2 = as.numeric(perextr),

peropen1 = as.numeric(peropen),

peropen2 = as.numeric(peropen))

selDVs <- c("parcontt","parincot", "parmonit", "parnegct", "parwarmt",

"peragre", "percons", "perneur", "perextr","peropen")

vupdate <- c("cp_loadings_r6c1", "cp_loadings_r7c1", "cp_loadings_r8c1",

"cp_loadings_r9c1", "cp_loadings_r10c1", "cp_loadings_r1c2",

"cp_loadings_r2c2", "cp_loadings_r3c2", "cp_loadings_r4c2",

"cp_loadings_r5c2")

m2 <- umxCP(data = dt,

mzData = "1: monozygotic",

dzData = "2: dizygotic",

selDVs = selDVs,

sep = "",

nFac = 2)

umx

m3 <- umxModify(m2, update = vupdate, comparison = F)

plot(m3)

parameters(m2)

Thanks,

Luis

## tidyverse is broken

I can't test because tidyverse doesn't exist for my version of R (4.0.3 which has been out ~2 months). But I can tell you how to do it. umxCP sets up OpenMx models with matrices. Most of these are in the 'top' model within the model that umxCP returns.

For example, the a paths are estimated in matrix a_cp, which we can see an example of by running the example from the ?umxCP help documentation.

$a_cp

DiagMatrix 'a_cp'

$labels

[,1] [,2] [,3]

[1,] "a_cp_r1c1" NA NA

[2,] NA "a_cp_r2c2" NA

[3,] NA NA "a_cp_r3c3"

$values

[,1] [,2] [,3]

[1,] 0.3191584 0.0000000 0.0000000

[2,] 0.0000000 0.5930313 0.0000000

[3,] 0.0000000 0.0000000 0.6918959

$free

[,1] [,2] [,3]

[1,] TRUE FALSE FALSE

[2,] FALSE TRUE FALSE

[3,] FALSE FALSE TRUE

`$lbound`

[,1] [,2] [,3]

[1,] 0 NA NA

[2,] NA 0 NA

[3,] NA NA 0

If you wish to allow the factors to correlate, you could use the Cholesky approach, which simply means freeing up the elements in the lower triangle of the a_cp, c_cp and e_cp matrices. If you only have 2 factors, this is easy because there's only one element in the lower triangle, so you could do something like this as Step 1:

model$top$a_cp$free[2,1] <- TRUE

model$top$c_cp$free[2,1] <- TRUE

model$top$e_cp$free[2,1] <- TRUE

Step 2 is to change the factor loading matrix, which is (cryptically) in matrix cp_loadings:

$cp_loadings

FullMatrix 'cp_loadings'

$labels

[,1] [,2] [,3]

[1,] "cp_loadings_r1c1" "cp_loadings_r1c2" "cp_loadings_r1c3"

[2,] "cp_loadings_r2c1" "cp_loadings_r2c2" "cp_loadings_r2c3"

[3,] "cp_loadings_r3c1" "cp_loadings_r3c2" "cp_loadings_r3c3"

[4,] "cp_loadings_r4c1" "cp_loadings_r4c2" "cp_loadings_r4c3"

[5,] "cp_loadings_r5c1" "cp_loadings_r5c2" "cp_loadings_r5c3"

[6,] "cp_loadings_r6c1" "cp_loadings_r6c2" "cp_loadings_r6c3"

$values

[,1] [,2] [,3]

[1,] 0.234958126 0.7924620 3.0297019

[2,] 0.049709341 -0.2315207 1.5511085

[3,] -0.009447686 0.7429272 0.5365263

[4,] 3.435387889 2.2862029 1.6776101

[5,] 1.923986619 2.6755898 2.2131049

[6,] -0.701359035 -1.4013078 -1.6685230

`$free`

[,1] [,2] [,3]

[1,] TRUE TRUE TRUE

[2,] TRUE TRUE TRUE

[3,] TRUE TRUE TRUE

[4,] TRUE TRUE TRUE

[5,] TRUE TRUE TRUE

[6,] TRUE TRUE TRUE

You can fix values to zero with a umx function, or with base OpenMx it might be done with omxSetParameters():

omxSetParameters(model$top, labels=c("cp_loadings_r4c1","cp_loadings_r5c1","cp_loadings_r6c1"), values=0, free=FALSE)

There are various tricks for using wildcards for labels that umx has that could be handy way to find all the factor loadings in a column without having to list them all out.

Step 3 is to run the model again once it has been modified.

Log in or register to post comments

## Thanks Mike,

Seems easy enough, however I am stuck in Step 1, as umx models seems not to allow direct modifications. So with:

m2$submodels$top$e_cp$free[2,1] <- TRUE

I get:

You cannot directly set the matrices of a model. To set objects in the model, use the mxModel() function.

I tried mxModel() with something like:

mxModel(m2$submodels$top, name = "a_cp", free = T)

But this is the wrong syntax.

- How do I do this using mxModel?

best

Log in or register to post comments

In reply to Thanks Mike, by lf-araujo

## umx generates OpenMx models

Second, sometimes direct tweaking of matrices isn't allowed (and I'm not sure what conditions affect this). Possibly, omitting the $submodels bit would solve the issue.

You can always replace the entire matrix by extracting it to an object first, modify that object, then put the matrix back into the model again. Sometimes it may be necessary to use mxModel(), with syntax of the form:

revisedModel <- mxModel(oldMxModel, matrixToBeReplaced)

where matrixToBeReplaced has the same name as the one it is replacing.

HTH

Log in or register to post comments

## This error occurs when

Log in or register to post comments

In reply to This error occurs when by Leo

## Thanks Leo,

This happens if I just try to change the content of the R object within the model like:

m2 <- umxCP(data = dt,

mzData = "1: monozygotic",

dzData = "2: dizygotic",

selDVs = selDVs,

sep = "",

nFac = 2)

`m2$submodels$top$matrices$e_cp$free[2,1] <- TRUE`

The same error happens. I am not sure if umx models are in any way different from the openMx ones. But I checked the structure and the above line was supposed to work. You mentioned a model with correlated factors, and I found an undocumented option in umx "correlatedA = T" that does what I wanted in terms of correlation (I think); the rest of Mike's instructions gets me where I wanted with this model.

Many thanks.

Log in or register to post comments

## umxCP, correlated causes

The install_github(tbates/umx") version now deprecates `correlatedA` in favour of `correlatedACE` which is more accurately named, and defaults to leaving the lower triangle fixed at zero, allowing you to free up the (few) paths you want.

To create a 2-factor CP model, just set `nFac=2`

To restrict what manifests each CP loads on, in the resultant model, delete the paths from CP1 to the set 2 manifests, and from CP2 to the set 1 manifests using labels.

Paths from cp1 are in column 1 of the `cp_loadings` matrix. and labeled as "cp_loadings_r1c1"

You can match the relevant pattern with regular expressions, or if you like more concrete or fool proof approach, make a list and drop that... e.g.:

```R

tmp = umxCP(your setup here..., correlatedACE=TRUE, auto=FALSE)

pathsToDrop = c( "cp_loadings_r5c1", "cp_loadings_r6c1", ..., "cp_loadings_r1c2", ...)

m2 = umxModify(tmp, pathsToDrop, name = "style_and_personality")

```

you would then need to free the covariance of the a paths if you think that makes sense.

Log in or register to post comments

In reply to umxCP, correlated causes by tbates

## problems with correlatedACE

I created a 2-factor CP model with

`correlatedA = TRUE`

a couple of weeks ago and it went well.`m1 = umxCP("2cp", selDVs = selDVs, sep = "_T", dzData = dzData, mzData = mzData,`

nFac = 2, correlatedA = TRUE, tryHard = "yes")

Now, I reran the model and received the polite note of changing

`correlatedA`

to`correlatedACE`

, as you just mentioned in your post. Unfortunately, in my case, using`correlatedACE`

does not result in a model with correlated A,C, and E paths. The corresponding paths (a_cp_r2c1/c_cp_r2c1/e_cp_r2c1) do neither show up in the list of parameters nor are they plotted in the model. Do you have any idea to solve this problem?Thank you in advance and best wishes,

Ida

Log in or register to post comments

## drop matrices word?

I don't usually have trouble changing objects within OpenMx models. One difference I notice is that you use:

m2$submodels$top$matrices$e_cp$free[2,1] <- TRUE

whereas I would use something like

m2$top$e_cp$free[2,1] <- TRUE

that is, refer to a matrix with model$matrix without either $submodels or $matrices in the string. I'm not sure that this is your issue though. Another option is to replace the whole matrix

e_cp <- m2$submodels$top$matrices$e_cp

e_cp$free[2,1]<-TRUE

m2$top <-mxModel(m2$top,tempMat)

although clumsier, the pass through mxModel has validation checks that can prevent runtime errors. HTH!

Log in or register to post comments