A SAS candidate pool offers every transformation of a variable as a separate
candidate: age, ln_age, in_age, age2 and
agee all compete. A
stepwise screen then spends its steps on them, and a per-variable selection
frequency reports each form separately. On one real screen five forms of age
each cleared 80% while the retained set collapsed to four distinct clinical
concepts – and the paper the job comes from reports concepts.
Usage
concept_of(
v,
pool,
affixes = POOL_AFFIXES,
plain_suffix = POOL_PLAIN_SUFFIX,
aliases = character(0),
min_stem = POOL_MIN_STEM
)Arguments
- v
Character scalar: the variable name.
- pool
Character vector: the candidate pool
vbelongs to.- affixes
Character vector of regular expressions for the study's transformation affixes. See
POOL_AFFIXES.- plain_suffix
Suffix carried by untransformed measurements.
- aliases
Named character vector,
c(variable = concept), declaring groupings no affix rule can reach. An alias on the variable itself wins over every rule: it is the study saying so directly.- min_stem
Minimum stem length before the prefix rule is tried.
Details
The rule is deliberately conservative. A variable joins a concept
only
when stripping one known affix yields a name that is itself in the
pool (or
that name plus plain_suffix). So zexp2 groups under zexp
because zexp
is a candidate, and ln_crcl groups under crcl_pr because that
is the
plain form present. A name whose stem is absent stays its own concept:
agee does not join age, because no rule strips a trailing
e.
Grouping too little costs some pruning. Grouping too much silently merges two clinical concepts and discards a real candidate, which is the error that cannot be seen in the output. The rule errs the safe way, and callers are expected to report the map so a human can check it.
Two mechanisms are needed, and only one can be mechanical.
vars.sas
truncates the stem when it names a derivative, so stripping the affix yields
a name absent by exact match:
Truncation –
effiis a prefix ofeffic, so it can be found. Handled automatically, but only when the stem prefixes exactly one pool member that is not itself a derived form, and only when the stem is at leastmin_stemcharacters. Ambiguity declines to group rather than guessing.Contraction –
arinis not a prefix ofarea_intand no rule can find it. Declare it viaaliases, so the judgement is recorded in the job rather than inferred by the function.
Left ungrouped on a real screen, effic at 86.4% and ln_effi at
60.8% were
both reported as retained risk factors at r = 0.9988, and in_arin at
70.6%
hid a concept whose union across its forms was 86.4%.
A permanent compatibility layer, not a temporary shim
Stem truncation exists because SAS capped variable names at 8 characters. A
modern builder has no such cap and a pool built that way needs none of this,
because ln_efficiency strips cleanly to efficiency.
But the two regimes coexist indefinitely: reproducing a legacy SAS job in R
is routine work, not a migration with an end date, so truncated pools keep
arriving from built*.sas7bdat extracts for as long as old jobs are
re-run.
Do not delete the prefix rule or the alias table when a new builder
ships. They are how a legacy pool is read. The right expectation is that
new datasets simply never need them.