integrated_brier_score_incidence()

Integrated (time-averaged) Brier score for a cause-specific cumulative incidence.

Usage

Source

integrated_brier_score_incidence(
    surv,
    incidence_prob,
    times,
    *,
    data=None,
    cause,
)

Summarizes cause-specific Brier scores computed at multiple time horizons into a single metric via trapezoidal integration. This provides an overall calibration measure for a competing-risks model’s predictions for a specific cause.

Use this to: Reduce multiple cause-specific Brier scores (one per time point) to a single number for model comparison. Especially useful when comparing Fine-Gray models for the same cause with different covariate sets.

Interpretation: Same scale as brier_score_incidence() (0 = perfect, 1 = worst).

Parameters

surv: Surv | Outcome | str

A multi-state Surv response (from gw.Surv() with a categorical event). An Outcome or a formula response such as 'Surv(time, status == 2)' is also accepted, with its columns read from data.

incidence_prob: Any

Predicted cumulative incidence probabilities for the cause of interest, shape (n_subjects, n_times).

times: Any

Evaluation times (at least 2). The integrated Brier score is computed as the area under the Brier-score curve from times[0] to times[-1], normalized by the time span.

cause: int

The cause of interest (integer event code from the Surv response).

data: Any = None
A data frame (pandas, Polars, PyArrow, DuckDB, a lazy frame, …) holding the columns named by the response and incidence_prob. When surv is an Outcome or a formula, rows with a missing value in any column used are dropped first, along with the matching rows of any arrays passed alongside.

Returns

float
Integrated Brier score (time-averaged). Lower is better.

Examples

Summarize CIF calibration for progression (cause 1) into a single score using the mgus2 dataset:

import greenwood as gw
import numpy as np

# The first of progression (PCM) or death, each with its own time and status columns
mgus2 = gw.load_dataset("mgus2", backend="polars")
first = gw.Outcome.first_event(
    endpoints={"pcm": ("ptime", "pstat"), "death": ("futime", "death")}
)

# Marginal CIF from Aalen-Johansen as a naive baseline
aj = gw.AalenJohansen().fit(first, data=mgus2)
cif_df = aj.to_frame(format="polars")
pcm_cif = cif_df.filter(cif_df["cause"] == "pcm")

# Evaluate over a fine time grid
times = np.linspace(30, 360, 12)
marginal = np.array(
    [float(np.interp(t, pcm_cif["time"].to_numpy(), pcm_cif["estimate"].to_numpy()))
     for t in times]
)
probs = np.tile(marginal, (mgus2.height, 1))
ibs = gw.integrated_brier_score_incidence(
    first, incidence_prob=probs, times=times, cause=1, data=mgus2
)
ibs
0.07514656777562731