The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.
The recommended interface now consists of lowercase
efa_* functions, with estimation and rotation settings
defined through estimate_control() and
rotate_control().
The existing uppercase functions remain available without
warnings, so current scripts continue to work, but new features will
generally be added only to the efa_* interface.
Estimators, rotations, retention criteria, scoring methods, and presets can now be specified without matching capitalization exactly, while results continue to store and display the standard spelling.
efa_* InterfaceThe efa_* functions now report an error for unused,
misspelled, or misplaced arguments instead of silently ignoring
them.
Estimation and rotation options such as convergence settings,
iteration limits, and rotation parameters should now be supplied through
estimate_control() or
rotate_control().
Factor-retention functions always fit unrotated models and therefore reject rotation settings that would not affect the retention result.
The estimator argument is now named estimator rather
than method, and rotation arguments use the names
p_type and random_starts rather than
P_type and randomStarts.
efa_retain() requires the full argument name
max_iter_CD, because the shorter form max_iter
is no longer matched automatically.
The second-order estimation preset for
efa_schmid_leiman() is now specified with
estimate_control(type = ...).
Control objects are validated when they are created, allowing invalid settings to be detected before a model is fitted.
A supplied seed now controls the complete analysis,
including random rotation starts, bootstrap samples, group-specific
fits, and model averaging where applicable.
efa_average() now has a seed argument
and produces the same result regardless of the number of parallel
workers.
Seeded results from efa_parallel() and
efa_hull() no longer depend on the parallel-processing
setup.
Because random-number handling and several calculations were
corrected, the same seed may produce different results than in earlier
versions for efa_parallel(), efa_hull(),
efa_average(), efa_group(), and some
efa_simulate() settings.
efa_fit(se = "information") now returns
NA with an efa_se_unreliable warning when
standard errors for unrotated loadings cannot be estimated reliably,
such as for Heywood cases or poorly distinguished factors.
Information-based standard errors are now calculated for correlation matrices rather than covariance matrices, improving their accuracy and agreement with sandwich and bootstrap estimates.
Information-based standard errors are now supported only with
Pearson correlations and FIML; use se = "sandwich" for
polychoric, tetrachoric, or rank correlations.
FIML-based analytic standard errors now use the same small-sample scaling as the package’s other standard errors and fit statistics.
efa_mi() no longer reports AIC, BIC, or ECVI when
these measures are not meaningful for the underlying fitted
models.
The pooled unrotated solution from efa_mi() no
longer depends on the order of the imputed datasets.
Pooled unrotated loadings from efa_mi() now use the
same orientation conventions as a regular efa_fit() result,
making the two easier to compare.
These changes can affect unrotated loadings, their standard errors, and statistics derived from them, but rotated solutions and their fit indices remain unchanged.
Consensus results from efa_group() no longer depend
on the order in which groups are supplied, so congruences, loading
differences, salience classifications, and invariance conclusions are
now stable across group orderings.
Fixed a regression in the revised MAP criterion, which could previously suggest an incorrect number of factors.
efa_smt() now rejects polychoric and tetrachoric
correlations because its tests and fit measures are not valid for these
inputs.
Rotated factors are now labelled F1,
F2, and so forth according to the variance they explain,
rather than inheriting labels that could change with the random
seed.
Rotation diagnostics now distinguish between the total number of
starting solutions and the number that were fully optimized; code using
n_starts should use n_starts_total or
n_optimized instead.
Criterion-based rotations now respect the specified
maxit limit during every stage of the
optimization.
efa_average() no longer prints NaN%
when no models converge and now clearly states which fitted models are
included in each reported rate.
Named presets such as "SPSS", "psych",
and "EFAtools" now use their intended iteration limits, so
models that exceed those limits are marked as non-converged and excluded
from the average.
Cudeck–Browne model-error simulations are now reproducible across computing platforms and numerical libraries, although a given seed will produce different populations than in earlier versions.
With marginals = "VM", categorized data now
reproduce the requested category proportions more accurately, with a
warning when the requested thresholds cannot be transformed
safely.
The documentation now clarifies that
match = "thresholds" and match = "polychoric"
produce the same data for normal marginals, and the selected value is
now stored in the result settings.
The documentation now explains the missing-data mechanism
produced by missing = "MAR" and the residual bias it may
create for analyses based only on the observed data.
The documentation now explains that
model_error = "WB" generally produces a larger RMSEA for
the generating model than the requested target.
efa_screen() now handles collinear or nearly
collinear variables without failing during its outlier checks.
Polychoric covariance calculations now handle sparse or nearly perfectly associated response tables more consistently, allowing DWLS analyses to continue while warning about problematic variable pairs.
Covariance matrices supplied where raw data or a correlation
matrix is expected are now rejected with a message suggesting
cov2cor().
Polychoric and tetrachoric correlations now require ordered factors or numeric response codes, preventing character or unordered-factor levels from being interpreted in alphabetical order.
efa_power() now clearly documents that
N is the total sample size across groups and returns the
corresponding sample size per group in
N_per_group.
Simulation-based power summaries now distinguish structure-recovery rates from the underlying Tucker congruence values.
The documentation for FACTOR_SCORES() now correctly
describes R2 as squared factor-score determinacy.
efa_group() performs multi-group EFA.efa_power() to conduct power analysis (analytic power
based on RMSEA and simulation based power analysis).efa_reliability() to calculate various reliability
indices.efa_screen() to screen data for multivariate normality
and suitability for factor analysis.efa_simulate() to simulate data with various
distributions and missing data mechanisms.EFA():
cor_method = "fiml" for raw data with missing
values.se = "sandwich" and
se = "information".boot.SE,
boot.CI, and boot.arrays on EFA
objects to SE, CI, and
replicates, as the old names are no longer accurate given
the additional SE implementations.GPArotation package. The rotated solutions are numerically
equivalent but implemented in C++ for speed to allow high numbers of
random starts.EFA() (randomStarts) has been raised from 10
to 100, making local minima less likely for the rotation criteria that
are prone to them.seed argument and now fits the non-parametric
bootstrap replicates (se = "np-boot") in parallel across
replicates via the future framework.summary() method that prints the full,
detailed solution (loadings with communalities and uniquenesses,
explained variances, fit indices, and residuals); print()
now gives a more compact overview.EFA_AVERAGE() gains cor_method = "fiml"
(passed to EFA()).EFA_POOLED():
boot.MI to
MI.target_method = "first_target", which
aligns every imputation to the first imputation’s rotated solution with
a single Procrustes rotation. For orthogonal rotations this reaches the
same pooled estimate as "consensus" with substantially less
work. "consensus" (Generalized Procrustes Analysis of the
imputation-specific rotated loadings) is still available as an opt-in
for orthogonal rotations, and now raises a classed condition
(efa_consensus_oblique_unsupported) when combined with an
oblique rotation, because the iterated-oblique-Procrustes centroid can
drift to degenerate targets.cor_method now accepts "poly" and
"tetra" to compute polychoric and tetrachoric correlations
from raw ordinal (respectively binary) data, using a two-step estimator
with no empty-cell continuity correction. Supported by
EFA() (including its non-parametric bootstrap),
EFA_AVERAGE(), the suitability tests KMO() and
BARTLETT(), and the retention criteria EKC(),
KGC(), MAP(), SCREE(),
SMT(), and N_FACTORS(). The criteria that
compare the data against simulated continuous reference data
(CD(), PARALLEL(), NEST(), and
HULL()) do not support "poly" /
"tetra" and signal an error.CD(),
EKC(), HULL(), KGC(),
MAP(), NEST(), PARALLEL(),
SCREE(), and SMT() now return objects of a
common efa_retention class with shared print()
and plot() methods.COMPARE() objects now have a plot() method
that returns a ggplot object. The plot is no longer drawn
as a side effect of print().print, summary, and
format methods) is now produced with the cli
package, and the messages, warnings, and errors emitted across the
package are now S3-classed conditions, which makes them easier to handle
programmatically.EFA(), SL(), and
EFA_AVERAGE() now accept method = "MINRES" as
a synonym for method = "ULS". Minimum residual and
unweighted least squares are two names for the same estimator and return
identical results.EFA() and EFA_POOLED(): The comparative
fit index (CFI) now floors the model and baseline noncentralities at
zero before taking their ratio (Bentler, 1990), so it is no longer
deflated toward zero when the baseline (independence) model fits
comparatively well. The value is unchanged for well-fitting models and
now matches lavaan. CFI can change for solutions in which
the baseline model does not misfit much.EFA_POOLED(): Corrected and extended the pooled
chi-square-based model-fit indices. The D2 average relative increase in
variance is now centred on the mean of the square-root statistics (Li,
Meng, Raghunathan & Rubin, 1991), removing a one-sided inflation of
the pooled chi-square, RMSEA, and CFI. Bootstrap/MI confidence intervals
for the pooled fit indices are now the Rubin-Wald multiple-imputation
summaries; a miscalibrated bootstrap-percentile interval (obtained by
re-running the pooling algorithm over matched replicate indices) was
removed, as was a mislabeled pooled Fm.EFA_AVERAGE(): When every averaged solution fails (all
runs error, fail to converge, or are Heywood cases), the function now
returns an empty (NA) averaged result instead of erroring
or averaging an empty set.EFA() with method = "PAF": the reported
number of iterations (iter) is now the number of iterations
actually performed; it was previously one too high. The loadings,
communalities, and convergence status are unchanged.ULS extraction: the minimised objective is now the sum
of squared off-diagonal residuals, consistent with its analytic gradient
and the reported minimum (Fm). The diagonal residuals were
previously included in the objective but not in its gradient. The fitted
loadings are unchanged to within optimiser tolerance.NEST() and PARALLEL(): A failed
eigendecomposition of a degenerate simulated matrix now raises a clear
error instead of resulting in undefined behaviour.ML and ULS
extraction. For method = "ML" this matches
stats::factanal() and psych::fa(); the
small-sample Bartlett correction was previously omitted. For
method = "ULS" it is now a proper chi-square-distributed
statistic matching psych::fa(fm = "minres"); previously the
least-squares residual sum of squares was multiplied by
N - 1 and read as if it were Wishart-distributed, which
produced an invalid p-value. The independence (baseline) model used for
the CFI is rescaled onto the same discrepancy scale. Consequently the
p-value, CFI, RMSEA (and its confidence interval), AIC, and BIC change
for ML and ULS solutions, and the number of factors suggested by
SMT() and HULL() may change for these
methods.PARALLEL(): The percentile reference eigenvalues are
now computed with stats::quantile(), correcting a slight
off-by-one in the previous indexing.EFA(): For oblique rotations, the factor
intercorrelations (Phi), the structure matrix, and the
explained variances are now reflected and reordered consistently with
the rotated loadings. Previously, when a factor was reflected to a
positive orientation the factor intercorrelations were not sign-adjusted
(so the structure matrix and reported correlations did not match the
loadings), and with order_type = "ss_factors" the factor
intercorrelations were not reordered at all.EFA(): The returned rotation matrix
(rotmat) is now reflected and reordered consistently with
the rotated loadings, for both orthogonal and oblique rotations, so that
the rotated loadings can be reconstructed from the unrotated loadings
and rotmat. Previously the sign reflection was not applied
to it and its factors were left in a different order, so this
reconstruction did not hold whenever a factor was reflected or
reordered.HULL(): The convex-hull elimination now tests every
triplet of adjacent solutions, including the one formed by the last
interior solution. Previously this final triplet was skipped, so a
solution lying below the line connecting its neighbours could remain on
the hull. This can change the number of factors suggested by
HULL() (and hence by N_FACTORS()).NEST(): When the test accepts every eigenvalue it
examines (no empirical eigenvalue falls at or below its reference within
the search range), it now retains that last accepted model rather than
the model with one fewer factor. The search range is also bounded so
that the reference model fitted at each step stays over-identified.PARALLEL(): When every real eigenvalue exceeds its
reference, so the decision rule finds no crossing, the suggested number
of factors is now all retained components, reported with a warning,
instead of a silent NA (matching the convention used by
EKC()).EFA(se = "np-boot"): The non-parametric bootstrap no
longer repeats per-replicate warnings (about arguments pinned alongside
type, and about the iterative fit reaching its maximum
number of iterations) once per replicate. They are now suppressed during
resampling, and non-convergence across replicates is reported once as a
summary.COMPARE(): With reorder = "congruence",
the columns of y are now matched to those of x
by an optimal one-to-one assignment that maximizes the total Tucker
congruence, rather than by an independent per-factor best match. The
greedy match could assign two factors of x to the same
column of y, duplicating that column and dropping another,
which corrupted the reported differences, factor correspondences, and
root mean squared distance. The result is unchanged whenever the greedy
match was already one-to-one.EFA(): Added randomStarts argument passed
to GPArotation functions, as suggested by Coen Bernaards.FACTOR_SCORES(): Added rho argument,
thanks to Andreas Soteriades.EFA_POOLED(): Fixed issue that could lead to averaged
Phi not being symmetric.MAP() computes the Velicer MAP criterion (both TR2 and
TR4).PROCRUSTES() to perform orthogonal and oblique
Procrustes / target rotation.CONSENSUS_PROCRUSTES() to perform Procrustes on a list
of targets to obtain a common target.residuals.EFA() to extract and print residuals and, if
computed, standardized residuals.EFA_POOLED() to run EFA on a list of multiple imputated
datasets and pool the results. Thanks to Andreas Soteriades for the
suggestion and first implementation.print.EFA_POOLED(), print method adapted from
print.EFA()N_FACTORS() can also compute the MAP criterion.EFA():
print.EFA() now prints more information.OMEGA() that led to incorrect omega, H,
and ECV values for lavaan bifactor models. Tnanks to
Christopher D. King for bug report and suggested fix.EFA_AVERAGE().EFA().EKC(): Now correctly returns the number of factors
based on the first time the eigenvalues drop below the references
values.NEST() to perform the Next Eigenvalue Sufficiency
Test (Achim, 2017).EKC(): The implementation based on Auerswald and
Moshagen (2019) used in previous versions differed from the original
implementation by Braeken and van Assen (2017). Now both versions are
implemented and can be selected with the new type argument.
Thanks to Luis Eduardo Garrido for pointing this out and to Johan
Braeken for sharing sample code, based on which the original version is
now implemented.N_FACTORS():
ekc_type, alpha_nest, and
n_datasets_nest to account for the changes in
EKC() and to control NEST().print.EFA():
EFA(): Calculate and return model implied correlation
matrix..gof(): Changed some tests to
take care of the ATLAS issue when using R-devel on x86_64 Fedora 34
Linux with alternative BLAS/LAPACK.OMEGA() to accommodate changes in the upcoming
version of psych::schmid()print.EFA(): Added arguments cutoff,
digits and max_name_length that are passed to
print.LOADINGS().print.LOADINGS(): New Argument
max_name_length to control the maximum length of the
displayed variable names (names longer than this will be cut on the
right side). Previously, this was fixed to 10 (which is now the
default)..gof()) that threw
an error when using R-devel on x86_64 Fedora 36 Linux with alternative
BLAS/LAPACK.dontrun to examples of EFA_AVERAGE()
and its print and plot methods as these were causing issues on R-oldrel
which were not directly related to EFAtools and thus could not be fixed
from within the package..gof(): Changed the helper function to take care of the
MKL issue when using R-devel on x86_64 Fedora 34 Linux with alternative
BLAS/LAPACK..is_cormat(): Changed the helper function to better
detect wheter a matrix is a correlation matrix.PARALLEL(): Added a check, testing whether N >
n_vars and throw an error if this is not the case.EFA(): Changed error to warning when model is
underidentified. This allows the Schmid-Leiman transformation to be
performed on a two-factor solution.OMEGA(): Added calculation of additional indices of
interpretive relevance (H index, explained common variance [ECV], and
percent of uncontaminated correlations [PUC]). This is optional and can
be avoided by setting add_ind = FALSE.CD(): Added na.omit() to remove missing
values from raw data to avoid an error in the comparison-data
procedure.EFA():
type = "SPSS" was used with
method = "ML" or method = "ULS", or with a
rotation other than none, varimax or
promax.type = "SPSS" is used.type = "psych" is used, by calling
psych::smc().varimax_type = "kaiser" if
type = "EFAtools" is used with varimax or
promax.EFA_AVERAGE():
future.seed = TRUE to call to
future.apply::future_lapply() to prevent warnings.print.EFA(): Fixed test for Heywood cases from testing
whether a communality or loading is greater than .998, to only test
whether communalities exceed 1 + .Machine$double.epsOMEGA(): Small bugfix when lavaan
second-order model is given as inputEFA_AVERAGE() to readme and the
EFAtools vignetteOMEGA functionEFA_AVERAGE() and respective print and
plot methods, to allow running many EFAs across different
implementations to obtain an average solution and test the stability of
the results.EFA(): Defaults that were previously set to
NULL are now mostly set to NA. This was
necessary for EFA_AVERAGE() to work correctly.PARALLEL(): Rewrote the generation of random data based
eigenvalues to be more stable when SMCs are used.OMEGA(): Changed expected input for argument
factor_corres from vector to matrix. Can now be a logical
matrix or a numeric matrix with 0’s and 1’s of the same dimensions as
the matrix of group factor loadings. This is more flexible and allows
for cross-loadings.psych and SPSS EFA
solutions with EFAtools.FACTOR_SCORES() to calculate factor
scores from a solution from EFA(). This is just a wrapper
for the psych::factor.scores function.SCREE() that does a scree plot. Also
added respective print and plot methods.CD(): Added check for whether entered data is a tibble,
and if so, convert to vanilla data.frame to avoid breaking the
procedure.EFA():
varimax_type = "svd"), with type SPSS, the reproduced SPSS
varimax implementation is used
(varimax_type = "kaiser").kaiser argument (controls if a Kaiser
normalization is done or not) into normalize to avoid
confusion with the varimax_type argument
specifications.ML(): Changed default start method to “psych”.N_FACTORS():
criteria argument.OMEGA(): Now also works with a lavaan second-order
solution as input. In this case, it does a Schmid-Leiman transformation
based on the first- and second-order loadings first and computes omegas
based on this Schmid-Leiman solution.SL(): Now also works with a lavaan second-order
solution as input (first- and second-order loadings taken directly from
lavaan output)..get_compare_matrix(): Fixed a bug that occurred when
names of data were longer than n_charCOMPARE(): Fixed a bug that occurred when using
reorder = "names".EFA(): RMSEA is now set to 1 if it is > 1.HULL(): Fixed a bug that occurred when no factors are
located on the HULLKMO(): Fixed a bug that the inverse of the correlation
matrix was not taken anew after smoothing was necessary.PARALLEL():
decision_rule = "percentile"print.COMPARE(): Fixed a bug that occurred when using
print_diff = FALSE in COMPARE().print.KMO(): Fixed a bug that printed two statements
instead of one, when the KMO value was < .6.OMEGA() and SL(): Added an error message
if the entered term in g_name is invalid (i.e., it cannnot
be found among the factor names of the entered lavaan solution).PARALLEL() if no solution has
been found after 25 tries.Updated different tests
Deleted no longer used packages from Imports and Suggests in DESCRIPTION
PARALLEL(): fixed a bug in indexing if method
"EFA" was used.
NEWS.md file to track changes to the
package.These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.