besem_ordered(), esem_ordered(method = "rotation"): polychoric
correlations now come from lavaan (same auxiliary fit as the weight
matrix and asymptotic covariance matrix), not psych::polychoric().
psych departs from lavaan and Mplus when items differ in number of
response categories. For those items chi-square, fit indices and loadings
now equal lavaan's WLSMV fit of the unrotated model. Standardized loadings
were within 0.005 of Mplus 9 in validation runs. Equal numbers of
categories: loadings agree with 0.6.0 to about four decimals. See
test-polychoric_source.R.polychoric_source element ("lavaan" or "r_obs_override").
r_obs_override warns if it is more than 0.001 from lavaan's
correlations, since the weight matrix is lavaan's either way.missing = "listwise").lavaan_fit keeps the groups for factor_scores().generate_mplus_syntax(), generate_mplus_besem_syntax(): semicolon
after NAMES and USEVARIABLES. BY lists wrap at Mplus's 90 columns. See
test-mplus_syntax.R.ordered argument: TRUE writes CATEGORICAL and WLSMV. ESEM syntax
uses the theta parameterization, as esem_ordered() does. B-ESEM syntax
keeps the Mplus default (delta), which is the model besem_ordered()
fits, so Mplus reports a negative residual variance when there is one.
generate_mplus_besem_syntax() also gets estimator.ITERATIONS = 10000 and CONVERGENCE = 0.000001, like
the invariance syntax. Mplus's default criterion can stop short of the
optimum that R reaches.missing_code = "." writes MISSING = .; (the NA code of
MplusAutomation::prepareMplusData()).Fixes and additions prompted by the review of the Teacher's Corner
manuscript. The minor version is bumped because reported values change:
SRMR now follows the Mplus definition, composite reliabilities use absolute
loadings, and lavaan >= 0.7-2 is required. Point estimates and fit of the
previously correct paths are unchanged. Prose now says "ordinal" instead of
"ordered-categorical"; function and argument names (esem_ordered(),
ordered = TRUE) are unchanged.
esem_invariance() passes the sorted group levels to lavaan as
group.label, so the reference group is the first sorted level in R and
in the Mplus syntax written by run_mplus_besem_invariance() alike.
Loadings and factor covariances are therefore oriented to the same group
in both programs.fit_ewc(var_fixed = FALSE) re-expresses the source ESEM exactly and is
honoured for a B-ESEM source (referent primary loadings fixed, factor
variances free, covariances 0).print() and compare_ewc() agree with each other and with
Mplus.print() of ESEM, B-ESEM and EWC fits, fit_indices(), compare_ewc(),
the parameters() header and esem_compare() report the robust
chi-square, CFI, TLI and RMSEA, matching the comparison table.esem_compare() fits its CFA with the ESEM's estimator, robust test,
standard errors, missing-data setting and, for ordinal items,
parameterization, so both columns are like for like.p(p+1)/2 + p), polychoric
and category-probability residuals for ordinal items (denominator
p(p-1)/2 + total categories), pooled over groups by sample size.
Multi-group values agree with Mplus to three decimals at every invariance
level of the validation runs; single-group values are unchanged at three
decimals. The custom DWLS B-ESEM path uses the same denominator.compute_indices() sums absolute standardized loadings in every
composite (Morin, Arens & Marsh, 2016), so reverse-scoring an item or
reflecting a factor changes nothing (test-reliability.R). For CFA and
ESEM the residual variance comes from the model-implied item variance
(one minus the diagonal of Lambda Phi Lambda'), which accounts for the
factor correlations.compute_indices() help describe
the other factor's variance as an additional source of error rather than
as partialled out (Morin et al., 2020).print() of the reliability indices follows the console width (80 to 100
columns) instead of a fixed 100, and alignment_check() wraps its
recommendation line.esem_invariance() is printed in bold
blue where the console supports ANSI colour (RStudio, or a terminal whose
TERM is not "dumb"); options(bifactory.ansi_colour = FALSE) turns it
off, TRUE forces it. Same detection as parameters().esem_invariance() catches lavaan's estimation warnings per level, on the
master and on the worker processes, and reports them reworded in
inv$notes and under "Estimation notes" after the table. Admissibility is
read from the reported solution, so a note names the group and the
parameter, e.g. "a negative variance estimate (Heywood case): 2 (G latent
variance -0.120)". Only the reported fit's notes are kept; package warnings
are unaffected.print(): levels fitted and
considered, that the table can be interpreted, the most constrained
admissible level supported by dCFI >= -0.010 among all fitted levels, any
note at that level, a tip toward through = "varcov" / "means" or
partial_invariance() when strict is supported but inadmissible, and
"Remember: print(inv)". factor_scores(level = "auto") uses the same
rule, so it never selects an inadmissible level and can select varcov or
means when they were fitted.esem_invariance() gains through = c("strict", "varcov", "means"): the
latent variance/covariance and latent mean invariance levels of Morin's
sequence, for ESEM and B-ESEM under MLR and WLSMV. The default sequence
is unchanged; run_mplus_besem_invariance() mirrors the fitted levels.partial_invariance() follows the partial-invariance rules for ESEM and
B-ESEM. Only level = "strong" (intercepts or thresholds) and
level = "strict" (residual variances) are accepted; level = "weak" is
refused with an explanation, because the rotated loadings are constrained
as a block. Constraints are released one at a time by score test; an item
is released only if every factor it belongs to keeps at least two items
with invariant intercepts/thresholds (Byrne, Shavelson & Muthén, 1989;
van de Schoot, Lugtig & Hox, 2012); releasing more than 20% of the
constraints added at a level warns (Dimitrov, 2010); every released
parameter is listed. On ordinal items at least one threshold per item
stays invariant (Millsap & Yun-Tein, 2004); an item's last threshold can
be released by hand through esem_invariance(..., group.partial =
"item|t1"). Released thresholds are honoured on the ordinal path, the
continuous refit is retried from simple starting values, and B-ESEM is
supported. A recovery test plants intercept shifts on two items in one of
two simulated groups and checks that exactly those items are released, as
intercepts on the continuous path and as thresholds on the ordinal path.start = "simple" starting
values; the alternative is kept when its fit function is lower by more
than 0.1%. The new cores argument (default 2) runs the two starts on
two worker processes at the same time with identical results, so a level
takes as long as its slower start; cores = 1 fits sequentially.align_loadings() compares against another fit, or against a supplied
solution (lambda, psi, theta per group), by orientation transfer:
the unstandardized loadings are rotated to the reference and the factor
covariances are transformed with the same rotation before standardizing.
This is exact in every group, including groups with free factor
covariances, where Procrustes alignment of standardized loadings is not.
An esem_invariance target is read at the requested level.run_mplus_besem_invariance() writes CONVERGENCE = 0.000001 for its
first Mplus attempt; if Mplus does not converge there, the retries start
at Mplus's default and then loosen (1e-4 to 5e-2). When a level's Mplus
run prints no fit (singular information matrix, no DIFFTEST derivatives
file), DIFFTEST is omitted from the next level's input.
extract_mplus_loadings() returns numeric matrices for such outputs.This release contains defensive fixes; estimation results are unchanged.
parameters() on a Heywood-corrected ESEM fit now reports NA for standard
errors, z-values, and p-values when the rotation changed after those
quantities were computed, while retaining the corrected standardized
loadings.factor_scores() now raises an informative error when the polychoric
correlation or score-information matrix is singular, instead of exposing a
bare solve() failure.NA/0 target convention, so primary cells
in targets built that way are freed correctly.factor_scores() now warns when one pooled polychoric matrix is applied
across multiple groups.esem_ordered() and besem_ordered() now stop with a clear message when
supplied item names collide case-insensitively, instead of silently
mismatching them.NA rather than NaN for a degenerate all-zero
loading matrix.Changes in response to CRAN review (no changes to estimation results):
efa().print()/summary() methods now uses message()
(or warning() where appropriate) instead of cat()/print(), so it can
be suppressed with suppressMessages(). Progress output keeps its
verbose gating.parameters() now returns a classed data frame (bifactory_parameters)
that prints the same formatted table via its own print() method.
Assigning the result no longer prints as a side effect..GlobalEnv;
internal fixed-seed sections use withr::with_seed() (new Import: withr).
Draws are unchanged, so results are identical to 0.5.0.lavaan::HolzingerSwineford1939); \dontrun{} is retained only for
examples that require a licensed Mplus installation or open an interactive
editor. Longer-running examples use \donttest{}. No runnable example
uses a package from Suggests.efa() blocks (MLR).Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.