Learn R Programming

umx (version 4.20.0)

umxRAM: Build and run path-based SEM models

Description

umxRAM expedites creation of structural equation models, still without doing invisible things to the model. It supports umxPath(). To support cross-language sharing and science learning, umxRAM also supports lavaan model strings.

Here's a path example that models miles per gallon (mpg) as a function of weight (wt) and engine displacement (disp) using the widely used mtcars data set.

m1 = umxRAM("tim", data = mtcars,
	umxPath(c("wt", "disp"), to = "mpg"),
	umxPath("wt", with = "disp"),
	umxPath(v.m. = c("wt", "disp", "mpg"))
)

As you can see, most of the work is done by umxPath(). umxRAM wraps these paths up, takes the data = input, and then internally sets up all the labels and start values for the model, runs it, and calls umxSummary(), and plot.MxModel().

Try it, or one of the several models in the examples at the bottom of this page.

A common error is to include data in the main list, a bit like saying lm(y ~ x + df) instead of lm(y ~ x, data = df).

nb: Because it uses the presence of a variable in the data to detect if a variable is latent or not, umxRAM needs data at build time.

String Syntax

Here is an example using lavaan syntax (for more, see umxLav2RAM())

m1 = umxRAM("mpg ~ wt + disp", data = mtcars)

Sketch mode

If you are at the "sketching" stage of theory consideration, umxRAM supports setting data to a simple vector of manifest names. As usual in umxRAM, any variables you refer to that are not in data are treated as latents.

m1 = umxRAM("sketch", data = c("A", "B"),
	umxPath("C", to = c("A", "B"), values=.3),
	umxPath("A", with = "B", values=.45),
	umxPath(v.m. = c("A", "B")),
	umxPath(v1m0 = "C")
)
plot(m1, means = FALSE)

Will create this figure:

Figure: sketch.png

Usage

umxRAM(
  model = NA,
  ...,
  data = NULL,
  name = NA,
  group = NULL,
  group.equal = NULL,
  suffix = "",
  comparison = TRUE,
  type = c("Auto", "FIML", "cov", "cor", "WLS", "DWLS", "ULS"),
  weight = NULL,
  allContinuousMethod = c("cumulants", "marginals"),
  autoRun = getOption("umx_auto_run"),
  tryHard = c("no", "yes", "ordinal", "search"),
  std = FALSE,
  refModels = NULL,
  remove_unused_manifests = TRUE,
  independent = NA,
  setValues = TRUE,
  optimizer = NULL,
  verbose = FALSE,
  std.lv = FALSE,
  lavaanMode = c("sem", "lavaan"),
  printTab = FALSE
)

Value

  • mxModel()

Arguments

model

A model to update (or set to string to use as name for new model)

...

umxPaths, mxThreshold objects, etc.

data

data for the model. Can be an mxData() or a data.frame

name

A friendly name for the model

group

(optional) Column name to use for a multi-group model (default = NULL)

group.equal

In multi-group models, what to equate across groups (default = NULL: all free)

suffix

String to append to each label (useful if model will be used in a multi-group model)

comparison

Compare the new model to the old (if updating an existing model: default = TRUE)

type

One of "Auto", "FIML", "cov", "cor", "WLS", "DWLS", "ULS"

weight

Passes weight values to mxData

allContinuousMethod

"cumulants" or "marginals". Used in all-continuous WLS data to determine if a means model needed.

autoRun

Whether to run the model (default), or just to create it and return without running.

tryHard

Default ('no') uses normal mxRun. "yes" uses mxTryHard. Other options: "ordinal", "search"

std

Whether to show standardized estimates, raw (NULL print fit only)

refModels

pass in reference models if available. Use FALSE to suppress computing these if not provided.

remove_unused_manifests

Whether to remove variables in the data to which no path makes reference (defaults to TRUE)

independent

Whether the model is independent (default = NA)

setValues

Whether to generate likely good start values (Defaults to TRUE)

optimizer

optionally set the optimizer (default NULL does nothing)

verbose

Whether to tell the user what latents and manifests were created etc. (Default = FALSE)

std.lv

Whether to auto standardize latent variables when using string syntax (default = FALSE)

lavaanMode

Defaults when building out string syntax default = "sem" (alternative is "lavaan", with very few defaults)

printTab

(for string input, whether to output a table of paths (FALSE)

Details

Comparison for OpenMx users

umxRAM differs from OpenMx::mxModel() in the following ways:

  1. You don't need to set type = "RAM".

  2. You don't need to list manifestVars (they are detected from path usage).

  3. You don't need to list latentVars (detected as anything in paths but not in mxData).

  4. You don't need to create mxData when you already have a data.frame.

  5. You add data with data = (as elsewhere in R, e.g. lm()).

  6. You don't need to add labels: paths are automatically labelled "a_to_b" etc.

  7. You don't need to set start values, they will be done for you.

  8. You don't need to mxRun the model: it will run automatically, and print a summary.

  9. You don't need to run summary: with autoRun=TRUE, it will print a summary.

  10. You get a plot of the model with estimates on the paths, including multiple groups.

  11. Less typing: umxPath() offers powerful verbs to describe paths.

  12. Supports a subset of lavaan string input.

Start values. Currently, manifest variable means are set to the observed means, residual variances are set to 80% of the observed variance of each variable, and single-headed paths are set to a positive starting value (currently .9). note: The start-value strategy is subject to improvement, and will be documented in the help for umxRAM().

Comparison with other software

Some SEM software does a lot of behind-the-scenes defaulting and path addition. If you want this, I'd say use umxRAM with lavaan string input.

References

See Also

umxPath(), umxSummary(), plot(), parameters(), umxSuperModel(), umxLav2RAM()

Other Core Model Building Functions: umxMatrix(), umxModify(), umxPath(), umxSuperModel(), umx

Examples

Run this code
if (FALSE) {

# ============================================
# = 1. Here's a simple example with raw data =
# ============================================
mtcars$litres = mtcars$disp/61.02
m1 = umxRAM("tim", data = mtcars,
	umxPath(c("wt", "litres"), to = "mpg"),
	umxPath("wt", with = "litres"),
	umxPath(v.m. = c("wt", "litres", "mpg"))
)

# 2. Use parameters to see the parameter estimates and labels
parameters(m1)

# And umxSummary to get standardized parameters, CIs etc from the run model.
umxSummary(m1, std=TRUE)
# |name           | Std.Estimate| Std.SE|CI                   |
# |:--------------|------------:|------:|:--------------------|
# |wt_to_mpg      |        -0.54|   0.17|-0.54 [-0.89, -0.2]  |
# |disp_to_mpg    |        -0.36|   0.18|-0.36 [-0.71, -0.02] |
# |mpg_with_mpg   |         0.22|   0.07|0.22 [0.08, 0.35]    |
# |wt_with_wt     |         1.00|   0.00|1 [1, 1]             |
# |b1             |         0.89|   0.04|0.89 [0.81, 0.96]    |
# |disp_with_disp |         1.00|   0.00|1 [1, 1]             |

# 3. Of course you can plot the model
plot(m1)
plot(m1, std=TRUE, means=FALSE)
plot(m1, std = TRUE, means=FALSE, strip= TRUE, resid = "line")

# ===============================================
# = lavaan string example (more at ?umxLav2RAM) =
# ===============================================
m1 = umxRAM(data = mtcars, "#modelName
 mpg ~ wt + disp")


# =======================
# = A multi-group model =
# =======================

mtcars$litres = mtcars$disp/61.02
m1 = umxRAM("tim", data = mtcars, group = "am",
	umxPath(c("wt", "litres"), to = "mpg"),
	umxPath("wt", with = "litres"),
	umxPath(v.m. = c("wt", "litres", "mpg"))
)
# In this model, all parameters are free across the two groups.

# ====================================
# = A cov model, with steps laid out =
# ====================================

# *note*: The variance of displacement is in cubic inches and is very large.
# to help the optimizer, one might, say, multiply disp *.016 to work in litres
tmp = mtcars; tmp$disp= tmp$disp *.016

# We can just give the raw data and ask for it to be made into type cov:
m1 = umxRAM("tim", data = tmp, type="cov",
	umxPath(c("wt", "disp"), to = "mpg"),
	umxPath("wt", with = "disp"),
	umxPath(var = c("mpg", "wt", "disp"))
)

# (see ?umxPath for more nifty options making paths...)

# =========================================
# = umxRAM can also accept mxData as data =
# =========================================
# For convenience, list up the manifests you will be using

selVars = c("mpg", "wt", "disp")
tmp = mtcars; tmp$disp= tmp$disp *.016
myCov = mxData(cov(tmp[, selVars]), type = "cov", numObs = nrow(mtcars) )

m1 = umxRAM("tim", data = myCov,
	umxPath(c("wt", "disp"), to = "mpg"),
	umxPath("wt", with = "disp"),
	umxPath(var = selVars)
)


# =======================
# = umxRAM supports WLS =
# =======================

# 1. Run an all-continuous WLS model
 mw = umxRAM("raw", data = mtcars[, c("mpg", "wt", "disp")], 
	type = "WLS", allContinuousMethod = "cumulants",
 	umxPath(var = c("wt", "disp", "mpg")),
 	umxPath(c("wt", "disp"), to = "mpg"),
 	umxPath("wt", with = "disp"),
     umxPath(var = c("wt", "disp", "mpg"))
 )
# 2. Switch to marginals to support means
 mw = umxRAM("raw", data = mtcars[, c("mpg", "wt", "disp")], 
	type = "WLS", allContinuousMethod= "marginals",
 	umxPath(var = c("wt", "disp", "mpg")),
 	umxPath(c("wt", "disp"), to = "mpg"),
 	umxPath("wt", with = "disp"),
     umxPath(var = c("wt", "disp", "mpg"))
 )


# ===============================
# = Using umxRAM in Sketch mode =
# ===============================
# No data needed: just list variable names!
# Resulting model will be plotted automatically
m1 = umxRAM("what does unique pairs do, I wonder", data = c("A", "B", "C"),
   umxPath(unique.pairs = c("A", "B", "C"))
)

m1 = umxRAM("ring around the rosey", data = c("B", "C"),
  umxPath(fromEach = c("A", "B", "C"))
)

m1 = umxRAM("fromEach with to", data = c("B", "C"),
   umxPath(fromEach = c("B", "C"), to= "D")
)

m1 = umxRAM("CFA_sketch", data = paste0("x", 1:4),
	umxPath("g", to = paste0("x", 1:4)),
	umxPath(var = paste0("x", 1:4)),
	umxPath(v1m0 = "g")
)

# =================================================
# = This is an example of using your own labels:  =
#   umxRAM will not over-ride them                =
# =================================================
m1 = umxRAM("tim", data = mtcars, type="cov",
	umxPath(c("wt", "disp"), to = "mpg"),
	umxPath(cov = c("wt", "disp"), labels = "b1"),
	umxPath(var = c("wt", "disp", "mpg"))
)
omxCheckEquals(m1$S$labels["disp", "wt"], "b1") # label preserved
m1$S$labels
#      mpg             wt            disp
# mpg  "mpg_with_mpg"  "mpg_with_wt" "disp_with_mpg"
# wt   "mpg_with_wt"   "wt_with_wt"  "b1"
# disp "disp_with_mpg" "b1"          "disp_with_disp"
parameters(m1)

# ===========
# = Weights =
# ===========
# !!! Not tested !!!
mtcars$litres = mtcars$disp/61.02
m1 = umxRAM("tim", data = mtcars, weight= "cyl",
	umxPath(c("wt", "litres"), to = "mpg"),
	umxPath("wt", with = "litres"),
	umxPath(v.m. = c("wt", "litres", "mpg"))
)

}

Run the code above in your browser using DataLab