semTests supports continuous FIML models with one or
several groups. Observed exogenous predictors can be included when they
are modeled jointly by setting fixed.x = FALSE and
conditional.x = FALSE. Fixed or conditional predictors need
a different reference distribution and are refused for now. These models
use the standard likelihood-ratio statistic and the usual biased gamma
estimate. The complete-data RLS and Du–Bentler
UG choices do not apply.
To make the information choice visible, we let missingness in
x1 and x5 depend on x9, which
stays observed. This gives the example a reproducible MAR-like
mechanism. It says nothing about the missingness process in the original
data.
fiml_data <- HolzingerSwineford1939
set.seed(20260717)
driver <- as.numeric(scale(fiml_data$x9))
missing_x1 <- runif(nrow(fiml_data)) <
plogis(qlogis(.20) + .8 * driver)
missing_x5 <- runif(nrow(fiml_data)) <
plogis(qlogis(.20) - .8 * driver)
fiml_data$x1[missing_x1] <- NA
fiml_data$x5[missing_x5] <- NA
colMeans(is.na(fiml_data[paste0("x", 1:9)]))
#> x1 x2 x3 x4 x5 x6 x7 x8
#> 0.2624585 0.0000000 0.0000000 0.0000000 0.2059801 0.0000000 0.0000000 0.0000000
#> x9
#> 0.0000000Fit the model using FIML:
fit_observed <- cfa(
model, fiml_data,
missing = "fiml",
estimator = "MLR"
)
pvalues(fit_observed, c("SB", "SS", "PEBA4"))
#> sb_ml ss_ml peba4_ml
#> 2.442470e-08 1.018704e-07 6.558237e-08
#> estimator: ML (MLR) (FIML) | data: continuous | information: observed | df: 24 | FIML convention: observedAn observed predictor works too when its distribution belongs to the joint model:
model_x <- "
visual =~ x1 + x2 + x3
visual ~ ageyr
"
random_x_data <- fiml_data
random_x_data$ageyr[seq(7, nrow(random_x_data), by = 23)] <- NA
fit_random_x <- cfa(
model_x, random_x_data,
missing = "fiml", estimator = "MLR",
fixed.x = FALSE, conditional.x = FALSE
)
pvalues(fit_random_x, c("SB", "SS", "PEBA2"))
#> sb_ml ss_ml peba2_ml
#> 0.6776279 0.6772337 0.6775772
#> estimator: ML (MLR) (FIML) | data: continuous | information: observed | df: 2 | FIML convention: observedBecause ageyr belongs to the joint model, its missing
values are handled by FIML too. Calling a predictor random is still a
modeling decision. If ageyr should instead be treated as a
fixed design variable, this example is not a substitute for a
conditional analysis.
Two similarly named controls do different jobs:
information fit option selects the model
information stored and used for lavaan’s own inference.fiml.convention selects the information matrices that
semTests uses for its reference distribution.The semTests default, "observed", uses
observed saturated and observed model information throughout.
semTests requests these matrices explicitly. A lavaan fit
created with expected information therefore keeps the same
observed-convention result.
Choose "lavaan" when the goal is compatibility with
lavaan’s own robust construction. For one model, it reproduces
lavInspect(fit, "UGamma"). For a nested pair, it reproduces
lavaan’s public Satorra-2000 construction. In that compatibility path,
information = "expected" controls the model-information
part of the calculation.
Expected information can be inconsistent under general MAR (Kenward and Molenberghs, 1998). Observed information reflects the realized missingness patterns and sample curvature. Savalei (2010) and Savalei and Rosseel (2022) work through the consequences for SEM. The choice can matter in finite samples, so we checked it with a large simulation.
The study crossed:
We followed the interval coverage of one free loading and the factor covariance. Six standard-error recipes combined three information choices with either a model-based covariance or an empirical-score sandwich covariance (Yuan & Bentler, 2000).
| Method | Correct, normal | Correct, t5 | Misspecified, normal | Misspecified, t5 |
|---|---|---|---|---|
| Expected, model-based | 94.48 | 79.41 | 92.10 | 75.21 |
| Expected + sandwich | 94.13 | 92.45 | 91.53 | 89.28 |
| Observed H1, model-based | 94.67 | 79.98 | 92.72 | 76.38 |
| Observed H1 + sandwich | 94.39 | 92.52 | 92.46 | 89.98 |
| Full observed Hessian, model-based | 94.73 | 80.14 | 93.46 | 77.51 |
| Full observed Hessian + sandwich | 94.72 | 93.64 | 94.53 | 93.00 |
The full observed Hessian with a sandwich covariance came closest to
95% overall, with its advantage largest under heavy tails and
misspecification, so semTests uses observed information by
default. The study targets parameter interval coverage, not the null
calibration of the goodness-of-fit p-values themselves, which have their
own deterministic and seeded checks under tools/. The
"lavaan" convention remains available when the goal is to
reproduce lavaan’s spectrum.
Fit the same model again, changing only lavaan’s model-information option:
fit_expected <- cfa(
model, fiml_data,
missing = "fiml",
estimator = "MLR",
information = "expected"
)
max(abs(coef(fit_observed) - coef(fit_expected)))
#> [1] 0The information option leaves the fitted parameters unchanged here. It can still change the reference distribution:
tests <- c("SB", "SS", "PEBA4")
comparison <- cbind(
observed_fit__observed_convention = as.numeric(
pvalues(fit_observed, tests, fiml.convention = "observed")
),
observed_fit__lavaan_convention = as.numeric(
pvalues(fit_observed, tests, fiml.convention = "lavaan")
),
expected_fit__observed_convention = as.numeric(
pvalues(fit_expected, tests, fiml.convention = "observed")
),
expected_fit__lavaan_convention = as.numeric(
pvalues(fit_expected, tests, fiml.convention = "lavaan")
)
)
rownames(comparison) <- tests
format(comparison, scientific = TRUE, digits = 4)
#> observed_fit__observed_convention observed_fit__lavaan_convention
#> SB "2.442e-08" "1.699e-08"
#> SS "1.019e-07" "6.115e-07"
#> PEBA4 "6.558e-08" "1.977e-07"
#> expected_fit__observed_convention expected_fit__lavaan_convention
#> SB "2.442e-08" "6.648e-08"
#> SS "1.019e-07" "5.204e-07"
#> PEBA4 "6.558e-08" "2.728e-07"The two observed-convention columns agree because
semTests explicitly requests observed information. The
lavaan-convention columns can differ because that path respects the
model-information choice stored in the fit.
Observed information reflects the realized missingness patterns and
sample curvature. Expected information averages curvature under the
fitted model. They can be close in well-behaved settings. Missingness
and non-normality can pull them apart. semTests keeps the
convention visible in both the function call and the result footer.
For nested models, both fits must use the same raw observations and missingness mask:
constrained <- "
visual =~ x1 + a*x2 + a*x3
textual =~ x4 + b*x5 + b*x6
speed =~ x7 + x8 + x9
"
m1 <- cfa(
model, fiml_data,
missing = "fiml", estimator = "MLR"
)
m0 <- cfa(
constrained, fiml_data,
missing = "fiml", estimator = "MLR"
)The default delta map works with the local model derivatives and tolerates a wider range of equivalent parameterizations. The exact map uses the literal parameter restrictions and requires both fits to share the same underlying set of free parameters:
nested_tests <- c("SB", "SS", "PEBA2")
nested <- cbind(
observed_delta = as.numeric(pvalues_nested(
m0, m1,
tests = nested_tests,
A.method = "delta", fiml.convention = "observed"
)),
observed_exact = as.numeric(pvalues_nested(
m0, m1,
tests = nested_tests,
A.method = "exact", fiml.convention = "observed"
)),
lavaan_delta = as.numeric(pvalues_nested(
m0, m1,
tests = nested_tests,
A.method = "delta", fiml.convention = "lavaan"
))
)
rownames(nested) <- nested_tests
format(nested, scientific = TRUE, digits = 4)
#> observed_delta observed_exact lavaan_delta
#> SB "3.392e-02" "4.335e-02" "1.530e-02"
#> SS "3.551e-02" "4.566e-02" "1.752e-02"
#> PEBA2 "3.431e-02" "4.384e-02" "1.609e-02"The delta default is the more flexible choice when equivalent models have different parameter tables. Use exact when the hypothesis is naturally written as a literal restriction on one shared set of free parameters.
Grouped models use the same interface. Here we compare a configural model with one that holds the factor loadings equal across schools:
mg1 <- cfa(
model, fiml_data,
group = "school",
missing = "fiml", estimator = "MLR"
)
mg0 <- cfa(
model, fiml_data,
group = "school", group.equal = "loadings",
missing = "fiml", estimator = "MLR"
)
pvalues(mg1, c("SB", "SS", "PEBA4"))
#> sb_ml ss_ml peba4_ml
#> 5.066665e-07 4.715279e-06 1.618893e-06
#> estimator: ML (MLR) (FIML) | data: continuous | information: observed | df: 48 | FIML convention: observed
pvalues_nested(mg0, mg1, tests = c("SB", "SS", "PEBA4"))
#> sb_ml ss_ml peba4_ml
#> 0.2253208 0.2320262 0.2254550
#> estimator: ML (MLR) (FIML) | data: continuous | information: observed | df: 6 | FIML convention: observed | nested (method 2000, A.method delta)The groups may have different sample sizes and missingness patterns. The two fits in a nested comparison still need the same observations and missingness mask within each group.
A reproducible FIML analysis should report:
information optionsemTests fiml.conventionA.method, when applicableThe result footer and attr(result, "semtests") retain
these semTests choices with the returned p-values.
Kenward, M. G., & Molenberghs, G. (1998). Likelihood based frequentist inference when data are missing at random. Statistical Science, 13(3), 236–247. https://doi.org/10.1214/ss/1028905886
Savalei, V. (2010). Expected versus observed information in SEM with incomplete normal and nonnormal data. Psychological Methods, 15(4), 352–367. https://doi.org/10.1037/a0020143
Savalei, V., & Rosseel, Y. (2022). Computational options for standard errors and test statistics with incomplete normal and nonnormal data in SEM. Structural Equation Modeling, 29(2), 163–181. https://doi.org/10.1080/10705511.2021.1877548
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. https://doi.org/10.1007/978-1-4615-4603-0_17
Yuan, K.-H., & Bentler, P. M. (2000). Three likelihood-based methods for mean and covariance structure analysis with nonnormal missing data. Sociological Methodology, 30, 165–200. https://doi.org/10.1111/0081-1750.00078