sfa: Semantic Factor Analysis

View source: R/sfa.R

sfaR Documentation

Semantic Factor Analysis

Description

Performs exploratory factor analysis on language model embeddings of scale items. Given item text, sfa embeds each item, transforms embeddings into a similarity matrix, and runs EFA to recover latent factor structure entirely from the text.

Usage

sfa(
  items,
  nfactors = NULL,
  rotate = "oblimin",
  fm = "minres",
  encoding = "atomic",
  embed = "sbert",
  model = NULL,
  embeddings = NULL,
  similarity = NULL,
  scoring = NULL,
  n_factors_method = "parallel",
  dim_select = c("none", "dynega"),
  n.obs = NA,
  parallel_iter = 100L,
  seed = 42L,
  calibrate = FALSE,
  calibrate_iter = 100L,
  label_factors = FALSE,
  leximax = list(),
  ...
)

Arguments

items

Character vector of item text, or a data.frame with an item (or text) column and optional code, factor, scoring columns.

nfactors

Integer number of factors to extract, or NULL for automatic determination via n_factors_method.

rotate

Rotation method passed to fa. Default "oblimin" (requires GPArotation, which is in Imports).

fm

Extraction method passed to fa. Default "minres".

encoding

Similarity transform: "atomic" (default), "atomic_reversed", "squid", or "mean_centered_pearson". Use "atomic_reversed" with a scoring vector to sign-flip reverse-keyed items. See sfa_similarity.

embed

Embedding backend: "sbert", "openai", or a function. Ignored when embeddings is provided.

model

Model name for the embedding backend. If NULL (default), resolves to a backend-appropriate default: "Qwen/Qwen3-Embedding-0.6B" (about 1.2 GB) for "sbert" and "text-embedding-3-small" for "openai". The sbert default is chosen to run on any machine. Larger embedding models recover factor structure more accurately; for higher fidelity pass "Qwen/Qwen3-Embedding-4B" (about 8 GB RAM) or "Qwen/Qwen3-Embedding-8B" (about 16 GB RAM). When the default model is used, print() reminds you of these options.

embeddings

Optional precomputed numeric matrix (n_items x embedding_dim). When supplied, skips the embedding step entirely.

similarity

Optional precomputed symmetric item-by-item similarity matrix (n_items x n_items). When supplied, embedding and the encoding transform are skipped and this matrix is used directly — e.g. a signed NLI matrix from sfa_nli_matrix. Parallel analysis is unavailable in this mode (no embeddings), so retention falls back to "kaiser" unless nfactors is set.

scoring

Numeric vector of +1/-1 per item. If NULL, defaults to all +1 with an informative message for encoding methods that use it.

n_factors_method

Retention rule when nfactors = NULL: "parallel" (embedding-adapted, default), "kaiser", "EGA", "TEFI", or "semk" (calibrated semantic retention via the learned sem-k rule; see sfa_semk() — requires Python and a one-time model download).

dim_select

Embedding-dimension selection before analysis: "none" (default, use the full vector) or "dynega" (select the leading-coordinate depth that best recovers structure by EGA-based depth optimization, adapting Golino 2026; see sfa_dimselect). Requires EGAnet.

n.obs

Sample size passed to fa. NA (default) suppresses sample-size-dependent fit indices.

parallel_iter

Iterations for embedding parallel analysis.

seed

Random seed for stochastic operations, used via with_seed without touching the global RNG state.

calibrate

Logical: run an isotropic random-embedding Monte Carlo null calibration of the fit diagnostics? (Inspired by Pokropek 2026, but using a random-Gaussian unit-vector null rather than Pokropek's corpus-word resampling. The two nulls differ in kind: corpus resampling preserves the baseline thematic similarity that all words in a topic-specific corpus share, whereas the Gaussian unit-vector null has zero expected inter-item similarity and is therefore a stricter, structure-free reference.)

calibrate_iter

Iterations for calibration.

label_factors

If TRUE, run sfa_name() on the fitted object with default settings and store the result as $labels. Requires the candidate pool for the embedding model (fetched on first use; see sfa_pool()). Default FALSE.

leximax

Options list for rotate = "leximax", ignored otherwise. Recognized entries: lexmap (a precomputed sfa_lexmap() object; built automatically when absent), model, instruction, pool, and block_size (forwarded to sfa_lexmap()), plus n_random, seed, col_scale, rotation, normalize, and max_iter (forwarded to sfa_leximax()).

...

Additional arguments passed to fa.

Value

An object of class "sfa" containing factor loadings, communalities, eigenvalues, variance accounted for, and embedding-specific diagnostics (KMO, TEFI, RMSR, CAF, McDonald's omega). The $loadings component has class "loadings" and works with factor.congruence and fa.sort. Use as_psych to obtain the underlying psych::fa object.

References

Milano, N., Luongo, M., Ponticorvo, M., & Marocco, D. (2025). Semantic analysis of test items through large language model embeddings predicts a-priori factorial structure of personality tests. Current Research in Behavioral Sciences, 8, 100168. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1016/j.crbeha.2025.100168")}

Casella, M., Luongo, M., Marocco, D., Milano, N., & Ponticorvo, M. (2024). LLM embeddings on test items predict post hoc loadings in personality tests. Ital-IA 2024: 4th National Conference on Artificial Intelligence, CEUR Workshop Proceedings.

Guenole, N., D'Urso, E. D., Samo, A., Sun, T., & Haslbeck, J. M. B. (Preprint). Enhancing Scale Development: Pseudo Factor Analysis of Language Embedding Similarity Matrices. OSF. https://osf.io/3mpzb/

Pellert, M., Lechner, C. M., Sen, I., & Strohmaier, M. (2026). Neural network embeddings recover value dimensions from psychometric survey items on par with human data. Findings of the Association for Computational Linguistics: EACL 2026, 5738–5752.

Pokropek, A. (2026). From keyword-based text measures to latent variables: Confirmatory factor analysis with word embeddings. EPJ Data Science. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1140/epjds/s13688-026-00654-1")}

See Also

sfa_similarity, sfa_parallel, sfa_nfactors, sfa_embed, sfa_congruence, as_psych

Examples

data(big5)
# nfactors = 5 keeps this example fast; omit it to let embedding-adapted
# parallel analysis (sfa_parallel) choose the number of factors.
fit <- sfa(big5$items, embeddings = big5$embeddings, scoring = big5$scoring,
           nfactors = 5)
print(fit)
plot(fit, type = "scree")


semanticfa documentation built on Sept. 2, 2026, 1:07 a.m.