The R port of %bootreg (bootstrap.models.sas in the CORR macro library).
Fits fitter on each of n_rep bootstrap replicates and records the
coefficients each model kept.
Usage
boot_select(
data,
formula,
fitter,
n_rep = 1000,
fraction = 1,
select = c("stepwise", "none"),
sle = 0.1,
sls = 0.05,
max_steps = 0,
max_attempts = 10 * n_rep,
seed = NULL
)Arguments
- data
A data frame.
- formula
Model formula offering the candidate terms.
- fitter
A fitter such as
fit_logistic(),fit_linear()orfit_cox().%bootregequivalent:PROC=.- n_rep
Number of valid models to generate (
%bootregRESAMPL=). Replicates whose fit fails are redrawn and do not count, matching the macro's®rccheck.- fraction
Fraction of
nrow(data)to draw per replicate (%bootregFRACTION=). Divergence: the macro documents this parameter but never applies it - it computesds_size * fraction, prints it, and then always drawsds_sizerows. This implementation applies it. Passfraction = 1(the default) to match SAS behaviour exactly.- select
"stepwise"or"none"(%bootregSELECT=/FIXED=).- sle, sls
Entry and retention p-value thresholds (
%bootregSLE=,SLS=). Each fitter pins its own entry and removal test to match itsPROC=- seefit_linear(),fit_logistic()andfit_cox()- sosleandslsare exactly what they mean in the job being ported. Model fitting is still not parity-tested - see the package's design spec - but these two arguments now select rather than only being recorded. Divergence: candidates are flat term labels, not a hierarchy, andfit_linear()'s removal test respects marginality whilefit_logistic()'s andfit_cox()'s Wald removal test does not - so a screen can keep an interaction without either main effect on the latter two, whichPROC LOGISTIC's defaultHIERARCHY=SINGLEwould not do. Not implemented; see D5 in the README's divergence register.- max_steps
Maximum selection steps (
%bootregMAXSTEP=).0means no restriction, implemented as a budget scaled to the model - ten passes over the candidate terms, floored at 1000 - which no realistic model reaches. It bounds the p-value stepwise driver's forward/backward loop (.pv_stepwise()inR/stepwise.R) rather than leaving it genuinely unbounded.- max_attempts
Budget of resampling attempts before giving up. Divergence:
%bootreghas no such cap - its loop advances only on a successful fit, so a model that fails on every replicate never terminates. That is survivable in a batch job with an operator watching the log; underR CMD checkit is an unbounded hang with no diagnostic. Exhausting the budget raises an error reporting how many valid models were obtained. PassInfto restore the macro's uncapped behaviour.- seed
Optional integer for reproducibility.
Value
An object of class boot_selection. $coefficients is a matrix with
one row per valid replicate and one column per candidate term, NA where
the term was not selected. $control records the run's own settings –
method, sle, sls, max_steps, fraction, seed, n_rows,
n_terms, elapsed_mins and the package version – so that a bag
builder boot_bag() can take a provenance record from
the run rather than from what a caller retypes. $call cannot serve
that purpose: match.call() omits every argument left at its default.
Details
A term the model did not select is NA in that replicate's row. That
missingness is the whole design: boot_summary() counts non-missing values
down a column, so n is the number of replicates that chose the term. Do
not fill those gaps with zero.
fitter is what PROC= was. Adding a model family means writing a fitter,
not another pipeline.
See also
boot_summary() for the per-variable selection frequencies, and
boot_clusters() for the same question asked of a correlated group.
fit_linear(), fit_logistic() and fit_cox() are the supplied fitters.
Examples
set.seed(1)
n <- 300
x1 <- rnorm(n)
df <- data.frame(y = 2 * x1 + rnorm(n), x1 = x1,
x2 = rnorm(n), noise = rnorm(n))
# n_rep is RESAMPL=. It counts VALID models, so a replicate whose fit fails
# is redrawn and does not consume one -- the macro's ®rc check.
fit <- boot_select(df, y ~ x1 + x2 + noise, fit_linear,
n_rep = 50, seed = 42)
fit
#> <boot_selection>
#> replicates: 50 valid of 50 attempts
#> terms: 4
#> Use boot_summary() for per-variable selection frequencies.
# The replicate table itself, one row per model, NA where a term was not
# selected. This is what %bootreg writes to OUTEST=.
head(fit$coefficients, 3)
#> (Intercept) x1 x2 noise
#> [1,] -0.09140503 2.072650 NA NA
#> [2,] -0.01488408 1.998002 NA NA
#> [3,] 0.01221866 1.906206 NA NA
boot_summary(fit)
#> variable n pct mean sd min max
#> 1 (Intercept) 50 100 -0.01935105 0.061297809 -0.1529768 0.1033970
#> 2 x1 50 100 2.01128028 0.090146372 1.8800885 2.2223719
#> 3 noise 3 6 0.12711552 0.019080164 0.1108547 0.1481200
#> 4 x2 3 6 0.13669590 0.007207413 0.1284142 0.1415486