knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
EFAtools exposes its functionality through a set of lowercase efa_* functions:
efa_screen(), efa_retain(), efa_fit(), and so on. Earlier releases used uppercase
names instead (EFA(), N_FACTORS(), OMEGA(), ...). The uppercase names have not been
removed — they still work — but the efa_* functions are now the recommended interface. This
vignette explains the change, gives the full old-to-new mapping, and walks through the
migration with the largest change to the argument list: EFA() to efa_fit().
library(EFAtools)
The efa_* names are the interface we recommend for new code. They read consistently,
share a common prefix that groups them in tab-completion and the documentation index, and
they are where the package's development now happens.
The uppercase names are superseded, not deprecated. In practice that means:
efa_*
functions, so an uppercase name will never grow a new argument.So there is no urgency to rewrite working code. Migrate a script when you want the new functions' additional features (or simply for consistency); until then the old calls remain valid.
Every uppercase function has a lowercase counterpart. For most of them the migration is a pure rename: the arguments are identical and only the name changes.
| Old name | Recommended name |
|---|---|
| EFA() | efa_fit() |
| N_FACTORS() | efa_retain() |
| EFA_AVERAGE() | efa_average() |
| EFA_POOLED() | efa_mi() |
| COMPARE() | efa_compare() |
| SL() | efa_schmid_leiman() |
| OMEGA() | efa_reliability() |
| FACTOR_SCORES() | efa_scores() |
| PROCRUSTES() | efa_procrustes() |
| BARTLETT() | efa_bartlett() |
| KMO() | efa_kmo() |
| PARALLEL() | efa_parallel() |
| EKC() | efa_ekc() |
| KGC() | efa_kgc() |
| HULL() | efa_hull() |
| SCREE() | efa_scree() |
| MAP() | efa_map() |
| NEST() | efa_nest() |
| SMT() | efa_smt() |
| CD() | efa_cd() |
efa_reliability() and efa_scores() are broader than the OMEGA() and FACTOR_SCORES()
they replace, but they cover the same use cases and are the recommended way to obtain those
quantities going forward.
Alongside the renamed functions, the package ships tools that have no uppercase
predecessor — they are new, and available only under the efa_* interface (and the two
control constructors):
| New function | Purpose |
|---|---|
| efa_screen() | Data screening and factorability diagnostics in one report |
| efa_group() | Multigroup EFA with factor congruence |
| efa_simulate() | Simulate data from a factor model |
| efa_power() | Power analysis for EFA |
| estimate_control() | Bundle the estimation tuning knobs (see below) |
| rotate_control() | Bundle the rotation tuning knobs (see below) |
For a plain rename, the call is unchanged apart from the name. For example, the Kaiser-Meyer-Olkin criterion:
cor_mat <- test_models$baseline$cormat # Recommended name -- exactly the same arguments as KMO(): efa_kmo(cor_mat) # The old name still works and returns the same result: identical(KMO(cor_mat)$KMO, efa_kmo(cor_mat)$KMO)
EFA() to efa_fit()EFA() exposed every estimation and rotation setting as a flat argument, which made for a
long and somewhat unwieldy signature. efa_fit() keeps the primary choices — the data,
factor count, sample size, estimator, rotation, and a few others — as top-level arguments
(see ?efa_fit for the full list), and collects the tuning knobs into two small control
objects built by estimate_control() and rotate_control().
Each flat EFA() tuning argument now lives in one of the two controls:
| Control object | Arguments it holds |
|---|---|
| estimate_control() | type, init_comm, criterion, criterion_type, max_iter, abs_eigen, start_method |
| rotate_control() | type, normalize, precision, order_type, varimax_type, p_type, k, random_starts |
A few points make the translation mechanical:
type preset feeds both controls. EFA() had a single type
("EFAtools", "psych", "SPSS", or "none") that governed both estimation and
rotation. Pass the same type to each constructor to reproduce it. Because the two
controls are independent, you can now give them different presets, but you do not have
to.estimator instead of
method — passing method to efa_fit() is an error that points to the new name, while
EFA() keeps its method argument. P_type is now p_type, and randomStarts is now
random_starts; EFA() still accepts those old spellings silently.maxit, gam (oblimin), or delta (geomin) — are passed through rotate_control()'s
... (or, equivalently, efa_fit()'s own ...). Both validate the names: an extra the
selected rotation's engine cannot consume (for example gamma, a misspelling of oblimin's
gam) is rejected with an error, where EFA() silently ignores it.The side-by-side below reproduces an SPSS-style analysis. The old flat call and the new control-based call give identical results:
# Old flat interface efa_old <- EFA(cor_mat, n_factors = 3, N = 500, type = "SPSS") # New interface: the SPSS preset travels through the two control objects efa_new <- efa_fit(cor_mat, n_factors = 3, N = 500, estimate_control = estimate_control(type = "SPSS"), rotate_control = rotate_control(type = "SPSS")) # Identical numerical result all.equal(efa_old$rot_loadings, efa_new$rot_loadings)
An individual knob is set on the control it belongs to. A flat
EFA(..., type = "SPSS", max_iter = 500, k = 3) becomes:
efa_fit(cor_mat, n_factors = 3, N = 500, rotation = "promax", estimate_control = estimate_control(type = "SPSS", max_iter = 500), rotate_control = rotate_control(type = "SPSS", k = 3))
One behavioural difference is worth knowing about. efa_fit() rejects a tuning knob
passed directly, rather than silently ignoring it. This turns a common and previously
invisible mistake into an immediate, informative error that names the constructor the knob
belongs to:
efa_fit(cor_mat, n_factors = 3, N = 500, max_iter = 500) #> Error: `max_iter` cannot be passed to `efa_fit()` directly. #> i The estimation and rotation tuning knobs live in `estimate_control()` and `rotate_control()`. #> i For example: `efa_fit(x, ..., estimate_control = estimate_control(max_iter = 500))`.
The same move — collecting flat estimation knobs into estimate_control() — applies to the
other functions that fit a model internally: efa_retain(), efa_schmid_leiman(), and the
retention criteria that fit a model or use EFA-based eigenvalues — efa_parallel(),
efa_kgc(), efa_scree(), efa_hull(), efa_nest(), and efa_smt(). efa_average() is the
exception: it keeps its flat estimation and rotation arguments, and only renames P_type to
p_type.
type Presets ReplicateThe type presets are more than shorthand for a bundle of defaults. "SPSS" and "psych"
follow how SPSS's FACTOR procedure and psych::fa() implement principal axis factoring and
promax rotation, and "EFAtools", the default, combines the settings that performed best in
a systematic comparison of the three
(Grieder and Steiner, 2022). There is one place a
preset alone is not enough: because every preset keeps EFAtools' Kaiser normalization, "psych"
also needs normalize = FALSE to reproduce psych::fa()'s promax — and even then a small
residual difference remains, from ordinary convergence slack between the two implementations.
Migrating a call does not break code that inspects or dispatches on the result. The renamed
functions attach the legacy class alongside the new one, so inherits() checks and S3
methods written against the old classes keep working — including on objects saved from
earlier sessions.
class(efa_new) inherits(efa_new, "EFA")
The same holds for the other direct renames: efa_retain() objects still inherit
"N_FACTORS", efa_bartlett() still inherits "BARTLETT", and likewise for
efa_kmo(), efa_schmid_leiman(), efa_compare(), efa_average(), and efa_mi(). The
retention criteria (efa_parallel(), efa_ekc(), and the rest) all share the single
efa_retention class they have returned since EFAtools 0.8.0. And the uppercase functions
themselves keep working unchanged: an EFA() call returns the same result as before, now
additionally classed efa so that it picks up the shared methods — inherits() checks
against "EFA" are unaffected.
That is the whole migration: rename the function, and — for EFA() only — move the tuning
knobs into estimate_control() and rotate_control(). For an overview of the full analysis
workflow under the efa_* interface, see the EFAtools vignette; the
individual help pages document each function's arguments in full.
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.