Competing Risks SurPyval Modelling

This page shows how to use SurPyval’s competing risks classes. For the theoretical background see Competing Risks Analysis.

Warning

The competing risks subsystem is under active development. The FineGray and CompetingRisksProportionalHazard fitters currently crash on first call; CompetingRisks has a known bug in its failure function (ff). These issues are tracked in DEVELOPMENT.md. Code examples below show the intended API; they will work once the fixes land.

Standard imports used throughout this page:

import surpyval as surv
import numpy as np
from matplotlib import pyplot as plt

Fitting a Parametric Competing Risks Model

The CompetingRisks class fits a parametric distribution independently to each failure cause and combines them into a joint model. Pass the observed times, a cause indicator, and optional censoring flags:

from surpyval import CompetingRisks, Weibull, Exponential

# Simulated data: two competing causes
np.random.seed(42)
t1 = Weibull.random(100, alpha=50, beta=2.5)   # cause 1 latent times
t2 = Exponential.random(100, lam=1./80)         # cause 2 latent times

# Observed time is the minimum; cause is which latent time was smaller
x = np.minimum(t1, t2)
cause = (t2 < t1).astype(int)  # 0 = cause 1, 1 = cause 2
c = np.zeros_like(x, dtype=int)  # all observed (no censoring)

model = CompetingRisks.fit(
    x=x,
    c=c,
    cause=cause,
    dist=[Weibull, Exponential],
)
print(model)

Once fitted, you can query the CIF for each cause:

t_plot = np.linspace(0, 150, 300)
for k, label in enumerate(['Cause 1 (Weibull)', 'Cause 2 (Exponential)']):
    plt.plot(t_plot, model.ff(t_plot, cause=k), label=label)
plt.xlabel('Time')
plt.ylabel('Cumulative Incidence')
plt.legend()
plt.title('Competing Risks CIF by Cause')

Fine-Gray Sub-distribution Hazards (Planned)

The Fine-Gray model estimates the effect of covariates directly on the cumulative incidence function. The intended API mirrors the single-event regression fitters:

# Planned API — not yet working (see DEVELOPMENT.md)
from surpyval.competing_risks import FineGray

model = FineGray.fit(x=x, c=c, Z=Z, cause=cause, cause_of_interest=0)
print(model.summary())

Cause-Specific Proportional Hazards (Planned)

Fit a separate proportional hazards model per cause, censoring all other events:

# Planned API — not yet working (see DEVELOPMENT.md)
from surpyval.competing_risks import CompetingRisksProportionalHazard

model = CompetingRisksProportionalHazard.fit(x=x, c=c, Z=Z, cause=cause)
print(model.summary())