{"id":22301693,"url":"https://github.com/jhorzek/mxsem","last_synced_at":"2025-07-29T02:32:45.385Z","repository":{"id":180986301,"uuid":"666026790","full_name":"jhorzek/mxsem","owner":"jhorzek","description":"A lavaan-like syntax for structural equation models with OpenMx","archived":false,"fork":false,"pushed_at":"2024-11-16T20:14:38.000Z","size":1876,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-16T21:21:47.277Z","etag":null,"topics":["factor-analysis","lavaan","openmx","structural-equation-modeling"],"latest_commit_sha":null,"homepage":"https://jhorzek.github.io/mxsem/","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jhorzek.png","metadata":{"files":{"readme":"README.Rmd","changelog":"NEWS.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-13T14:34:33.000Z","updated_at":"2024-11-16T20:11:13.000Z","dependencies_parsed_at":"2024-05-05T17:45:41.934Z","dependency_job_id":"17c1814a-f249-4b15-a835-c1da2ee9b2ed","html_url":"https://github.com/jhorzek/mxsem","commit_stats":null,"previous_names":["jhorzek/mxsem"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhorzek%2Fmxsem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhorzek%2Fmxsem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhorzek%2Fmxsem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhorzek%2Fmxsem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jhorzek","download_url":"https://codeload.github.com/jhorzek/mxsem/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227973513,"owners_count":17849728,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["factor-analysis","lavaan","openmx","structural-equation-modeling"],"created_at":"2024-12-03T18:23:53.826Z","updated_at":"2024-12-03T18:23:54.480Z","avatar_url":"https://github.com/jhorzek.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\noutput: github_document\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.path = \"man/figures/README-\",\n  out.width = \"100%\"\n)\nlibrary(mxsem)\nset.seed(123)\n```\n\n# mxsem\n\n\u003c!-- badges: start --\u003e\n[![Total Downloads](https://cranlogs.r-pkg.org/badges/grand-total/mxsem)](https://cranlogs.r-pkg.org/badges/grand-total/mxsem)\n[![R-CMD-check](https://github.com/jhorzek/mxsem/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/jhorzek/mxsem/actions/workflows/R-CMD-check.yaml)\n\u003c!-- badges: end --\u003e\n\n**mxsem** provides a **lavaan**-like (Rosseel, 2012) syntax to implement structural equation models (SEM)\nwith **OpenMx** (Boker et al., 2011). The objective is to simplify fitting basic SEM with\n**OpenMx**, while also unlocking some very useful advanced features. For instance, \n**mxsem** allows for parameter transformations and definition\nvariables. However, **mxsem** is intentionally incomplete in order to focus\non simplicity. The main function (`mxsem()`) is similar to **lavaan**'s `sem()`-function\nin that it tries to set up parts of the model automatically (e.g., adding variances\nautomatically or scaling the latent variables automatically).\n\n\u003e **Warning**: The syntax and settings of **mxsem** may differ from \n**lavaan** in some cases. See `vignette(\"Syntax\", package = \"mxsem\")` for more details \non the syntax and the default arguments.\n\n## Alternatives\n\n**mxsem** is not the first package providing a **lavaan**-like syntax for **OpenMx**.\nYou will find similar functions in the following packages:\n\n- [**metaSEM**](https://github.com/mikewlcheung/metasem) (Cheung, 2015) provides a `lavaan2RAM`\nfunction that can be combined with the `create.mxModel` function. This combination\noffers more features than **mxsem**. For instance, constraints of the form `a \u003c b`\nare supported. In **mxsem** such constraints require algebras (e.g., `!diff; a := b - exp(diff)`).\n- [**umx**](https://github.com/tbates/umx) (Bates et al., 2019) \nprovides the `umxRAM` and `umxLav2RAM` functions that can parse single **lavaan**-style \nstatements (e.g., `eta =~ y1 + y2 + y3`) \nor an entire **lavaan** models to **OpenMx** models.\n- [**tidySEM**](https://github.com/cjvanlissa/tidySEM) (van Lissa, 2023) provides the\n`as_ram` function to translate **lavaan** syntax to **OpenMx** and also implements a unified syntax to\nspecify both, **lavaan** and **OpenMx** models. Additionally, it works well with the\n**tidyverse**.\n- [**ezMx**](https://github.com/OpenMx/ezMx) (Bates, et al. 2014) simplifies fitting SEM with **OpenMx**\nand also provides a translation of **lavaan** models to **OpenMx** with the \n`lavaan.to.OpenMx` function.\n\nBecause **mxsem** implements the syntax parser from scratch, it can extend the \n**lavaan** syntax to account for specific **OpenMx** features. This enables \n[implicit transformations](#transformations) with curly braces.\n\n## Citation\n\nCite **OpenMx** (Boker et al., 2011) for the modeling and **lavaan** for the \nsyntax (Rosseel, 2012). To cite **mxsem**, check `citation(\"mxsem\")`.\n\n## Installation\n\n**mxsem** is available from CRAN:\n\n```{r, eval = FALSE}\ninstall.packages(\"mxsem\")\n```\n\nThe newest version of the package can be installed from GitHub using the following commands in R:\n\n```{r, eval = FALSE}\nif(!require(devtools)) install.packages(\"devtools\")\ndevtools::install_github(\"jhorzek/mxsem\", \n                         ref = \"main\")\n```\nBecause **mxsem** uses Rcpp, you will need a compiler for C++ (e.g., by installing\nRtools on Windows, Xcode on Mac and build-essential on linux).\n\n## Example\n\nThe following example is directly adapted from **lavaan**:\n\n```{r, eval = TRUE, results = 'hide', message=FALSE, warning=FALSE, message=FALSE, warning=FALSE}\nlibrary(mxsem)\nmodel \u003c- '\n  # latent variable definitions\n     ind60 =~ x1 + x2 + x3\n     dem60 =~ y1 + a1*y2 + b*y3 + c1*y4\n     dem65 =~ y5 + a2*y6 + b*y7 + c2*y8\n\n  # regressions\n    dem60 ~ ind60\n    dem65 ~ ind60 + dem60\n\n  # residual correlations\n    y1 ~~ y5\n    y2 ~~ y4 + y6\n    y3 ~~ y7\n    y4 ~~ y8\n    y6 ~~ y8\n'\n\nmxsem(model = model,\n      data  = OpenMx::Bollen) |\u003e\n  mxTryHard() |\u003e\n  summary()\n```\n\u003cdetails\u003e\n\u003csummary\u003eShow summary\u003c/summary\u003e\n\n\n```{r, include=FALSE}\nfit_mx \u003c- mxsem(model = model,\n                data  = OpenMx::Bollen) |\u003e\n  mxTryHard()\n```\n```{r,echo=FALSE}\nsummary(fit_mx)\n```\n\n\u003c/details\u003e\n\n## Adding bounds\n\nLower and upper bounds can be added to any of the parameters in the model. \nThe following demonstrates bounds on a loading:\n```{r, eval = TRUE, results = 'hide', message=FALSE, warning=FALSE}\nlibrary(mxsem)\nmodel \u003c- '\n  # latent variable definitions\n     ind60 =~ x1 + x2 + x3\n     dem60 =~ y1 + a1*y2 + b*y3 + c1*y4\n     dem65 =~ y5 + a2*y6 + b*y7 + c2*y8\n     \n  # lower bound on a1\n     a1 \u003e 0\n  # upper bound on a2\n     a2 \u003c 10.123\n'\n\nmxsem(model = model,\n      data  = OpenMx::Bollen, \n      # use latent variances to scale the model\n      scale_loadings = FALSE, \n      scale_latent_variances = TRUE) |\u003e\n  mxTryHard() |\u003e\n  summary()\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eShow summary\u003c/summary\u003e\n\n```{r, include=FALSE}\nfit_mx \u003c- mxsem(model = model,\n                data  = OpenMx::Bollen, \n                # use latent variances to scale the model\n                scale_loadings         = FALSE, \n                scale_latent_variances = TRUE) |\u003e\n  mxTryHard()\n```\n```{r,echo=FALSE}\nsummary(fit_mx)\n```\n\n\u003c/details\u003e\n\n**mxsem** adds lower bounds to any of the variances by default. To remove these\nlower bounds, set `lbound_variances = FALSE` when calling `mxsem()`.\n\n## Definition Variables\n\nDefinition variables are, for instance, used in latent growth curve models when\nthe time intervals between observations are different for the subjects\nin the data set. Here is an example, where the variables `t_1`-`t_5` indicate\nthe person-specific times of observation:\n\n```{r, eval = TRUE}\nlibrary(mxsem)\nset.seed(3489)\ndataset \u003c- simulate_latent_growth_curve(N = 100)\nhead(dataset)\n```\n\nIn **OpenMx**, parameters can be set to the values found in the columns of\nthe data set with the `data.` prefix. This is used in the following to fix\nthe loadings of a latent slope variable on the observations to the times \nrecorded in `t_1`-`t_5`:\n```{r, eval = TRUE, results = 'hide', message=FALSE, warning=FALSE}\nlibrary(mxsem)\nmodel \u003c- \"\n  # specify latent intercept\n     I =~ 1*y1 + 1*y2 + 1*y3 + 1*y4 + 1*y5\n  # specify latent slope\n     S =~ data.t_1 * y1 + data.t_2 * y2 + data.t_3 * y3 + data.t_4 * y4 + data.t_5 * y5\n    \n  # specify means of latent intercept and slope\n     I ~ int*1\n     S ~ slp*1\n  \n  # set intercepts of manifest variables to zero\n     y1 ~ 0*1; y2 ~ 0*1; y3 ~ 0*1; y4 ~ 0*1; y5 ~ 0*1;\n  \"\n\nmxsem(model = model,\n      data  = dataset) |\u003e\n  mxTryHard() |\u003e\n  summary()\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eShow summary\u003c/summary\u003e\n\n```{r, include=FALSE}\nfit_mx \u003c- mxsem(model = model,\n                data  = dataset) |\u003e\n  mxTryHard()\n```\n```{r,echo=FALSE}\nsummary(fit_mx)\n```\n\n\u003c/details\u003e\n\n## Transformations\n\nSometimes, one may want to express one parameter as a function of other parameters.\nIn moderated non-linear factor analysis, for example, model parameters are often \nexpressed in terms of a covariate k. For instance, the effect $a$ of $\\xi$ on $\\eta$ \ncould be expressed as $a = a_0 + a_1\\times k$.\n\n```{r, eval = TRUE}\nlibrary(mxsem)\nset.seed(9820)\ndataset \u003c- simulate_moderated_nonlinear_factor_analysis(N = 100)\nhead(dataset)\n```\n\n**mxsem** currently supports two ways of specifying such transformations. First,\nthey can be specified explicitly. To this end, the parameters $a_0$ and $a_1$\nmust fist be initialized with `!a0` and `!a1`. Additionally, the transformation\nmust be defined with `a := a0 + a1*data.k`.\n```{r, eval = TRUE, results = 'hide', message=FALSE, warning=FALSE}\nmodel \u003c- \"\n  # loadings\n     xi =~ x1 + x2 + x3\n     eta =~ y1 + y2 + y3\n  # regression\n     eta ~ a*xi\n  \n  # we need two new parameters: a0 and a1. These are created as follows:\n     !a0\n     !a1\n  # Now, we redefine a to be a0 + k*a1, where k is found in the data\n     a := a0 + data.k*a1\n\"\n\nfit_mx \u003c- mxsem(model = model,\n                data  = dataset) |\u003e\n  mxTryHard()\n\nsummary(fit_mx)\n\n# get just the value for parameter a:\nmxEval(expression = a, model = fit_mx)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eShow summary\u003c/summary\u003e\n\n```{r, include=FALSE}\nfit_mx \u003c- mxsem(model = model,\n                data = dataset) |\u003e\n  mxTryHard()\n```\n```{r,echo=FALSE}\nsummary(fit_mx)\n# get just the value for parameter a:\nmxEval(expression = a, \n       model      = fit_mx)\n```\n\n\u003c/details\u003e\n\nAlternatively, the transformations can be defined implicitly by placing the\nalgebra in curly braces and directly inserting it in the syntax in place\nof the parameter label. This is inspired by the approach in **metaSEM** (Cheung, 2015).\n```{r, eval = TRUE, results = 'hide', message=FALSE, warning=FALSE}\nmodel \u003c- \"\n  # loadings\n     xi =~ x1 + x2 + x3\n     eta =~ y1 + y2 + y3\n  # regression\n     eta ~ {a0 + a1*data.k} * xi\n\"\n\nmxsem(model = model,\n      data  = dataset) |\u003e\n  mxTryHard() |\u003e\n  summary()\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eShow summary\u003c/summary\u003e\n\n```{r, include=FALSE}\nfit_mx \u003c- mxsem(model = model,\n                data  = dataset) |\u003e\n  mxTryHard()\n```\n```{r,echo=FALSE}\nsummary(fit_mx)\n```\n\n\u003c/details\u003e\n\nYou can also provide custom names for the algebra results:\n```{r, eval = TRUE, results = 'hide', message=FALSE, warning=FALSE}\nmodel \u003c- \"\n  # loadings\n     xi  =~ x1 + x2 + x3\n     eta =~ y1 + y2 + y3\n  # regression\n     eta ~ {a := a0 + a1*data.k} * xi\n\"\n\nfit_mx \u003c- mxsem(model = model,\n                data  = dataset) |\u003e\n  mxTryHard()\n\nsummary(fit_mx)\n\n# get just the value for parameter a:\nmxEval(expression = a, \n       model      = fit_mx)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eShow summary\u003c/summary\u003e\n\n```{r, include=FALSE}\nfit_mx \u003c- mxsem(model = model,\n                data  = dataset) |\u003e\n  mxTryHard()\n```\n\n```{r,echo=FALSE}\nsummary(fit_mx)\n# get just the value for parameter a:\nmxEval(expression = a, \n       model      = fit_mx)\n```\n\n\u003c/details\u003e\n\n## Adapting the Model\n\n`mxsem` returns an `mxModel` object that can be adapted further by users familiar\nwith **OpenMx**.\n\n## Trouble shooting\n\nSometimes things may go wrong. One way to figure out where **mxsem** messed up\nis to look at the parameter table generated internally. This parameter table\nis not returned by default. See `vignette(\"create_parameter_table\", package = \"mxsem\")`\nfor more details.\n\nAnother point of failure are the default labels used by **mxsem** to indicate directed\nand undirected effects. These are based on unicode characters. If you see parameter \nlabels similar to `\"eta\\u2192y1\"` in your output, this indicates that your editor cannot display\nunicode characters. In this case, you can customize the labels as follows:\n\n```{r, eval = TRUE, results = 'hide', message=FALSE, warning=FALSE, message=FALSE, warning=FALSE}\nlibrary(mxsem)\nmodel \u003c- '\n  # latent variable definitions\n     ind60 =~ x1 + x2 + x3\n     dem60 =~ y1 + a1*y2 + b*y3 + c1*y4\n     dem65 =~ y5 + a2*y6 + b*y7 + c2*y8\n'\n\nmxsem(model      = model,\n      data       = OpenMx::Bollen, \n      directed   = \"_TO_\", \n      undirected = \"_WITH_\") |\u003e\n  mxTryHard() |\u003e\n  summary()\n```\n\u003cdetails\u003e\n\u003csummary\u003eShow summary\u003c/summary\u003e\n\n\n```{r, include=FALSE}\nfit_mx \u003c- mxsem(model = model,\n                data  = OpenMx::Bollen, \n                directed   = \"_TO_\", \n                undirected = \"_WITH_\") |\u003e\n  mxTryHard()\n```\n```{r,echo=FALSE}\nsummary(fit_mx)\n```\n\n\u003c/details\u003e\n\n\n\n## References\n\n* Bates, T. C., Maes, H., \u0026 Neale, M. C. (2019). umx: Twin and Path-Based Structural Equation Modeling in R. Twin Research and Human Genetics, 22(1), 27–41. https://doi.org/10.1017/thg.2019.2\n* Bates, T. C., Prindle, J. J. (2014). ezMx. https://github.com/OpenMx/ezMx\n* Boker, S. M., Neale, M., Maes, H., Wilde, M., Spiegel, M., Brick, T., Spies, J., Estabrook, R., Kenny, S., Bates, T., Mehta, P., \u0026 Fox, J. (2011).\nOpenMx: An Open Source Extended Structural Equation Modeling Framework. Psychometrika, 76(2), 306–317. https://doi.org/10.1007/s11336-010-9200-6\n* Cheung, M. W.-L. (2015). metaSEM: An R package for meta-analysis using structural equation modeling. Frontiers in Psychology, 5. https://doi.org/10.3389/fpsyg.2014.01521\n* Rosseel, Y. (2012). lavaan: An R package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36. https://doi.org/10.18637/jss.v048.i02\n* van Lissa, C. J. (2023). tidySEM: Tidy Structural Equation Modeling. R package version 0.2.4, https://cjvanlissa.github.io/tidySEM/.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhorzek%2Fmxsem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjhorzek%2Fmxsem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhorzek%2Fmxsem/lists"}