knitr::opts_chunk$set(collapse = TRUE, comment = "#>", eval = FALSE)
Semantic factor analysis extracts factors from the meaning of scale items.
sfa_name() completes the workflow by giving each factor a verbal label —
the name of the psychological construct its items express — retrieved
deterministically from a pre-filtered pool of ~370,000 candidate terms
(every WordNet entry and filtered Wikipedia title that qualifies as a
psychological-attribute noun phrase, completed against five open construct
inventories). Nothing is generated: the label is the nearest eligible term
to the factor in the embedding space, under an instruction that asks the
model to represent each item as the construct it measures.
library(semanticfa) fit <- sfa(big5$items, nfactors = 5) labels <- sfa_name(fit) labels #> Factor labels (Qwen/Qwen3-Embedding-0.6B) #> #> F1 emotional instability [emotional instability, neuroticism] #> F2 conscientiousness #> ...
The first call downloads the candidate pool for your embedding model into
the user cache (a one-time download; see sfa_pool()); afterwards
everything is local and deterministic.
Or inline with the fit:
fit <- sfa(big5$items, nfactors = 5, label_factors = TRUE) fit$labels
One row per factor:
label — the automatic label. All quantitative claims should use it.candidates — the leave-one-out candidate set: every term that ranks
first when the factor's items are jackknifed one at a time. This is the
method's error bar: a sharp factor yields a single candidate, a fuzzy
factor several. You may report a different member of the set as the
factor name, but state that a human chose it.rule — provenance: tier1 (the label is a dictionary construct-noun)
or top1 (no dictionary noun in the top candidates; the raw best term
was used).collision_moved — TRUE if this factor originally picked the same
label as another factor and was re-labeled with its best non-conflicting
candidate (the factor geometrically closer to the shared term keeps it).Labels name the pole toward which the factor's positive loadings point: a factor defined by reverse-worded sociability items may be labeled "social withdrawal" — that is the faithful reading of its loadings, not an error.
Extraction and naming reward different model properties: factor structure
is recovered well by compact encoders, but label abstraction (choosing
"anxiety" over a symptom word like "palpitation") improves with larger
naming models. sfa_name() therefore accepts its own model:
labels <- sfa_name(fit, model = "microsoft/harrier-oss-v1-27b")
The factor structure stays exactly as fitted; only the naming space changes. Note the model itself is downloaded on first use and is large (~54 GB for the example above) — a GPU machine is strongly recommended for this option.
Naming reads whatever orientation the rotation happened to produce. If you
would rather choose the orientation that is most nameable in the first
place, sfa_leximax() rotates the solution toward the construct lexicon,
maximizing the agreement between each factor's naming target and the term
retrieved for it:
# rotate an existing fit rot <- sfa_leximax(fit) rot$labels # or fit and rotate in one call fit_lex <- sfa(big5$items, nfactors = 5, rotate = "leximax")
This is a rotation, so model fit is invariant: communalities and the
reproduced correlation matrix are unchanged, and only the axes move.
sfa_nameability() reports how nameable any given orientation is, which is
what lets you compare a leximax solution against the oblimin one you
started with.
Both need the naming word pool, so fetch it once with
sfa_pool(model, download = TRUE) before working offline.
sfa_naming_instruction()); label robustness to instruction rewording
was validated during method development. Overriding it is possible but
warned.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.