mxsem provides a lavaan-like
(Rosseel, 2012) syntax to implement structural equation models (SEM)
with OpenMx (Boker et al., 2011). The objective is to
simplify fitting basic SEM with OpenMx, while also
unlocking some very useful advanced features. For instance,
mxsem allows for parameter transformations and
definition variables. However, mxsem is intentionally
incomplete in order to focus on simplicity. The main function
(mxsem()
) is similar to lavaan’s
sem()
-function in that it tries to set up parts of the
model automatically (e.g., adding variances automatically or scaling the
latent variables automatically).
Warning: The syntax and settings of mxsem may differ from lavaan in some cases. See
vignette("Syntax", package = "mxsem")
for more details on the syntax and the default arguments.
mxsem is not the first package providing a lavaan-like syntax for OpenMx. You will find similar functions in the following packages:
lavaan2RAM
function that can be
combined with the create.mxModel
function. This combination
offers more features than mxsem. For instance,
constraints of the form a < b
are supported. In
mxsem such constraints require algebras (e.g.,
!diff; a := b - exp(diff)
).umxRAM
and
umxLav2RAM
functions that can parse single
lavaan-style statements (e.g.,
eta =~ y1 + y2 + y3
) or an entire lavaan
models to OpenMx models.as_ram
function to translate
lavaan syntax to OpenMx and also
implements a unified syntax to specify both, lavaan and
OpenMx models. Additionally, it works well with the
tidyverse.lavaan.to.OpenMx
function.Because mxsem implements the syntax parser from scratch, it can extend the lavaan syntax to account for specific OpenMx features. This enables implicit transformations with curly braces.
Cite OpenMx (Boker et al., 2011) for the modeling
and lavaan for the syntax (Rosseel, 2012). To cite
mxsem, check citation("mxsem")
.
mxsem is available from CRAN:
install.packages("mxsem")
The newest version of the package can be installed from GitHub using the following commands in R:
if(!require(devtools)) install.packages("devtools")
::install_github("jhorzek/mxsem",
devtoolsref = "main")
Because mxsem uses Rcpp, you will need a compiler for C++ (e.g., by installing Rtools on Windows, Xcode on Mac and build-essential on linux).
The following example is directly adapted from lavaan:
library(mxsem)
<- '
model # latent variable definitions
ind60 =~ x1 + x2 + x3
dem60 =~ y1 + a1*y2 + b*y3 + c1*y4
dem65 =~ y5 + a2*y6 + b*y7 + c2*y8
# regressions
dem60 ~ ind60
dem65 ~ ind60 + dem60
# residual correlations
y1 ~~ y5
y2 ~~ y4 + y6
y3 ~~ y7
y4 ~~ y8
y6 ~~ y8
'
mxsem(model = model,
data = OpenMx::Bollen) |>
mxTryHard() |>
summary()
#> Summary of untitled2
#>
#> free parameters:
#> name matrix row col Estimate Std.Error A lbound ubound
#> 1 ind60→x2 A x2 ind60 2.012660e+00 0.38891027
#> 2 ind60→x3 A x3 ind60 1.650326e+00 0.36081541
#> 3 ind60→dem60 A dem60 ind60 4.091644e+00 0.82825703
#> 4 ind60→dem65 A dem65 ind60 4.476238e+01 33.03590013
#> 5 a1 A y2 dem60 1.296343e+00 0.22069102
#> 6 b A y3 dem60 1.187559e+00 0.13597913
#> 7 c1 A y4 dem60 1.413415e+00 0.18183251
#> 8 dem60→dem65 A dem65 dem60 -9.854813e+00 5.74179618
#> 9 a2 A y6 dem65 1.121844e+00 0.16042018
#> 10 c2 A y8 dem65 1.224479e+00 0.14984899
#> 11 y1↔y1 S y1 y1 2.686888e+00 0.59075793 1e-06
#> 12 y2↔y2 S y2 y2 8.576610e+00 1.48229765 1e-06
#> 13 y3↔y3 S y3 y3 5.847195e+00 1.09096957 1e-06
#> 14 y2↔y4 S y2 y4 1.987018e+00 0.78013870
#> 15 y4↔y4 S y4 y4 3.387325e+00 0.74388310 1e-06
#> 16 y2↔y6 S y2 y6 2.385179e+00 0.76306049
#> 17 y6↔y6 S y6 y6 5.129115e+00 0.91213692 1e-06
#> 18 x1↔x1 S x1 x1 3.013521e-01 0.06239685 1e-06
#> 19 x2↔x2 S x2 x2 1.325533e+00 0.27206604 1e-06
#> 20 x3↔x3 S x3 x3 1.326978e+00 0.25275042 1e-06
#> 21 y1↔y5 S y1 y5 7.307489e-01 0.40428182
#> 22 y5↔y5 S y5 y5 2.262309e+00 0.47568663 1e-06
#> 23 y3↔y7 S y3 y7 1.315088e+00 0.74793582
#> 24 y7↔y7 S y7 y7 3.819416e+00 0.79913029 1e-06
#> 25 y4↔y8 S y4 y8 3.442654e-01 0.46177893
#> 26 y6↔y8 S y6 y8 1.438664e+00 0.60291913
#> 27 y8↔y8 S y8 y8 3.402689e+00 0.72529659 1e-06
#> 28 ind60↔ind60 S ind60 ind60 2.286328e-01 0.08085603 1e-06
#> 29 dem60↔dem60 S dem60 dem60 1.000001e-06 NA ! 0!
#> 30 dem65↔dem65 S dem65 dem65 1.334856e-01 0.24827033 1e-06
#> 31 one→y1 M 1 y1 5.464667e+00 0.29473841
#> 32 one→y2 M 1 y2 4.256443e+00 0.44738225
#> 33 one→y3 M 1 y3 6.563110e+00 0.38723974
#> 34 one→y4 M 1 y4 4.452533e+00 0.38359678
#> 35 one→y6 M 1 y6 2.978074e+00 0.38247416
#> 36 one→x1 M 1 x1 5.054383e+00 0.08406584
#> 37 one→x2 M 1 x2 4.792195e+00 0.17327643
#> 38 one→x3 M 1 x3 3.557690e+00 0.16123756
#> 39 one→y5 M 1 y5 5.136252e+00 0.30340241
#> 40 one→y7 M 1 y7 6.196264e+00 0.37176597
#> 41 one→y8 M 1 y8 4.043390e+00 0.37170879
#>
#> Model Statistics:
#> | Parameters | Degrees of Freedom | Fit (-2lnL units)
#> Model: 41 784 3274.152
#> Saturated: 77 748 NA
#> Independence: 22 803 NA
#> Number of observations/statistics: 75/825
#>
#> Information Criteria:
#> | df Penalty | Parameters Penalty | Sample-Size Adjusted
#> AIC: 1706.152 3356.152 3460.515
#> BIC: -110.759 3451.169 3321.947
#> To get additional fit indices, see help(mxRefModels)
#> timestamp: 2024-07-21 20:44:38
#> Wall clock time: 0.1139431 secs
#> optimizer: SLSQP
#> OpenMx version number: 2.21.11
#> Need help? See help(mxSummary)
Lower and upper bounds can be added to any of the parameters in the model. The following demonstrates bounds on a loading:
library(mxsem)
<- '
model # latent variable definitions
ind60 =~ x1 + x2 + x3
dem60 =~ y1 + a1*y2 + b*y3 + c1*y4
dem65 =~ y5 + a2*y6 + b*y7 + c2*y8
# lower bound on a1
a1 > 0
# upper bound on a2
a2 < 10.123
'
mxsem(model = model,
data = OpenMx::Bollen,
# use latent variances to scale the model
scale_loadings = FALSE,
scale_latent_variances = TRUE) |>
mxTryHard() |>
summary()
#> Summary of untitled4
#>
#> free parameters:
#> name matrix row col Estimate Std.Error A lbound ubound
#> 1 ind60→x1 A x1 ind60 -0.66602168 0.06402911
#> 2 ind60→x2 A x2 ind60 -1.45290840 0.12615652
#> 3 ind60→x3 A x3 ind60 -1.21127230 0.12698816
#> 4 dem60→y1 A y1 dem60 2.21018030 0.24806182
#> 5 a1 A y2 dem60 2.98303646 0.39464650 0
#> 6 b A y3 dem60 2.52119429 0.27195610
#> 7 c1 A y4 dem60 2.86625955 0.31512659
#> 8 dem65→y5 A y5 dem65 2.08192035 0.25256395
#> 9 a2 A y6 dem65 2.61417796 0.33067157 10.123
#> 10 c2 A y8 dem65 2.72104603 0.30578894
#> 11 x1↔x1 S x1 x1 0.08176774 0.01979715 1e-06
#> 12 x2↔x2 S x2 x2 0.11868552 0.07038039 1e-06
#> 13 x3↔x3 S x3 x3 0.46717050 0.08933577 1e-06
#> 14 y1↔y1 S y1 y1 1.92282818 0.40072499 1e-06
#> 15 y2↔y2 S y2 y2 6.51159526 1.20284012 1e-06
#> 16 y3↔y3 S y3 y3 5.31392061 0.95937939 1e-06
#> 17 y4↔y4 S y4 y4 2.88902582 0.63409911 1e-06
#> 18 y5↔y5 S y5 y5 2.38176160 0.45553891 1e-06
#> 19 y6↔y6 S y6 y6 4.36051128 0.82332444 1e-06
#> 20 y7↔y7 S y7 y7 3.58248880 0.68191696 1e-06
#> 21 y8↔y8 S y8 y8 2.95767562 0.62791664 1e-06
#> 22 ind60↔dem60 S ind60 dem60 -0.43953545 0.10490002
#> 23 ind60↔dem65 S ind60 dem65 -0.54935145 0.09041729
#> 24 dem60↔dem65 S dem60 dem65 0.97753003 0.02697925
#> 25 one→x1 M 1 x1 5.05438406 0.08369988
#> 26 one→x2 M 1 x2 4.79219545 0.17243259
#> 27 one→x3 M 1 x3 3.55769028 0.16060761
#> 28 one→y1 M 1 y1 5.46466541 0.30131941
#> 29 one→y2 M 1 y2 4.25644008 0.45333817
#> 30 one→y3 M 1 y3 6.56310968 0.39450506
#> 31 one→y4 M 1 y4 4.45253268 0.38484200
#> 32 one→y5 M 1 y5 5.13625169 0.29928682
#> 33 one→y6 M 1 y6 2.97807303 0.38639154
#> 34 one→y7 M 1 y7 6.19626363 0.36407370
#> 35 one→y8 M 1 y8 4.04338969 0.37174814
#>
#> Model Statistics:
#> | Parameters | Degrees of Freedom | Fit (-2lnL units)
#> Model: 35 790 3130.995
#> Saturated: 77 748 NA
#> Independence: 22 803 NA
#> Number of observations/statistics: 75/825
#>
#> Information Criteria:
#> | df Penalty | Parameters Penalty | Sample-Size Adjusted
#> AIC: 1550.9954 3200.995 3265.611
#> BIC: -279.8202 3282.107 3171.797
#> To get additional fit indices, see help(mxRefModels)
#> timestamp: 2024-07-21 20:44:40
#> Wall clock time: 0.2327423 secs
#> optimizer: SLSQP
#> OpenMx version number: 2.21.11
#> Need help? See help(mxSummary)
mxsem adds lower bounds to any of the variances by
default. To remove these lower bounds, set
lbound_variances = FALSE
when calling
mxsem()
.
Definition variables are, for instance, used in latent growth curve
models when the time intervals between observations are different for
the subjects in the data set. Here is an example, where the variables
t_1
-t_5
indicate the person-specific times of
observation:
library(mxsem)
set.seed(3489)
<- simulate_latent_growth_curve(N = 100)
dataset head(dataset)
#> y1 y2 y3 y4 y5 t_1 t_2 t_3
#> [1,] 1.2817946 5.159870 7.178191 8.950046 11.4822306 0 1.5792322 2.304777
#> [2,] 1.1796379 3.588279 5.927219 8.381157 10.4640667 0 1.6701976 3.530621
#> [3,] 0.2196010 0.763441 2.499564 3.672995 4.4505868 0 0.6452145 2.512730
#> [4,] 0.5688185 1.440709 1.523483 1.416965 1.9674847 0 1.7171826 3.245522
#> [5,] 3.4928919 2.620657 1.753159 1.080701 -0.4436508 0 1.4055839 2.024568
#> [6,] 0.3520293 5.126854 7.390669 10.721785 12.6363472 0 1.5249299 2.400432
#> t_4 t_5
#> [1,] 3.120797 4.217403
#> [2,] 5.004695 6.408367
#> [3,] 3.761189 4.729461
#> [4,] 4.331997 6.145424
#> [5,] 3.570780 5.517224
#> [6,] 3.654230 4.222212
In OpenMx, parameters can be set to the values found
in the columns of the data set with the data.
prefix. This
is used in the following to fix the loadings of a latent slope variable
on the observations to the times recorded in
t_1
-t_5
:
library(mxsem)
<- "
model # specify latent intercept
I =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5
# specify latent slope
S =~ data.t_1 * y1 + data.t_2 * y2 + data.t_3 * y3 + data.t_4 * y4 + data.t_5 * y5
# specify means of latent intercept and slope
I ~ int*1
S ~ slp*1
# set intercepts of manifest variables to zero
y1 ~ 0*1; y2 ~ 0*1; y3 ~ 0*1; y4 ~ 0*1; y5 ~ 0*1;
"
mxsem(model = model,
data = dataset) |>
mxTryHard() |>
summary()
#> Summary of untitled6
#>
#> free parameters:
#> name matrix row col Estimate Std.Error A lbound ubound
#> 1 y1↔y1 S y1 y1 0.02578029 0.014488230 0!
#> 2 y2↔y2 S y2 y2 0.04010524 0.008389744 0!
#> 3 y3↔y3 S y3 y3 0.04008175 0.006984929 0!
#> 4 y4↔y4 S y4 y4 0.01752572 0.006930952 ! 0!
#> 5 y5↔y5 S y5 y5 0.05936968 0.016067405 1e-06
#> 6 I↔I S I I 1.02593614 0.148068976 1e-06
#> 7 I↔S S I S -0.14724710 0.110019557
#> 8 S↔S S S S 1.13050977 0.160502645 1e-06
#> 9 int M 1 I 0.93112329 0.102209132
#> 10 slp M 1 S 0.48442608 0.106476404
#>
#> Model Statistics:
#> | Parameters | Degrees of Freedom | Fit (-2lnL units)
#> Model: 10 10 841.2609
#> Saturated: 20 0 NA
#> Independence: 10 10 NA
#> Number of observations/statistics: 100/20
#>
#> Information Criteria:
#> | df Penalty | Parameters Penalty | Sample-Size Adjusted
#> AIC: 821.2609 861.2609 863.7328
#> BIC: 795.2092 887.3126 855.7301
#> To get additional fit indices, see help(mxRefModels)
#> timestamp: 2024-07-21 20:44:41
#> Wall clock time: 0.4582329 secs
#> optimizer: SLSQP
#> OpenMx version number: 2.21.11
#> Need help? See help(mxSummary)
Sometimes, one may want to express one parameter as a function of other parameters. In moderated non-linear factor analysis, for example, model parameters are often expressed in terms of a covariate k. For instance, the effect \(a\) of \(\xi\) on \(\eta\) could be expressed as \(a = a_0 + a_1\times k\).
library(mxsem)
set.seed(9820)
<- simulate_moderated_nonlinear_factor_analysis(N = 100)
dataset head(dataset)
#> x1 x2 x3 y1 y2 y3 k
#> [1,] -1.2166034 -1.2374549 -1.3731943 -1.01018683 -0.8296293 -1.2300555484 0
#> [2,] 1.1911346 0.9971499 1.0226322 0.86048030 0.4509088 0.6052786392 1
#> [3,] -0.7777169 -0.4725291 -0.8507347 -1.09582848 -0.5035753 -0.8048378456 0
#> [4,] 1.0027847 1.2351709 0.6951317 0.94040287 0.6684979 0.6596891858 0
#> [5,] 0.4387896 0.3919877 0.3260557 -0.58188691 -0.3614349 -0.4901022121 0
#> [6,] -1.4951549 -0.8834637 -1.1715535 0.01173845 -0.4697865 -0.0006475256 0
mxsem currently supports two ways of specifying such
transformations. First, they can be specified explicitly. To this end,
the parameters \(a_0\) and \(a_1\) must fist be initialized with
!a0
and !a1
. Additionally, the transformation
must be defined with a := a0 + a1*data.k
.
<- "
model # loadings
xi =~ x1 + x2 + x3
eta =~ y1 + y2 + y3
# regression
eta ~ a*xi
# we need two new parameters: a0 and a1. These are created as follows:
!a0
!a1
# Now, we redefine a to be a0 + k*a1, where k is found in the data
a := a0 + data.k*a1
"
<- mxsem(model = model,
fit_mx data = dataset) |>
mxTryHard()
summary(fit_mx)
# get just the value for parameter a:
mxEval(expression = a, model = fit_mx)
#> Summary of untitled20
#>
#> free parameters:
#> name matrix row col Estimate Std.Error A lbound ubound
#> 1 xi→x2 A x2 xi 0.79157856 0.026246030
#> 2 xi→x3 A x3 xi 0.89166084 0.027991530
#> 3 eta→y2 A y2 eta 0.81610417 0.028977422
#> 4 eta→y3 A y3 eta 0.90741898 0.027924339
#> 5 x1↔x1 S x1 x1 0.04060218 0.011022272 0!
#> 6 x2↔x2 S x2 x2 0.04519854 0.008621602 0!
#> 7 x3↔x3 S x3 x3 0.04647176 0.010143713 0!
#> 8 y1↔y1 S y1 y1 0.03388953 0.008495337 0!
#> 9 y2↔y2 S y2 y2 0.04210954 0.007766716 ! 0!
#> 10 y3↔y3 S y3 y3 0.03107018 0.007268297 ! 0!
#> 11 xi↔xi S xi xi 1.07304573 0.157790632 1e-06
#> 12 eta↔eta S eta eta 0.26127595 0.041232498 1e-06
#> 13 one→x1 M 1 x1 -0.14881004 0.105059830
#> 14 one→x2 M 1 x2 -0.10969640 0.084340983
#> 15 one→x3 M 1 x3 -0.15448448 0.094428639
#> 16 one→y1 M 1 y1 -0.05304588 0.089763143
#> 17 one→y2 M 1 y2 -0.13040824 0.074580498
#> 18 one→y3 M 1 y3 -0.05666192 0.081649015
#> 19 a0 new_parameters 1 1 0.78168122 0.069380240
#> 20 a1 new_parameters 1 2 -0.19334116 0.107739139
#>
#> Model Statistics:
#> | Parameters | Degrees of Freedom | Fit (-2lnL units)
#> Model: 20 7 475.3822
#> Saturated: 27 0 NA
#> Independence: 12 15 NA
#> Number of observations/statistics: 100/27
#>
#> Information Criteria:
#> | df Penalty | Parameters Penalty | Sample-Size Adjusted
#> AIC: 461.3822 515.3822 526.0151
#> BIC: 443.1460 567.4856 504.3206
#> To get additional fit indices, see help(mxRefModels)
#> timestamp: 2024-07-21 20:44:42
#> Wall clock time: 0.07763433 secs
#> optimizer: SLSQP
#> OpenMx version number: 2.21.11
#> Need help? See help(mxSummary)
#> [,1]
#> [1,] 0.7816812
Alternatively, the transformations can be defined implicitly by placing the algebra in curly braces and directly inserting it in the syntax in place of the parameter label. This is inspired by the approach in metaSEM (Cheung, 2015).
<- "
model # loadings
xi =~ x1 + x2 + x3
eta =~ y1 + y2 + y3
# regression
eta ~ {a0 + a1*data.k} * xi
"
mxsem(model = model,
data = dataset) |>
mxTryHard() |>
summary()
#> Summary of untitled48
#>
#> free parameters:
#> name matrix row col Estimate Std.Error A lbound ubound
#> 1 xi→x2 A x2 xi 0.79157856 0.026246030
#> 2 xi→x3 A x3 xi 0.89166084 0.027991530
#> 3 eta→y2 A y2 eta 0.81610417 0.028977422
#> 4 eta→y3 A y3 eta 0.90741898 0.027924339
#> 5 x1↔x1 S x1 x1 0.04060218 0.011022272 0!
#> 6 x2↔x2 S x2 x2 0.04519854 0.008621602 0!
#> 7 x3↔x3 S x3 x3 0.04647176 0.010143713 0!
#> 8 y1↔y1 S y1 y1 0.03388953 0.008495337 0!
#> 9 y2↔y2 S y2 y2 0.04210954 0.007766716 ! 0!
#> 10 y3↔y3 S y3 y3 0.03107018 0.007268297 ! 0!
#> 11 xi↔xi S xi xi 1.07304573 0.157790632 1e-06
#> 12 eta↔eta S eta eta 0.26127595 0.041232498 1e-06
#> 13 one→x1 M 1 x1 -0.14881004 0.105059830
#> 14 one→x2 M 1 x2 -0.10969640 0.084340983
#> 15 one→x3 M 1 x3 -0.15448448 0.094428639
#> 16 one→y1 M 1 y1 -0.05304588 0.089763143
#> 17 one→y2 M 1 y2 -0.13040824 0.074580498
#> 18 one→y3 M 1 y3 -0.05666192 0.081649015
#> 19 a0 new_parameters 1 1 0.78168122 0.069380240
#> 20 a1 new_parameters 1 2 -0.19334116 0.107739139
#>
#> Model Statistics:
#> | Parameters | Degrees of Freedom | Fit (-2lnL units)
#> Model: 20 7 475.3822
#> Saturated: 27 0 NA
#> Independence: 12 15 NA
#> Number of observations/statistics: 100/27
#>
#> Information Criteria:
#> | df Penalty | Parameters Penalty | Sample-Size Adjusted
#> AIC: 461.3822 515.3822 526.0151
#> BIC: 443.1460 567.4856 504.3206
#> To get additional fit indices, see help(mxRefModels)
#> timestamp: 2024-07-21 20:44:42
#> Wall clock time: 0.0693748 secs
#> optimizer: SLSQP
#> OpenMx version number: 2.21.11
#> Need help? See help(mxSummary)
You can also provide custom names for the algebra results:
<- "
model # loadings
xi =~ x1 + x2 + x3
eta =~ y1 + y2 + y3
# regression
eta ~ {a := a0 + a1*data.k} * xi
"
<- mxsem(model = model,
fit_mx data = dataset) |>
mxTryHard()
summary(fit_mx)
# get just the value for parameter a:
mxEval(expression = a,
model = fit_mx)
#> Summary of untitled76
#>
#> free parameters:
#> name matrix row col Estimate Std.Error A lbound ubound
#> 1 xi→x2 A x2 xi 0.79157856 0.026246030
#> 2 xi→x3 A x3 xi 0.89166084 0.027991530
#> 3 eta→y2 A y2 eta 0.81610417 0.028977422
#> 4 eta→y3 A y3 eta 0.90741898 0.027924339
#> 5 x1↔x1 S x1 x1 0.04060218 0.011022272 0!
#> 6 x2↔x2 S x2 x2 0.04519854 0.008621602 0!
#> 7 x3↔x3 S x3 x3 0.04647176 0.010143713 0!
#> 8 y1↔y1 S y1 y1 0.03388953 0.008495337 0!
#> 9 y2↔y2 S y2 y2 0.04210954 0.007766716 ! 0!
#> 10 y3↔y3 S y3 y3 0.03107018 0.007268297 ! 0!
#> 11 xi↔xi S xi xi 1.07304573 0.157790632 1e-06
#> 12 eta↔eta S eta eta 0.26127595 0.041232498 1e-06
#> 13 one→x1 M 1 x1 -0.14881004 0.105059830
#> 14 one→x2 M 1 x2 -0.10969640 0.084340983
#> 15 one→x3 M 1 x3 -0.15448448 0.094428639
#> 16 one→y1 M 1 y1 -0.05304588 0.089763143
#> 17 one→y2 M 1 y2 -0.13040824 0.074580498
#> 18 one→y3 M 1 y3 -0.05666192 0.081649015
#> 19 a0 new_parameters 1 1 0.78168122 0.069380240
#> 20 a1 new_parameters 1 2 -0.19334116 0.107739139
#>
#> Model Statistics:
#> | Parameters | Degrees of Freedom | Fit (-2lnL units)
#> Model: 20 7 475.3822
#> Saturated: 27 0 NA
#> Independence: 12 15 NA
#> Number of observations/statistics: 100/27
#>
#> Information Criteria:
#> | df Penalty | Parameters Penalty | Sample-Size Adjusted
#> AIC: 461.3822 515.3822 526.0151
#> BIC: 443.1460 567.4856 504.3206
#> To get additional fit indices, see help(mxRefModels)
#> timestamp: 2024-07-21 20:44:43
#> Wall clock time: 0.0685575 secs
#> optimizer: SLSQP
#> OpenMx version number: 2.21.11
#> Need help? See help(mxSummary)
#> [,1]
#> [1,] 0.7816812
mxsem
returns an mxModel
object that can be
adapted further by users familiar with OpenMx.
Sometimes things may go wrong. One way to figure out where
mxsem messed up is to look at the parameter table
generated internally. This parameter table is not returned by default.
See vignette("create_parameter_table", package = "mxsem")
for more details.
Another point of failure are the default labels used by
mxsem to indicate directed and undirected effects.
These are based on unicode characters. If you see parameter labels
similar to "eta\u2192y1"
in your output, this indicates
that your editor cannot display unicode characters. In this case, you
can customize the labels as follows:
library(mxsem)
<- '
model # latent variable definitions
ind60 =~ x1 + x2 + x3
dem60 =~ y1 + a1*y2 + b*y3 + c1*y4
dem65 =~ y5 + a2*y6 + b*y7 + c2*y8
'
mxsem(model = model,
data = OpenMx::Bollen,
directed = "_TO_",
undirected = "_WITH_") |>
mxTryHard() |>
summary()
#> Summary of untitled90
#>
#> free parameters:
#> name matrix row col Estimate Std.Error A lbound ubound
#> 1 ind60_TO_x2 A x2 ind60 2.18115702 0.13928666
#> 2 ind60_TO_x3 A x3 ind60 1.81852890 0.15228797
#> 3 a1 A y2 dem60 1.40364256 0.18390038
#> 4 b A y3 dem60 1.17009172 0.10871747
#> 5 c1 A y4 dem60 1.34853386 0.14637663
#> 6 a2 A y6 dem65 1.20074512 0.14855357
#> 7 c2 A y8 dem65 1.25031848 0.13637438
#> 8 x1_WITH_x1 S x1 x1 0.08169539 0.01979123 1e-06
#> 9 x2_WITH_x2 S x2 x2 0.11895803 0.07035954 1e-06
#> 10 x3_WITH_x3 S x3 x3 0.46715652 0.08931226 1e-06
#> 11 y1_WITH_y1 S y1 y1 1.96249145 0.40675153 ! 1e-06
#> 12 y2_WITH_y2 S y2 y2 6.49922273 1.20251628 1e-06
#> 13 y3_WITH_y3 S y3 y3 5.32559112 0.95894588 1e-06
#> 14 y4_WITH_y4 S y4 y4 2.87950917 0.63665763 1e-06
#> 15 y5_WITH_y5 S y5 y5 2.37088343 0.45487035 1e-06
#> 16 y6_WITH_y6 S y6 y6 4.37313277 0.82251242 1e-06
#> 17 y7_WITH_y7 S y7 y7 3.56699590 0.68171379 1e-06
#> 18 y8_WITH_y8 S y8 y8 2.96557681 0.62443800 ! 1e-06
#> 19 ind60_WITH_ind60 S ind60 ind60 0.44829143 0.08675629 1e-06
#> 20 ind60_WITH_dem60 S ind60 dem60 0.63807497 0.19920187
#> 21 dem60_WITH_dem60 S dem60 dem60 4.50351167 1.00616960 1e-06
#> 22 ind60_WITH_dem65 S ind60 dem65 0.81413650 0.21697272
#> 23 dem60_WITH_dem65 S dem60 dem65 4.52636825 0.93243049
#> 24 dem65_WITH_dem65 S dem65 dem65 4.75141153 1.04835747 1e-06
#> 25 one_TO_x1 M 1 x1 5.05438446 0.08405796
#> 26 one_TO_x2 M 1 x2 4.79219580 0.17325941
#> 27 one_TO_x3 M 1 x3 3.55769067 0.16122376
#> 28 one_TO_y1 M 1 y1 5.46466750 0.29359270
#> 29 one_TO_y2 M 1 y2 4.25644400 0.45268169
#> 30 one_TO_y3 M 1 y3 6.56311167 0.39140003
#> 31 one_TO_y4 M 1 y4 4.45253335 0.38413637
#> 32 one_TO_y5 M 1 y5 5.13625263 0.30813153
#> 33 one_TO_y6 M 1 y6 2.97807393 0.38680848
#> 34 one_TO_y7 M 1 y7 6.19626358 0.36642683
#> 35 one_TO_y8 M 1 y8 4.04339058 0.37222072
#>
#> Model Statistics:
#> | Parameters | Degrees of Freedom | Fit (-2lnL units)
#> Model: 35 790 3131.168
#> Saturated: 77 748 NA
#> Independence: 22 803 NA
#> Number of observations/statistics: 75/825
#>
#> Information Criteria:
#> | df Penalty | Parameters Penalty | Sample-Size Adjusted
#> AIC: 1551.1683 3201.168 3265.784
#> BIC: -279.6473 3282.280 3171.970
#> To get additional fit indices, see help(mxRefModels)
#> timestamp: 2024-07-21 20:44:44
#> Wall clock time: 0.1770966 secs
#> optimizer: SLSQP
#> OpenMx version number: 2.21.11
#> Need help? See help(mxSummary)