What
Add an optional per-model summary of the precision of a term supplied through
null.terms — its standard error, or the width of its confidence band — so that
the effect of each candidate covariate on the estimate of a forced term can be
read from the model set.
Why it matters
Where null.terms carries a term the analysis exists to estimate, the question
asked of the model set is not only which candidates predict the response, but
which of them help resolve that term. The two are different, and the existing
output answers only the first.
A candidate can explain response variance well and still widen the interval on the
forced term, if the two are correlated. That case is not visible anywhere at
present: r2.vals.unique reports fit, variable.importance reports how often a
term is selected, and neither is a statement about the precision of a different
term. It is also the case the collinearity screen cannot catch, because
null.terms is outside it (beckyfisher/FSSgam_package#23).
The alternative is for the user to refit the set by hand, extracting the term's
standard error from each fit, which is a loop the package is already running.
Why not general effect-size reporting
A broader capability — effect sizes for every term in the selected set — is
tempting but has a defect that this narrower one avoids.
Estimates and intervals taken from a model chosen by AICc out of a large candidate
set have wrong coverage: the intervals are too narrow, because the selection step
is not accounted for. A term reported with an interval looks like an estimate and
will be used as one, and for a selected term that reading is not supported.
A null.terms term is not subject to selection for its own inclusion, so it does
not carry that bias in the same way. Restricting the report to forced terms keeps
the output defensible. (The standard error is still conditional on a data-driven
nuisance specification, which is a smaller effect but worth stating in the
documentation rather than leaving implied.)
Evidence that the loop already has what is needed
fit_model_set() already fits and holds every model, and extract_mod_dat()
already pulls per-model statistics from each fit:
mod.dat <- list(AICc=NA, BIC=NA, r2.vals=NA, r2.vals.unique=NA, edf=NA, edf.less.1=NA)
so the addition is another extractor over the same objects, not another pass.
Implementation detail
Interface
An argument naming the term of interest, e.g. precision.term = "s(flow)" or the
bare variable name, defaulting to NULL for no change in behaviour. Adding a
column to mod.data.out keeps it alongside AICc and r2.vals.unique, where the
comparison is wanted.
What to report, by term type
- Parametric term — the standard error from
summary(fit)$p.table, which is
unambiguous.
- Smooth — there is no single coefficient, so a choice is needed. Two
workable options: the mean width of the pointwise confidence band over the
observed range of the variable, or the standard error of a user-supplied
contrast between two values of it. The second is more interpretable and more
work; the first is a reasonable default. Either way the quantity should be
named in the documentation, since "the precision of a smooth" is not
self-defining.
- Random effect in
null.terms — not a target for this; the argument should
either skip or error on a term with no fixed-effect interpretation, rather than
return something meaningless.
Points to settle
- Behaviour when the named term is absent from
null.terms. Erroring is
probably right: the whole argument for the feature rests on the term being
forced into every model, so a term that is merely usually selected should not
be accepted silently.
- The
gamm/gamm4/dsm classes each reach the fitted smooth differently, as
extract_mod_dat() already has to handle for R².
- Comparability across models requires the same rows in each fit, which holds
when predictors are complete — generate_model_set() already rejects
predictors containing NA.
Definition of done
For a named forced term, mod.data.out carries a precision column that can be
read against delta.AICc and r2.vals.unique, and the documentation states what
the number is, that it applies only to forced terms, and why it is not offered for
selected ones.
What
Add an optional per-model summary of the precision of a term supplied through
null.terms— its standard error, or the width of its confidence band — so thatthe effect of each candidate covariate on the estimate of a forced term can be
read from the model set.
Why it matters
Where
null.termscarries a term the analysis exists to estimate, the questionasked of the model set is not only which candidates predict the response, but
which of them help resolve that term. The two are different, and the existing
output answers only the first.
A candidate can explain response variance well and still widen the interval on the
forced term, if the two are correlated. That case is not visible anywhere at
present:
r2.vals.uniquereports fit,variable.importancereports how often aterm is selected, and neither is a statement about the precision of a different
term. It is also the case the collinearity screen cannot catch, because
null.termsis outside it (beckyfisher/FSSgam_package#23).The alternative is for the user to refit the set by hand, extracting the term's
standard error from each fit, which is a loop the package is already running.
Why not general effect-size reporting
A broader capability — effect sizes for every term in the selected set — is
tempting but has a defect that this narrower one avoids.
Estimates and intervals taken from a model chosen by AICc out of a large candidate
set have wrong coverage: the intervals are too narrow, because the selection step
is not accounted for. A term reported with an interval looks like an estimate and
will be used as one, and for a selected term that reading is not supported.
A
null.termsterm is not subject to selection for its own inclusion, so it doesnot carry that bias in the same way. Restricting the report to forced terms keeps
the output defensible. (The standard error is still conditional on a data-driven
nuisance specification, which is a smaller effect but worth stating in the
documentation rather than leaving implied.)
Evidence that the loop already has what is needed
fit_model_set()already fits and holds every model, andextract_mod_dat()already pulls per-model statistics from each fit:
so the addition is another extractor over the same objects, not another pass.
Implementation detail
Interface
An argument naming the term of interest, e.g.
precision.term = "s(flow)"or thebare variable name, defaulting to
NULLfor no change in behaviour. Adding acolumn to
mod.data.outkeeps it alongside AICc andr2.vals.unique, where thecomparison is wanted.
What to report, by term type
summary(fit)$p.table, which isunambiguous.
workable options: the mean width of the pointwise confidence band over the
observed range of the variable, or the standard error of a user-supplied
contrast between two values of it. The second is more interpretable and more
work; the first is a reasonable default. Either way the quantity should be
named in the documentation, since "the precision of a smooth" is not
self-defining.
null.terms— not a target for this; the argument shouldeither skip or error on a term with no fixed-effect interpretation, rather than
return something meaningless.
Points to settle
null.terms. Erroring isprobably right: the whole argument for the feature rests on the term being
forced into every model, so a term that is merely usually selected should not
be accepted silently.
gamm/gamm4/dsmclasses each reach the fitted smooth differently, asextract_mod_dat()already has to handle for R².when predictors are complete —
generate_model_set()already rejectspredictors containing
NA.Definition of done
For a named forced term,
mod.data.outcarries a precision column that can beread against
delta.AICcandr2.vals.unique, and the documentation states whatthe number is, that it applies only to forced terms, and why it is not offered for
selected ones.