RandomSurvivalForest

A random survival forest: a bagged ensemble of log-rank survival trees.

Usage

Source

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