Changelog
Source:NEWS.md
EFAtools 1.1.0.9000
-
efa_fit()changes:- The default rotation is now oblimin (
rotation = "oblimin"). With one factor, no rotation is done.efa_group()andefa_mi()use the same default; for this oblique default,efa_group()aligns the groups to the first group unlessreference_groupis given.EFA()andEFA_POOLED()keep no rotation as their default. - PAF now gives the same chi-square-based fit indices as ULS (chi-square, CFI, TLI, RMSEA, AIC, BIC, ECVI), because a converged PAF solution is the ULS solution (Jöreskog & van Thillo, 1971). Thus, PAF without
Nnow also gives a warning that these indices are not available.efa_average()andefa_mi()report them for PAF too. -
print()shows the chi-square, CFI, TLI, RMSEA, and SRMR.summary()adds AIC, BIC, and ECVI. CAF is not printed, because a correctly specified model gives a CAF near 0.5, not near 1. A CAF that cannot be computed is nowNA, not 0, and gives no warning. - With
se = "np-boot", the bootstrap intervals of RMSEA, CFI, and TLI now come from cases transformed so that their misfit equals the estimated misfit (Yuan, Hayashi, & Yanagihara, 2007). The earlier intervals moved toward worse fit, because each resample added sampling misfit. Their coverage was often much too low (Zhang & Savalei, 2016).print()andsummary()show the intervals of CFI and TLI. The other fit indices no longer get bootstrap standard errors or intervals. The new intervals needcor_method = "pearson", no missing values in the analysed cases, and a chi-square with df > 0; otherwise,SE,CI, andreplicateshave nofit_indices. The additional fits make the bootstrap slower. Inefa_mi(),fit_indices_descriptivenow pools these replicates of RMSEA, CFI, and TLI. - With pairwise deletion of missing values, a new warning (
efa_pairwise_n) shows thatN, the number of rows, overstates the cases behind each correlation, so the chi-square is too large and the standard errors are too small.cor_method = "fiml"(orefa_mi()for ordinal data) avoids this. -
se = "np-boot"with a correlation matrix now gives an error (efa_boot_cormat), as the other unavailable standard-error methods do. -
efa_fit()no longer has.... Give the rotation-engine argumentsgam,delta, andmaxittorotate_control(). - Raw data no longer give the message that correlations are computed from the raw data.
- The parallel workers of the bootstrap now also compute the correlations of the resamples, which take most of the time for polychoric and FIML correlations. A parallel plan is thus much faster there. This change alone leaves the results for a given seed unchanged.
- A fit with
se = "sandwich"no longer returnsGamma, which needs about 11 MB at 50 variables. - The printed header shows
Nand a correlation type other than Pearson, and the Heywood alert names the variables. A just-identified model (df = 0) shows only SRMR and df. - The tables of analytic confidence intervals name their covariance (expected information, robust sandwich, or two-stage FIML sandwich).
-
summary()no longer repeats the simple-structure counts and the largest residual in the model diagnostics; it states when no simple-structure problem occurs.summary(ci = "separate")was removed, because it did the same as"auto". - The message about the rows dropped for an asymptotic covariance now gives their number.
- The default rotation is now oblimin (
A tuning knob set in
estimate_control()orrotate_control()together with atypepreset no longer gives a warning (efa_type_override). The value you set is used.Removed unnecessary warning from
efa_map()that warned when the residual variance reached 0 and thus the search ended early.efa_kgc()now counts the eigenvalues greater than 0, not greater than 1, foreigen_type = "SMC"and"EFA". These eigenvalues come from the reduced correlation matrix, and the cutoff 1 has no basis for it. With SMCs, the number of positive eigenvalues is a lower bound to the number of factors (Guttman, 1954). These types now suggest more factors, often too many in samples."PCA"keeps the cutoff 1. The report and the plot show the cutoff of each type.KGC()andN_FACTORS(criteria = "KGC")change too, and so doesefa_retain()witheigen_type_other = "SMC"or"EFA".efa_hull()no longer gives a warning when it increases the largest number of factors that it fits to 3. This is a rule of the method, not a change to a user setting.efa_nest()andefa_parallel()are much faster for large samples, and so areefa_hull()andefa_retain(), which use them. They now draw each simulated correlation matrix directly from its exact distribution and do not simulate raw data (efa_parallel()does this for Pearson correlations only). The reference eigenvalues have the same distribution as before, but the results for a given seed are different.-
efa_retain()changes:- Parallel analysis, also in the Hull method, now uses PCA eigenvalues by default (
eigen_type_other = "PCA",eigen_type_HULL = "PCA"), not SMC, which often retains too many factors (Lim & Jahng, 2019). The Kaiser-Guttman criterion and the scree plot also use PCA eigenvalues. For the upper bound of the Hull method, parallel analysis now uses the 95th percentile (new argumentdecision_rule_HULL = "percentile"; Lorenzo-Seva et al., 2011);decision_ruleapplies only toPARALLEL, andN_FACTORS()keeps the mean rule for both. - The Hull method now uses only the CAF by default (
gof = "CAF"). With strongly correlated factors, CFI and RMSEA can make the Hull method retain too few factors. The CAF works with every estimator, soestimator = "PAF"no longer gives a message. - Because of these new defaults, the results can be different from earlier versions.
N_FACTORS()keeps the earlier defaults. - With
cor_method = "poly"or"tetra",CDnow runs on the Pearson correlations of the raw data. This is the original method (Ruscio & Roche, 2012): its comparison data resample the observed values. Bartlett’s test also uses the Pearson correlations of the raw data, because its chi-square distribution is not valid for polychoric correlations. - Fewer warnings. Skipped criteria give one warning, and failed criteria give one more. A default criterion that cannot use the input is skipped without a warning; a missing
Nstill gives one. A skipped Bartlett’s test shows only in the report. - An invalid argument (for example
n_datasets = 0) now gives an error before any criterion runs, not a warning that a criterion could not be run. - The Hull method now uses the simulated eigenvalues of the parallel analysis if both run with the same type of eigenvalues, so the simulation runs only once.
- The suitability report is shorter and shows the same lines as
efa_screen(). -
alphais renamed toalpha_CD, which you must give by its full name.alphais deprecated.
- Parallel analysis, also in the Hull method, now uses PCA eigenvalues by default (
efa_hull()now has the same defaults asefa_retain(): the ML estimator, only the CAF (gof = "CAF"), and PCA eigenvalues with the 95th percentile in the parallel analysis that sets the largest number of factors to fit (eigen_type = "PCA",decision_rule = "percentile"; Lorenzo-Seva et al., 2011). Thus, the results can be different from earlier versions.HULL()keeps the earlier defaults (PAF, all three indices, SMC eigenvalues, and the mean rule).efa_power(mode = "simulation")uses the newefa_retain()defaults forKGC,PARALLEL, andHULL, so their variants are nowKGC_PCA,PARALLEL_PCA, andHULL_CAF.-
efa_screen()changes:- Outliers are now detected with the deterministic DetMCD algorithm, so the result is the same on every run and large samples are much faster. The
seedargument is deprecated and has no effect. -
mcd_alphanow defaults to0.75instead of0.5, which flags fewer clean cases. - If any variable is categorical (fewer than ten distinct values), no case is flagged as an outlier. The report names the cases with the largest Mahalanobis distances instead. A chi-square cutoff is not valid for rating-scale data, and it flagged many clean cases when items were skewed.
- The Henze-Zirkler test was removed; Mardia’s tests remain and are much faster in large samples.
- With
cor_method = "poly"or"tetra", the multivariate normality tests are skipped, and the report no longer recommends polychoric correlations for items with few categories. - A non-significant Bartlett’s test now appears in the recommendations, instead of the note that the data appear suitable.
- The multicollinearity recommendation names the variables involved (Belsley’s variance-decomposition proportions), and the report shows the condition index instead of the determinant and the condition number.
- The report is shorter, and conditions that the report already describes no longer also give a warning.
- Outliers are now detected with the deterministic DetMCD algorithm, so the result is the same on every run and large samples are much faster. The
-
efa_reliability()changes:- An
efa_fit()solution with an orthogonal rotation is now scored like an oblique solution, with factor correlations of 0, and a"bifactorT"solution as a bifactor solution. Before, the function refused both. The function now refuses a"bifactorQ"solution (efa_reliability_bifactor_oblique), because its group factors are correlated; before, it scored the general factor as a group factor. It also refuses an unrotated solution with two or more factors (efa_reliability_not_rotated). - Without
factor_map, a loading matrix and the components use their non-zero pattern only if most variables have an exact zero group loading, as in a target matrix. Otherwise, each variable is assigned to the group factor with its largest loading. Before, a loading matrix always used its non-zero pattern, so an estimated bifactor matrix assigned every variable to every group factor; a pattern matrix withPhiand the components always used the largest loading. - A
lavaanfit is now a bifactor solution only if variables load on a factor namedg_nameand on other factors. The function now scores correlated-factors fits with cross-loadings and ESEM fits; before, it refused them. In an ESEM block, each variable is assigned to the factor with its largest loading.OMEGA()refuses such fits withefa_reliability_invalid_lavaan. - The whole-scale omega subscale now counts all group-factor loadings also with
variance = "correlation". Thus, on the whole-scale row, omega total is omega hierarchical plus omega subscale with both settings. Before, it counted only the loadings of the assigned variables, aspsych::omega()does.OMEGA()changes too. - A correlated-factors solution no longer gives omega subscale. Omega subscale is the share in addition to a general factor, and when the factors correlate, it is not a share of the variance (Rodriguez et al., 2016). For a
lavaanfit to a correlation matrix, the omega total of each factor equalssemTools::compRelSEM(fit, obs.var = FALSE). Negatively correlated factors no longer give a false out-of-range warning. - The function no longer gives messages about a single factor, a correlated-factors
lavaanfit, a second-order fit, and variables with fewer than two loadings.print()no longer shows the total-variance line and the note about the omega columns of a correlated-factors solution. - A non-positive residual variance of a variable in a
lavaanfit now gives the Heywood warning of the other inputs, not an error. A non-positive variance or residual variance of a factor still gives an error, with the new classefa_reliability_factor_heywood.OMEGA()changes too, and now gives the Heywood warning also withadd_ind = FALSE. - The result has a new attribute,
factor_map: the assignment of the variables to the group factors that was used. - The mixed-keying warning now also tells what to do when the factors measure opposite constructs.
fac_namesgiven with alavaanfit now gives theefa_reliability_args_ignoredwarning. -
g_load,s_load,var_names, andpatternare deprecated. Give the loadings as one matrix inmodelinstead. - With the largest-loading rule, a variable without a group loading is no longer assigned to the first group factor.
OMEGA()changes too. - Without
factor_map, a Schmid-Leiman solution in which most variables have an exact zero group loading, such as a transformedlavaansolution, now uses its non-zero pattern, as thelavaanfit does. - A
lavaanfit with a negative path between latent variables, in addition to the second-order loadings, now gives the errorefa_reliability_higher_order. Before, it was scored as a second-order model without that path.OMEGA()changes too.
- An
-
efa_schmid_leiman()changes:- For a
lavaansolution whose general factor also loads directly on items, the general-factor loadings now include these direct loadings. Before, they were dropped with a warning, so an item that loads only on the general factor got a general-factor loading and a communality of 0.efa_reliability()andOMEGA()change too for such fits. - A
lavaansolution with more than one second-order factor, other paths between the latent variables, or correlated disturbances now gives an error (efa_sl_higher_order,efa_sl_correlated_factors). Before, the transformation ignored these parts of the model, and the results were wrong without a warning. - The group factors now keep the column order and the names of the input solution, for example the factor names of a
lavaanmodel, or"PA2","PA3","PA1"of apsych::fa()solution. Before, they were sorted by the number in their names and renamed"F1"to"Fk", so an indicator-to-factor map built in the input order could match the wrong factors. If the columns do not have unique names, they are still labelled"F1"to"Fk".SL()changes too. - For a
lavaansolution,orig_Ris now the correlation matrix that the model was fitted to, soefa_reliability()works with its defaultvariance = "correlation". -
g_namenow defaults toNULL: the general factor is the latent variable that loads on the other latent variables.SL()keepsg_name = "g". A multiple-grouplavaanfit now gives the errorefa_sl_multigroup. - A standardized
lavaanloading of 1 or more no longer gives an error. With correlated factors, such a loading can occur in a proper solution. A variance of 0 or less still gives an error. - With two first-order factors, the second-order loadings now get the same absolute value, and their product is the factor intercorrelation, as in
psych::schmid(). No second-order EFA is run for them, and the warning tells this. -
efa_schmid_leiman()no longer has.... Theefa_fit()arguments that it passed on had no effect on the second-order EFA. Give the settings of this EFA inestimate_control(). - A
Phigiven with a fitted solution no longer gives a warning (efa_sl_phi_specified). It replaces the fitted factor intercorrelations. - An
efa_fit()solution withrotation = "bifactorQ"now gives the errorefa_sl_bifactor, because it already has a general factor. - The warnings of the second-order EFA name the first-order factors also for a pattern matrix without names.
-
L2is now a plain matrix with the column"g"and one row for each first-order factor, for every input.settingskeeps only the estimator and the estimation settings of the second-order EFA. -
print()shows the second-order loadings.
- For a
-
efa_simulate()withmarginals = "empirical"changes:- Each dataset is now a new draw of independent cases: normal deviates at an intermediate correlation, each mapped through the empirical quantile function of its column of
marginal_data(Cario & Nelson, 1997). The intermediate correlation of each pair is calculated once from the bivariate normal distribution. Before, the correlations of each dataset were fitted to the population correlation, so the datasets varied less than samples do. This made recovery in simulation studies look too good. - The data now reproduce the population correlation also with model error, or with an
Rthat is not an exact factor structure. Before, only the common-factor part of the population was reproduced. - The rows are now in random order. Before, they were sorted by the last variable.
- A population correlation that two marginals cannot attain now gives an error (
efa_simulate_unattainable_cor). An intermediate correlation matrix that is not positive definite gives an error, or withforce_pd = TRUEis smoothed, as formarginals = "VM". -
n_factorsis deprecated and ignored. - The results for a given seed are different.
- Each dataset is now a new draw of independent cases: normal deviates at an intermediate correlation, each mapped through the empirical quantile function of its column of
efa_cd()generates its comparison-data populations faster, most of all with many variables. The populations have the same distribution as before, but the results for a given seed are different.
EFAtools 1.1.0
CRAN release: 2026-08-21
Comparing and Averaging Solutions
efa_compare()now savesprint(),format(), andplot()display settings, and reuses them.efa_compare()’sare_equalnow returnsNA, not0, when the compared values differ before the decimal point.efa_compare()’s elementwise differences are now signed.efa_compare(reorder = "congruence")now also matches the sign of single-factor solutions.Fixed
efa_compare()’s handling of missing loadings. This previously inflateddiff_corresanddiff_corres_cross.Fixed a bug that could trigger spurious warnings from
efa_average()’s progress bar.
Data Screening and Simulation
Fixed two bugs in
efa_screen()’s outlier detection. Both could give an incorrect or less robust result.efa_screen()’s multicollinearity verdict is now based on the condition index alone, following Belsley (1991).efa_screen()now withholds an uninformative Henze-Zirkler p-value instead of reporting an exact 0 or 1.Mardia’s skewness and kurtosis in
efa_screen()now use small-sample corrections.efa_simulate()gainsmissing_vars, to restrict missingness to selected variables.Fixed
efa_simulate()’s reportedpopulationundermarginals = "VM"andforce_pd = TRUE.
Factor Retention
The
typeargument ofefa_ekc()andekc_typeofefa_retain()no longer have any effect: the empirical Kaiser criterion now always follows Braeken and van Assen (2017). Suggested factor counts can differ from earlier results.efa_nest()results can now be plotted.efa_parallel()now shares simulated reference data between"PCA"and"SMC", roughly halving simulation time. Results for a given seed can differ from before.
Input Validation and Correlation Handling
efa_*arguments with fixed choices are now case-insensitive and accept unambiguous abbreviations.Correlation matrices supplied as data frames are now recognised and analysed correctly.
Correlation-matrix smoothing now consistently returns a positive-definite matrix.
Missing Data and Multiple Imputation
efa_mi()’srmsr_upperargument is deprecated and no longer used.With
target_method = "consensus",efa_mi()’s pooled result no longer depends on the order ofdata_list. Results can differ from earlier versions.efa_mi()’s pooled RMSEA is now capped at 1, and its confidence interval is withheld when it excludes the point estimate.An
efa_mi()solution now reports the Heywood status of each imputation, inmi_admissibility.A
cor_method = "fiml"fit with analytic standard errors now withholds loading standard errors when the rotation is weakly determined, matching the other standard-error methods.
Model Estimation
The
"uls"estimator now minimises the full residual, including the diagonal, matching its analytic gradient. Results can shift for over-factored models.Starting values for the
"paf","ml", and"uls"estimators are now kept within [0, 1], matchingpsych::smc().estimate_control()gainsfiml_max_iterandfiml_tol, to control the FIML algorithm.A
cor_method = "fiml"fit now reports its convergence status in a newfimlcomponent, and warns if it does not converge.An RMSEA confidence interval that cannot be computed is now reported as
NA, instead of stopping the fit.
Ordinal Correlations
Perfectly ordered polychoric or tetrachoric pairs are now reported as
0.9999/-0.9999, with a warning.Binary pairs with an empty response cell now use a margin-preserving continuity correction.
Unavailable asymptotic variances for polychoric or tetrachoric pairs are now reported as
NA, and affected robust standard errors are withheld.Rare response patterns in strongly correlated pairs are now handled more accurately. They less often block
DWLSor robust standard errors.
Power Analysis
efa_power()withgroup > 1now always solves for a whole-number sample size per group.In simulation mode,
efa_power()now reportsNA, not a misleading hit rate, when a retention criterion never gives a suggestion.In simulation mode,
efa_power()now rejects apthat disagrees with the population model, instead of silently replacing it.
Reliability and Factor Scores
efa_reliability()andOMEGA()now compute every omega total from the model’s full implied common variance, including cross-loadings and contributions from other group factors. Results can change for solutions with cross-loadings.The whole-scale row of a correlated-factors solution is now labelled
"total", not"g"/"general", which implied a general factor such solutions do not have.efa_reliability()now recognises several solution types correctly, including Schmid-Leiman tables and single-factor solutions, which were previously misclassified, mislabeled, or refused.efa_scores()andFACTOR_SCORES()withmethod = "Bartlett"or"Anderson"now stop on a communality at or above 1, instead of returning unusable weights.efa_scores()andFACTOR_SCORES()now reject scoring data with a constant, infinite, or too-short variable, instead of silently returningNaNscores.
Rotation
Oblique rotations, including
efa_procrustes(), now refuse a nearly singular transformation matrix at every step. Results can differ for near-degenerate solutions.A gradient-projection rotation is now reported as converged only when its projected gradient meets tolerance. Convergence flags can differ from before.
Standard Errors
efa_fit(se = "sandwich")now withholds standard errors and confidence intervals when a Heywood case occurs.Bootstrap output now reports the number of usable replicates when fewer than requested are available.
Analytic standard-error output now includes factor and variable names in
SE$Phiandvcov_unrot_loadings.
EFAtools 1.0.0
CRAN release: 2026-07-23
New Interface
The recommended interface now consists of lowercase
efa_*functions, with estimation and rotation settings defined throughestimate_control()androtate_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.
Changes When Using the efa_* Interface
The
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()orrotate_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
estimatorrather thanmethod, and rotation arguments use the namesp_typeandrandom_startsrather thanP_typeandrandomStarts.efa_retain()requires the full argument namemax_iter_CD, because the shorter formmax_iteris no longer matched automatically.The second-order estimation preset for
efa_schmid_leiman()is now specified withestimate_control(type = ...).Control objects are validated when they are created, allowing invalid settings to be detected before a model is fitted.
Reproducibility
A supplied
seednow controls the complete analysis, including random rotation starts, bootstrap samples, group-specific fits, and model averaging where applicable.efa_average()now has aseedargument and produces the same result regardless of the number of parallel workers.Seeded results from
efa_parallel()andefa_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 someefa_simulate()settings.
Standard Errors and Fit Statistics
efa_fit(se = "information")now returnsNAwith anefa_se_unreliablewarning 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.
Multiple Imputation and Group Comparisons
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 regularefa_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.
Factor Retention and Rotation
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_startsshould usen_starts_totalorn_optimizedinstead.Criterion-based rotations now respect the specified
maxitlimit during every stage of the optimization.
Model Averaging
efa_average()no longer printsNaN%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.
Data Simulation
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"andmatch = "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.
Input Validation and Correlation Handling
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.
Power Analysis and Factor Scores
efa_power()now clearly documents thatNis the total sample size across groups and returns the corresponding sample size per group inN_per_group.Simulation-based power summaries now distinguish structure-recovery rates from the underlying Tucker congruence values.
The documentation for
FACTOR_SCORES()now correctly describesR2as squared factor-score determinacy.
EFAtools 0.8.0
CRAN release: 2026-07-07
New Functions
-
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.
Changes to Functions
-
EFA():- gains
cor_method = "fiml"for raw data with missing values. - gains
se = "sandwich"andse = "information". - renamed the top-level fields
boot.SE,boot.CI, andboot.arraysonEFAobjects toSE,CI, andreplicates, as the old names are no longer accurate given the additional SE implementations. - All criterion-based rotations are now computed by a built-in gradient-projection rotation engine instead of the
GPArotationpackage. The rotated solutions are numerically equivalent but implemented in C++ for speed to allow high numbers of random starts. - The default number of random starts for the rotation in
EFA()(randomStarts) has been raised from 10 to 100, making local minima less likely for the rotation criteria that are prone to them. - additionally reports the Tucker-Lewis index (TLI, also called the non-normed fit index), the expected cross-validation index (ECVI), and the standardized root mean square residual (SRMR)
- gains a
seedargument and now fits the non-parametric bootstrap replicates (se = "np-boot") in parallel across replicates via thefutureframework. - now has a
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.
- gains
-
EFA_AVERAGE()gainscor_method = "fiml"(passed toEFA()). -
EFA_POOLED():- now dispatches its multiple-imputation standard-error pooling automatically by the standard-error method of its component fits: Rubin’s rules for the information method (with Wald confidence intervals), the two-stage pooled-inputs (MI2S) approach for the sandwich method, and the existing bootstrap pooling for the non-parametric bootstrap method.
- Renamed the top-level field
boot.MItoMI. - now defaults to
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_methodnow 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 byEFA()(including its non-parametric bootstrap),EFA_AVERAGE(), the suitability testsKMO()andBARTLETT(), and the retention criteriaEKC(),KGC(),MAP(),SCREE(),SMT(), andN_FACTORS(). The criteria that compare the data against simulated continuous reference data (CD(),PARALLEL(),NEST(), andHULL()) do not support"poly"/"tetra"and signal an error. - The factor-retention functions
CD(),EKC(),HULL(),KGC(),MAP(),NEST(),PARALLEL(),SCREE(), andSMT()now return objects of a commonefa_retentionclass with sharedprint()andplot()methods. -
COMPARE()objects now have aplot()method that returns aggplotobject. The plot is no longer drawn as a side effect ofprint(). - Console output (the
print,summary, andformatmethods) is now produced with theclipackage, and the messages, warnings, and errors emitted across the package are now S3-classed conditions, which makes them easier to handle programmatically. -
EFA(),SL(), andEFA_AVERAGE()now acceptmethod = "MINRES"as a synonym formethod = "ULS". Minimum residual and unweighted least squares are two names for the same estimator and return identical results.
Bug Fixes
-
EFA()andEFA_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 matcheslavaan. 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 pooledFm. -
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()withmethod = "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. -
ULSextraction: 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()andPARALLEL(): A failed eigendecomposition of a degenerate simulated matrix now raises a clear error instead of resulting in undefined behaviour. - The chi-square model-fit statistic is now the Bartlett-corrected maximum likelihood discrepancy evaluated at the model-implied correlation matrix, for both
MLandULSextraction. Formethod = "ML"this matchesstats::factanal()andpsych::fa(); the small-sample Bartlett correction was previously omitted. Formethod = "ULS"it is now a proper chi-square-distributed statistic matchingpsych::fa(fm = "minres"); previously the least-squares residual sum of squares was multiplied byN - 1and 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 bySMT()andHULL()may change for these methods. -
PARALLEL(): The percentile reference eigenvalues are now computed withstats::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 withorder_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 androtmat. 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 byHULL()(and hence byN_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 silentNA(matching the convention used byEKC()). -
EFA(se = "np-boot"): The non-parametric bootstrap no longer repeats per-replicate warnings (about arguments pinned alongsidetype, 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(): Withreorder = "congruence", the columns ofyare now matched to those ofxby 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 ofxto the same column ofy, 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.
EFAtools 0.7.1
CRAN release: 2026-05-08
Changes to Functions
-
EFA(): AddedrandomStartsargument passed to GPArotation functions, as suggested by Coen Bernaards. -
FACTOR_SCORES(): Addedrhoargument, thanks to Andreas Soteriades. -
EFA_POOLED(): Fixed issue that could lead to averaged Phi not being symmetric.
EFAtools 0.7.0
CRAN release: 2026-04-30
New Functions
-
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 fromprint.EFA()
Changes to Functions
-
N_FACTORS()can also compute the MAP criterion. -
EFA():- Now returns and prints residuals and, if SEs are computed, standardized residuals.
- Calculates and prints RMSR.
- Can calculate bootstrap standard errors and CIs of parameters and fit indices.
-
print.EFA()now prints more information.
Bug Fixes
- Fixed a bug in
OMEGA()that led to incorrect omega, H, and ECV values forlavaanbifactor models. Tnanks to Christopher D. King for bug report and suggested fix. - Small fix in the documentation of
EFA_AVERAGE(). - Fixed incorrect calculation of RMSEA in
EFA().
EFAtools 0.6.1
CRAN release: 2025-07-30
Changes to Functions
-
EKC(): Now correctly returns the number of factors based on the first time the eigenvalues drop below the references values.
EFAtools 0.6.0
CRAN release: 2025-06-19
New Functions
- Added
NEST()to perform the Next Eigenvalue Sufficiency Test (Achim, 2017).
Changes to Functions
-
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 newtypeargument. 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():- Updated default settings to only use often used and well performing factor retention methods (others, like the Kaiser Guttman criterion can still be used).
- Added NEST as additional factor retention method.
- New arguments:
ekc_type,alpha_nest, andn_datasets_nestto account for the changes inEKC()and to controlNEST().
EFAtools 0.5.0
CRAN release: 2025-05-23
Changes to Functions
-
print.EFA():- Now returns explained variance from rotated, rather than unrotated solution, if a rotation was performed.
- Now prints communalities and uniquenesses in loading/pattern matrix
-
EFA(): Calculate and return model implied correlation matrix.
EFAtools 0.4.5
CRAN release: 2024-12-22
Bug Fixes
- Updated
OMEGA()to accommodate changes in the upcoming version ofpsych::schmid()
EFAtools 0.4.4
CRAN release: 2023-01-06
Changes to Functions
-
print.EFA(): Added argumentscutoff,digitsandmax_name_lengththat are passed toprint.LOADINGS(). -
print.LOADINGS(): New Argumentmax_name_lengthto 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).
Misc
- Updated a test of a helper function (
.gof()) that threw an error when using R-devel on x86_64 Fedora 36 Linux with alternative BLAS/LAPACK. - added
dontrunto examples ofEFA_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.
EFAtools 0.4.2
CRAN release: 2022-09-27
Changes to Functions
-
.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.
EFAtools 0.4.0
CRAN release: 2022-03-21
Changes to Functions
-
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 settingadd_ind = FALSE.
EFAtools 0.3.1
CRAN release: 2021-03-27
General
- When testing for whether a matrix is singular and thus smoothing should be done, test against .Machine$double.eps^.6 instead of 0, as suggested by Florian Scharf.
Changes to Functions
-
EFA():- Added warnings if
type = "SPSS"was used withmethod = "ML"ormethod = "ULS", or with a rotation other thannone,varimaxorpromax. - Avoided smoothing of non-positive definite correlation matrices if
type = "SPSS"is used. - Use Moore-Penrose Pseudo Inverse in computation of SMCs if
type = "psych"is used, by callingpsych::smc(). - Use
varimax_type = "kaiser"iftype = "EFAtools"is used withvarimaxorpromax.
- Added warnings if
Bug Fixes
-
EFA_AVERAGE():- Added
future.seed = TRUEto call tofuture.apply::future_lapply()to prevent warnings. - 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.eps
- Added
-
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.eps -
OMEGA(): Small bugfix whenlavaansecond-order model is given as input
EFAtools 0.3.0
CRAN release: 2020-11-04
General
- Added examples for
EFA_AVERAGE()to readme and the EFAtools vignette - Updated examples in readme and vignettes according to the updated
OMEGAfunction
New Functions
- Added function
EFA_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.
Changes to Functions
-
EFA(): Defaults that were previously set toNULLare now mostly set toNA. This was necessary forEFA_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 argumentfactor_corresfrom 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.
EFAtools 0.2.0
CRAN release: 2020-09-17
General
- Created new vignette Replicate_SPSS_psych to show replication of original
psychandSPSSEFA solutions withEFAtools.
New Functions
- Added function
FACTOR_SCORES()to calculate factor scores from a solution fromEFA(). This is just a wrapper for thepsych::factor.scoresfunction. - Added function
SCREE()that does a scree plot. Also added respective print and plot methods.
Changes to Functions
-
CD(): Added check for whether entered data is a tibble, and if so, convert to vanilla data.frame to avoid breaking the procedure. -
EFA():- Updated the EFAtools type in PAF and Promax.
- Added p value for chi square value in output (calculated for ML and ULS fitting methods).
- Updated the SPSS varimax implementation to fit SPSS results more closely.
- Created an argument “varimax_type” that is set according to the specified type, but that can also be specified individually. With type R psych and EFAtools, the stats::varimax is called by default (
varimax_type = "svd"), with type SPSS, the reproduced SPSS varimax implementation is used (varimax_type = "kaiser"). - Renamed the
kaiserargument (controls if a Kaiser normalization is done or not) intonormalizeto avoid confusion with thevarimax_typeargument specifications.
-
ML(): Changed default start method to “psych”. -
N_FACTORS():- Added option to do a scree plot if “SCREE” is included in the
criteriaargument. - Added a progress bar.
- Added option to do a scree plot if “SCREE” is included in the
-
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).
Bug Fixes
-
.get_compare_matrix(): Fixed a bug that occurred when names of data were longer than n_char -
COMPARE(): Fixed a bug that occurred when usingreorder = "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 HULL -
KMO(): Fixed a bug that the inverse of the correlation matrix was not taken anew after smoothing was necessary. -
PARALLEL():- Fixed a bug that occurred when using
decision_rule = "percentile" - Relocated error messages that were not evaluated if no data were entered (and should be)
- Fixed a bug that occurred when using
-
print.COMPARE(): Fixed a bug that occurred when usingprint_diff = FALSEinCOMPARE(). -
print.KMO(): Fixed a bug that printed two statements instead of one, when the KMO value was < .6.
EFAtools 0.1.1
CRAN release: 2020-07-13
Minor Changes
- Added an error message in
PARALLEL()if no solution has been found after 25 tries.
Bug Fixes
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.