A random survival forest: a bagged ensemble of log-rank survival trees.
RandomSurvivalForest(
*,
n_estimators=100,
max_depth=None,
min_samples_split=6,
min_samples_leaf=3,
max_features="sqrt",
bootstrap=True,
oob_score=False,
engine="numpy",
random_state=None,
)
Each tree is grown on a bootstrap sample of the data and considers a random subset of covariates at every split, following Ishwaran et al. (2008). At each node the split threshold is chosen to maximize the log-rank separation between the child groups. Predictions average the per-tree cumulative-hazard functions across the ensemble; the scalar risk score is the summed ensemble cumulative hazard (mortality). Averaging many decorrelated trees yields a low-variance, well-calibrated non-parametric survival model that captures non-linearities and interactions without a proportional-hazards assumption.
Parameters
n_estimators: int = 100
-
Number of trees in the forest.
max_depth: int | None = None
-
Maximum depth of each tree (None for unlimited).
min_samples_split: int = 6
-
Minimum node size eligible for splitting.
min_samples_leaf: int = 3
-
Minimum subjects in each child of a split.
max_features: Any = "sqrt"
-
Covariates considered per split: "sqrt" (default), "log2", an int, a float, or None.
bootstrap: bool = True
-
Whether to grow each tree on a bootstrap sample (required for oob_score and variable_importance).
oob_score: bool = False
-
Whether to compute an out-of-bag concordance estimate after fitting.
engine: str = "numpy"
-
Compute backend for the split search: "numpy" (default, deterministic) or "numba" (faster on large datasets, requires the fast extra; produces a statistically equivalent fit that may differ in tie-breaking). "auto" uses Numba when available.
random_state: Any = None
-
Seed or
numpy.random.Generator for bootstrap sampling and per-node feature selection.
Examples
Fit a forest on the bundled lung dataset and inspect the out-of-bag concordance:
import greenwood as gw
# Load data and build a right-censored response
lung = gw.load_dataset("lung", backend="pandas").dropna(subset=["ph.ecog", "ph.karno"])
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
cols = ["age", "sex", "ph.ecog", "ph.karno", "wt.loss"]
# Fit the forest with an out-of-bag score
rsf = gw.RandomSurvivalForest(
n_estimators=100, oob_score=True, random_state=0
).fit(y, lung[cols])
rsf
RandomSurvivalForest (100 log-rank trees, max_features='sqrt')
n = 213, events = 151, features = 5
out-of-bag concordance = 0.6009