Run forward, backward, or two-way stepwise selection on an existing
hazard fit using score (Q) statistics, Wald p-values, or AIC deltas as
the entry / retention criterion. Phase-specific entry is supported for
multiphase models: a covariate can enter one phase and not another.
Usage
hzr_stepwise(
fit,
scope = NULL,
data,
direction = c("both", "forward", "backward"),
criterion = c("score", "wald", "aic"),
slentry = 0.3,
slstay = 0.2,
max_steps = 50L,
max_move = 4L,
force_in = character(),
force_out = character(),
trace = TRUE,
...
)
# S3 method for class 'hzr_stepwise'
print(x, ...)
# S3 method for class 'hzr_stepwise'
summary(object, ...)
# S3 method for class 'summary.hzr_stepwise'
print(x, ...)
# S3 method for class 'hzr_stepwise'
as.data.frame(x, ...)Arguments
- fit
A fitted
hazardobject built via theformula = Surv(...) ~ predictors, data = dfinterface.- scope
Candidate set.
NULL(default) uses every data-frame column not already in the model for every phase. For single-distribution fits, pass a one-sided formula (~ age + nyha) or a character vector of names. For multiphase fits, pass a named list of one-sided formulas keyed by phase.- data
Data frame the base fit was built on. Required for refits.
- direction
Search strategy — one of
"both"(default),"forward", or"backward". Controls whether variables may only enter, only leave, or both. See the Selection direction and criterion section.- criterion
Entry / retention rule — one of
"score"(default),"wald", or"aic"."score"and"wald"both apply SAS-style p-value thresholds (slentry/slstay) but score entry candidates differently, and can therefore select different variable sets;"score"reproduces C/SAS HAZARD and needs no per-candidate refit."aic"adds or drops whenever it lowers the AIC. See the Selection direction and criterion section.- slentry
Entry p-value threshold for the score / Wald criteria. Default
0.30matches SASSLENTRY.- slstay
Retention p-value threshold for the score / Wald criteria. Default
0.20matches SASSLSTAY.- max_steps
Hard cap on total accepted actions. Emits a
warning()if hit. Default50.- max_move
Per-variable oscillation cap. When a variable has entered + exited more than
max_movetimes it is frozen for the remainder of the run. Default4.- force_in
Character vector of variables that must remain in the model. Such variables are still scored and reported in the selection trace, but are never dropped.
- force_out
Character vector of variables that may never be considered as candidates.
- trace
Logical; print step-by-step progress to the console. Default
TRUE.- ...
Unused.
- x
An
hzr_stepwiseobject.- object
An
hzr_stepwiseobject.
Value
An object of class c("hzr_stepwise", "hazard") – the
final fit augmented with:
stepsData frame with one row per accepted / frozen action; see Details.
scopeRecord of the candidate scope, plus
force_in,force_out, and the frozen set.criteriaNamed list of the threshold / direction settings actually applied, plus, under
criterion = "score",n_uncomputable_scores(how many candidate scores wereNA),uncomputable_reasons(a named integer vector of why) andstopped_uncomputable. Readuncomputable_reasonsbefore treating an unscored candidate as a bad one:information_indefinitemarks candidates whose effect is too large for the score test's approximation at zero, which are typically the strongest variables on offer rather than degenerate ones. Those are now refit and tested by Wald automatically, counted inn_wald_fallbacks; a candidate still reachesuncomputable_reasonsonly when that refit itself fails, or when the cause is one no refit can rescue — which is every cause exceptinformation_indefiniteandcoefficient_diverging, the two a refit exists to rescue. Readuncomputable_reasonsfor which one it was in any given run. For every criterion it also carriesrefit_failures(the"var"/"var@phase"tokens of candidate moves whose refit errored or failed to converge),n_refit_failures, andstopped_refit_failed—TRUEwhen the run ended on an iteration in which refits failed, which is a screen that could not test its candidates rather than one that tested them and liked none. Check it before reading a zero-rowstepsas an honest null result.trace_msgCharacter vector of the trace lines, captured regardless of the
traceflag.elapseddifftimefrom start to finish.final_callThe call that produced this result.
print.hzr_stepwise returns x invisibly.
summary.hzr_stepwise returns a summary.hzr_stepwise object
(extends summary.hazard) with $stepwise_steps and $stepwise_trace
appended.
print.summary.hzr_stepwise returns x invisibly.
as.data.frame.hzr_stepwise returns the $steps data frame.
Details
The steps data frame has columns:
step_numInteger sequence starting at 1.
action"enter","drop", or"frozen".variableVariable affected.
phasePhase name (multiphase) or
NA_character_.criterionThe criterion actually applied to this step —
"score","wald", or"aic". Undercriterion = "score"the drop rows read"wald", because score is entry-only.scoreWinning score used for the decision.
stat,dfTest statistic and degrees of freedom.
stat_typeWhat
statis on this row, and so which reference distribution recomputes its p-value:"score_q"(chi-square ondf),"wald_z"(standard normal) or"wald_chisq"(chi-square ondf).dfalone does not distinguish them — a scalar Wald is reported as a z, not as its square, so it and a score Q are both recorded atdf = 1while calling for different distributions. This also identifies the rows the Wald fallback rescued: undercriterion = "score"they are the ones reading"wald_z"(see$criteria$n_wald_fallbacksfor the count).p_value,delta_aicAlways populated when computable, regardless of the active criterion.
logLik,aic,n_coefGoodness-of-fit diagnostics of the model after this step.
Selection direction and criterion
Two arguments shape the search. direction decides which moves are
allowed at each step; criterion decides how a candidate move is scored
and whether it is accepted.
direction = "forward"Start from the base model and only add variables — the best eligible candidate enters each step until none clears the entry rule. Variables never leave once in.
direction = "backward"Start from the full candidate model and only drop variables — the weakest term leaves each step until all survivors clear the retention rule.
direction = "both"(default)Two-way stepwise: after each entry, already-selected variables are re-tested and may be dropped. This is the SAS
SELECTION = STEPWISEstrategy.max_movecaps how often a single variable may oscillate before it is frozen.
criterion = "score"(default)Accept moves on SAS-style significance thresholds, using the score (Q) statistic of the candidate coefficient — this reproduces C/SAS HAZARD's
SELECTIONstatistic. Q is evaluated at the current model's MLE with the candidate's coefficient pinned at zero, so no candidate refit is needed: the reduced-model information is inverted once per step and reused across every candidate. Only the winner is refit. A candidate enters if its p-value is belowslentry.Score is an entry criterion; the drop path never refit per candidate in the first place, so removals are tested on the current model's Wald p-value against
slstay, as SAS does.For single-distribution fits, the score criterion computes the observed information numerically via the suggested numDeriv package and errors with a clear message if it is not installed; a multiphase fit uses the analytic Hessian instead and does not need it.
Following SAS, the variance used during selection is approximate: shaping-parameter covariances are ignored. This affects selection only — final-model standard errors are unchanged and still come from the full Hessian. Candidates must be single-column numeric main-effect terms; a factor is rejected with an error rather than skipped.
criterion = "wald"Accept moves on SAS-style significance thresholds, using the Wald \(\chi^2\) of the affected coefficient(s): a candidate enters if its p-value is below
slentry, and a term is dropped if its p-value rises aboveslstay. Entry candidates are scored from a refit that adds the candidate (so its new coefficient can be tested); drop candidates are scored from the current model's Wald p-values without a per-candidate refit, and a single refit is run only after a drop is chosen. This was the default before version 1.2.0. It differs algorithmically from C/SAS HAZARD, so the two criteria can take different step paths — and select different variable sets — even when they converge to a similar final model.criterion = "aic"Accept any move with \(\Delta\mathrm{AIC} < 0\) (a strictly better penalised fit), ignoring
slentry/slstay. Entry candidates use the actual \(\Delta\mathrm{AIC}\) from the candidate refit; drop candidates use a Wald-to-likelihood-ratio approximation, \(\Delta\mathrm{AIC} \approx W - 2\,\mathrm{df}\), computed from the current model without a per-candidate refit (the chosen drop is refit afterwards). Use this for a non-significance-based, information-criterion search.
See also
hazard() for the base model and hzr_phase() for multiphase
scopes; stepwise_trace() to retrieve the captured selection log.
Examples
data(avc)
avc <- na.omit(avc)
base <- hazard(survival::Surv(int_dead, dead) ~ age,
data = avc, dist = "weibull", fit = TRUE,
theta = c(mu = 0.01, nu = 0.5, 0))
# \donttest{
sw <- hzr_stepwise(base, scope = ~ age + mal,
data = avc, direction = "forward",
control = list(n_starts = 1))
#> Stepwise selection (direction = forward, criterion = score, slentry = 0.30, slstay = 0.20)
#>
#> Step 1: ENTER mal (p = 0.001)
#> (no further action after 1 step)
#>
#> Final model: 2 covariates, logLik = -223.55, AIC = 455.09
print(sw)
#> Stepwise selection (direction = forward, criterion = score, slentry = 0.30, slstay = 0.20)
#>
#> Step 1: ENTER mal (p = 0.001)
#> (no further action after 1 step)
#>
#> Final model: 2 covariates, logLik = -223.55, AIC = 455.09
# }