concordance_index_ipcw()

IPCW concordance index (Uno et al., 2011) for right-censored survival data.

Usage

Source

concordance_index_ipcw(
    surv,
    risk,
    *,
    data=None,
    tau=None,
)

An inverse-probability-of-censoring-weighted concordance index that corrects for censoring bias. Unlike Harrell’s C, the IPCW concordance is a consistent estimator of the true concordance probability even under informative censoring patterns. It is more robust when censoring is heavy or differs across risk groups.

When to use this instead of concordance_index (Harrell’s C):

  • when censoring exceeds 30-40% of subjects.
  • when censoring patterns differ across risk groups (informative censoring).
  • when comparing models across datasets with different censoring rates.

Interpretation: Same scale as Harrell’s C (0.5 = random, 1.0 = perfect discrimination). Values are comparable to Harrell’s C under light censoring and diverge when censoring is heavy.

Parameters

surv: Surv | Outcome | str

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

risk: Any

Risk score for each subject, one per observation. Higher values indicate higher risk (earlier expected failure). Accepts a 1-D array, Pandas/Polars Series, or Python sequence.

tau: float | None = None

Truncation time. Only pairs with an event before tau contribute. This avoids instability from low censoring survival in the tail. Defaults to the largest observed event time.

data: Any = None
A data frame (pandas, Polars, PyArrow, DuckDB, a lazy frame, …) holding the columns named by the response and risk. 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
IPCW concordance index between 0 and 1.

Details

Uno estimator: For each subject i with an observed event at T_i \le \tau, compare against all subjects j with T_j > T_i:

\hat{C}_{\mathrm{IPCW}} = \frac{\displaystyle\sum_{i:\Delta_i=1,\,T_i \le \tau} \hat{G}(T_i^-)^{-2} \Bigl[\#\{j: T_j > T_i,\, \eta_j < \eta_i\} + \tfrac{1}{2}\#\{j: T_j > T_i,\, \eta_j = \eta_i\}\Bigr]} {\displaystyle\sum_{i:\Delta_i=1,\,T_i \le \tau} \hat{G}(T_i^-)^{-2} \cdot \#\{j: T_j > T_i\}}

where \hat{G} is the Kaplan-Meier estimate of the censoring distribution.

Truncation: Restricting to events before \tau avoids instability from dividing by very small censoring probabilities in the tail. The default \tau is the largest event time. Set it explicitly to the maximum follow-up of interest.

Examples

Fit a Cox model on the lung dataset and compute the IPCW concordance:

import greenwood as gw

lung = gw.load_dataset("lung", backend="polars")
death = gw.Outcome.surv(time="time", event="status")
cox = gw.CoxPH().fit(death, covariates=["age", "sex"], data=lung)

lp = cox.predict(type="lp")

# Compare Harrell's C with IPCW C
c_harrell = gw.concordance_index(death, risk=lp, data=lung)
c_ipcw = gw.concordance_index_ipcw(death, risk=lp, data=lung)
print(f"Harrell C: {c_harrell:.4f}")
print(f"IPCW C:    {c_ipcw:.4f}")
Harrell C: 0.6029
IPCW C:    0.5959

Truncate at 1 year to focus on short-term discrimination:

c_1yr = gw.concordance_index_ipcw(death, risk=lp, tau=365.0, data=lung)
print(f"IPCW C (1-year): {c_1yr:.4f}")
IPCW C (1-year): 0.5991