Cholesky paths with umxPath
This page will introduce writing Cholesky structures using umxPath
to facilitate twin modeling with umxRAM
.
It is not finished, and for now (and perhaps for sometime), I’d recommend you read this page instead on the awesome umxACE function
# ====================
# = Cholesky example =
# ====================
latents = paste0("A", 1:5)
manifests = names(demoOneFactor)
myData = mxData(cov(demoOneFactor), type = "cov", numObs = 500)
m1 = umxRAM("Chol", data = myData,
umxPath(Cholesky = latents, to = manifests),
umxPath(var = manifests),
umxPath(var = latents, fixedAt = 1.0)
)
We can see that this fits “perfectly” - it’s a saturated solution, with some caveats (see umx::umxACEv
to learn more about these):
umxSummary(m1)
What about a 1-factor solution?
A 1 factor Cholesky is just a general factor, but let’s use it as an example:
manifests = names(demoOneFactor)
m2 = umxRAM("Chol", data = demoOneFactor, type = "cov",
umxPath(Cholesky = "A1", to = manifests),
umxPath(var = manifests),
umxPath(var = "A1", fixedAt = 1)
)
plot(m2)
We could also drop the paths from m1:
m3 = umxModify(m1, regex = "^A[2-5]")
tip: use parameters(m1, pattern = "^A[2-5]")
to see what paths this expression matches and drops.
Is a one-factor model significantly worse than the extravagant saturated five Cholesky-factor solution?
umxCompare(m1, m2)
Model | EP | Δ -2LL | Δ df | p | AIC | Δ AIC | Compare with Model |
---|---|---|---|---|---|---|---|
Chol | 20 | 9.994993 | 0 | ||||
Chol | 10 | 7.3987999 | 10 | 0.687 | -2.606207 | -12.6012001 | Chol |
No: fit is not-significantly worse.
A multi-group twin model
Twin models have models for each class of twins – MZ DZ, perhaps differentiated by sex – and these differ in the genetic paths they set.
umx includes built-in twin models, including umxACE
. Here, we’ll build a twin model completely by hand in umx
from scratch.
NOTE: umx
now includes umxTwinMaker
which makes specifying novel multivariate twin models MUCH more straight-foward.
First let’s build an ace model from scratch:
data(twinData)
tmpTwin = twinData
names(tmpTwin)
# "fam", "age", "zyg", "part", "wt1", "wt2", "ht1", "ht2", "htwt1", "htwt2", "bmi1", "bmi2"
# Set zygosity to a factor
labList = c("MZFF", "MZMM", "DZFF", "DZMM", "DZOS")
tmpTwin$zyg = factor(tmpTwin$zyg, levels = 1:5, labels = labList)
# Pick the variables
selDVs = c("bmi1", "bmi2") # nb: Can also give base name, (i.e., "bmi") AND set suffix.
# the function will then make the varnames for each twin using this:
# for example. "VarSuffix1" "VarSuffix2"
mzData = tmpTwin[tmpTwin$zyg %in% "MZFF", selDVs]
dzData = tmpTwin[tmpTwin$zyg %in% "DZFF", selDVs]
latentA = paste0(c("A1"), "_T", 1:2)
latentC = paste0(c("C1"), "_T", 1:2)
latentE = paste0(c("E1"), "_T", 1:2)
latents = c(latentA, latentC, latentE)
mz = umxRAM("mz", data = mxData(mzData, type = "raw"),
umxPath(v1m0 = latents),
umxPath(v.m. = selDVs),
# twin 1
umxPath(Cholesky = "A1_T1", to = "bmi1"),
umxPath(Cholesky = "C1_T1", to = "bmi1"),
umxPath(Cholesky = "E1_T1", to = "bmi1"),
# twin 2
umxPath(Cholesky = "A1_T2", to = "bmi2"),
umxPath(Cholesky = "C1_T2", to = "bmi2"),
umxPath(Cholesky = "E1_T2", to = "bmi2"),
# A C E links
umxPath("A1_T1", with = "A1_T2", fixedAt = 1),
umxPath("C1_T1", with = "C1_T2", fixedAt = 1),
umxPath("E1_T1", with = "E1_T2", fixedAt = 0)
)
dz = mxModel(mz, name= "dz",
mxData(dzData, type = "raw"),
umxPath("A1_T1", with = "A1_T2", fixedAt = .5)
)
m1 = mxModel(mz, dz, mxFitFunctionMultigroup(c("mz", "dz")))
parameters(mz)
plot(dz, fixed= TRUE)
umxTwinMaker
Now let’s do that in umxTwinMaker
. Here we only have to draw the model for one person.
First let’s assemble some data
data(twinData)
tmp = umx_make_twin_data_nice(data=twinData, sep="", zygosity="zygosity", numbering=1:2)
tmp = umx_scale_wide_twin_data(varsToScale= c("wt", "ht"), sep= "_T", data= tmp)
mzData = subset(tmp, zygosity %in% c("MZFF", "MZMM"))
dzData = subset(tmp, zygosity %in% c("DZFF", "DZMM"))
Now, I’ll make a bivariate ACE twin model.
1. Define paths for one person:
latents = paste0(rep(c("a", "c", "e"), each = 2), 1:2)
paths = c(
umxPath(v1m0 = latents),
umxPath(mean = c("wt", "ht")),
umxPath(fromEach = c("a1", 'c1', "e1"), to = c("ht", "wt")),
umxPath(c("a2", 'c2', "e2"), to = "wt")
)
2. Make a twin model based on the paths for one person
m1 = umxTwinMaker("myACE", paths, mzData = mzData, dzData= dzData)
plot(m1, std= TRUE, means= FALSE)
Here’s the same thing using umxACE
m2 = umxACE(selDVs= c("wt", "ht"), mzData = mzData, dzData=dzData, sep="_T")
plot(m2)