--- title: "Robust test statistics with semTests" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Robust test statistics with semTests} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", message = FALSE, warning = FALSE ) ``` ## Introduction `semTests` computes robust *p*-values for structural equation models fit with [`lavaan`](https://lavaan.ugent.be/). The standard chi-square test of model fit can reject too often when the data are non-normal. Familiar corrections such as Satorra--Bentler help. The methods in this package keep more information about the shape of the reference distribution by using its estimated eigenvalues. For the mathematically curious, the reference distribution is a weighted sum \(\sum_j \lambda_j \chi^2_1\). You do not need to calculate any eigenvalues by hand. Fit the model in lavaan, then let `pvalues()` do that part. The same basic idea covers maximum likelihood, least squares, categorical models, and FIML. The penalized eigenvalue block-averaging (`pEBA`) and penalized regression (`pOLS`) methods were introduced by Foldnes, Moss, and Grønneberg (2025). Foldnes, Grønneberg, and Moss (2026) extended them to nested model comparison. ```{r setup} library("semTests") library("lavaan") ``` ## Choose a focused guide This vignette is a quick tour. Pick the focused guide that matches your data when you want more depth: * `vignette("continuous-data", package = "semTests")` covers complete continuous data, the classical ML workflow, GLS/ULS, and nested tests. * `vignette("categorical-data", package = "semTests")` covers ordered and mixed indicators, pairwise missingness, and categorical nested comparison. * `vignette("fiml-missing-data", package = "semTests")` covers continuous FIML, the finite-sample evidence for the observed-information default, the lavaan compatibility convention, and nested restriction maps. * `vignette("latent-growth", package = "semTests")` gives FIML a more applied outing in a latent growth model. * `vignette("measurement-invariance", package = "semTests")` walks through threshold and loading invariance with ordinal indicators. ## Basic usage: goodness of fit Fit a model with `lavaan`, then call `pvalues()`. For ML models, request a robust lavaan test such as `estimator = "MLM"` or `"MLR"`. This makes lavaan store the extra sample information that `semTests` needs. ```{r basic} model <- "visual =~ x1 + x2 + x3 textual =~ x4 + x5 + x6 speed =~ x7 + x8 + x9" fit <- cfa(model, HolzingerSwineford1939, estimator = "MLM") pvalues(fit) ``` The result is a named vector with a short footer showing the estimator, data type, information choice, and degrees of freedom actually used. The complete record is available with `attr(x, "semtests")`. ### The test-name grammar Each requested test uses one of `TEST`, `TEST_UG`, `TEST_ML`, `TEST_RLS`, `TEST_UG_ML`, or `TEST_UG_RLS`: * **TEST** gives the family. Choose `pEBA` for penalized block averaging, where `j` is usually between 2 and 6. Other choices include `pOLS`, `pall`, `all`, `eba`, `std`, `sb`, `ss`, and `sf`. * **UG** asks for the unbiased Du--Bentler (2022) gamma. Without `UG`, the standard biased gamma is used. * **ML / RLS** chooses the base chi-square. `ML` uses the normal-theory discrepancy and `RLS` uses Browne's reweighted least squares statistic. Leave the suffix out to use the default for the fitted model. Several tests can be requested at once: ```{r grammar} pvalues(fit, c("SB_ML", "pEBA4_ML", "pOLS2_ML")) ``` The `UG` gamma and the `RLS` statistic belong to continuous, complete-data fits from lavaan's ML family. That includes fits requested as `MLM` or `MLR`. Other model families return an error if either option is requested. ## Nested model comparison To compare two nested models, fit both and pass them to `pvalues_nested()` with the **constrained** model first. Here we ask whether the textual loadings can be held equal: ```{r nested} constrained <- "visual =~ x1 + x2 + x3 textual =~ a*x4 + a*x5 + a*x6 speed =~ x7 + x8 + x9" m1 <- cfa(model, HolzingerSwineford1939, estimator = "MLM") m0 <- cfa(constrained, HolzingerSwineford1939, estimator = "MLM") pvalues_nested(m0, m1) ``` `PALL` is the recommended default for nested comparison (Foldnes, Grønneberg, and Moss, 2026). `semTests` uses Satorra's 2000 construction. The 2001 method has been withdrawn because it performs poorly. Both fits must use the same estimator, options, variables, groups, and observations. If the inputs arrive in reverse order, `semTests` warns and swaps them. ## More data families The package also covers several non-ML estimators. These paths have been checked against a separate implementation. `?semTests-support` gives the exact list of supported combinations. GLS and ULS work directly. ULS needs a robust lavaan test so the fit contains the required sample information: ```{r estimators} gls <- cfa(model, HolzingerSwineford1939, estimator = "GLS") pvalues(gls, "pEBA4") uls <- cfa(model, HolzingerSwineford1939, estimator = "ULS", test = "satorra.bentler" ) pvalues(uls, "pEBA4") ``` Missing data is handled through full-information maximum likelihood. Fit with `missing = "fiml"` and pass the fit to `pvalues()` as usual. FIML uses the usual biased gamma and the standard statistic, so suffix-free test names are the right choice. ```{r fiml} HS <- HolzingerSwineford1939 set.seed(1) HS$x1[sample(nrow(HS), 60)] <- NA fit_fiml <- cfa(model, HS, missing = "fiml", estimator = "MLR") pvalues(fit_fiml) ``` Observed information is the default, following Savalei (2010). The choice and the optional lavaan-compatibility convention are explained in `vignette("fiml-missing-data", package = "semTests")`, along with nested FIML examples. ### Ordered and mixed indicators Categorical models use lavaan's inspected `UGamma` and unscaled statistic. DWLS, including WLSMV/WLSM/WLSMVS, and ULS, including ULSMV, are supported for single-group and multigroup ordered or mixed-indicator models. Full WLS/ADF is refused because its correction reduces to the ordinary chi-square. ```{r categorical} HSord <- HolzingerSwineford1939 ordered_names <- paste0("x", 1:9) HSord[ordered_names] <- lapply( HSord[ordered_names], function(x) ordered(cut(x, 3)) ) fit_ordinal <- cfa(model, HSord, ordered = ordered_names) pvalues(fit_ordinal, c("SB", "SS", "pEBA4")) ``` The artificial cut only keeps this tour reproducible. In a real analysis, the decision to treat an indicator as ordered should come from how it was measured. Categorical fits may use listwise or pairwise missingness. Pairwise support uses lavaan's pairwise sample statistics and `UGamma`. Pairwise deletion has its own missingness assumptions and does not provide FIML inference. Nested categorical comparison uses `method = "2000"` with `A.method = "delta"`. ## References Browne, M. W. (1974). Generalized least squares estimators in the analysis of covariance structures. *South African Statistical Journal*, 8, 1–24. Du, H., & Bentler, P. M. (2022). 40-Year Old Unbiased Distribution Free Estimator Reliably Improves SEM Statistics for Nonnormal Data. *Structural Equation Modeling*, 29(6), 872–887. Foldnes, N., Moss, J., & Grønneberg, S. (2025). Improved goodness of fit procedures for structural equation models. *Structural Equation Modeling: A Multidisciplinary Journal*, 32(1), 1–13. Foldnes, N., Grønneberg, S., & Moss, J. (2026). Penalized eigenvalue block averaging: Extension to nested model comparison and Monte Carlo evaluations. *Behavior Research Methods*, 58, article 107. Savalei, V. (2010). Expected versus observed information in SEM with incomplete normal and nonnormal data. *Psychological Methods*, 15(4), 352–367. Satorra, A. (2000). Scaled and adjusted restricted tests in multi-sample analysis of moment structures. In R. D. H. Heijmans, D. S. G. Pollock, & A. Satorra (Eds.), *Innovations in Multivariate Statistical Analysis* (pp. 233–247). Kluwer Academic. Satorra, A., & Bentler, P. M. (1994). Corrections to test statistics and standard errors in covariance structure analysis. In A. von Eye & C. C. Clogg (Eds.), *Latent Variables Analysis: Applications for Developmental Research* (pp. 399–419). Sage.