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
areprone 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.