import greenwood as gw
sim = gw.simulate_competing_risks(n=300, n_causes=2, seed=42)
sim.survSurv(type=mright, n=300, events=171, states=('cause1', 'cause2'))
Generate synthetic competing-risks data from a latent-Weibull model.
Usage
Each cause has its own Weibull distribution with specified shape and scale parameters. For each subject, a latent event time is drawn independently for every cause, and the cause with the shortest latent time is the one observed. An independent censoring time is drawn from a Weibull(1, scale) distribution (i.e., exponential). If the censoring time is shortest, the subject is censored.
When covariates are requested, cause-specific proportional hazards are applied: the Weibull scale for cause k is adjusted as b_k \cdot \exp(-\mathbf{x}^\top \boldsymbol{\beta}_k / a_k), where a_k and b_k are the shape and scale for cause k. Covariates are drawn from a standard normal distribution.
n: int = 500Number of subjects (default 500).
n_causes: int = 2Number of competing event types (default 2).
shapes: tuple[float, …] | None = NoneWeibull shape parameter for each cause. Length must equal n_causes. Defaults to (1.0, 1.5, ...) cycling through [1.0, 1.5, 0.8]. A shape of 1.0 gives an exponential (constant hazard). Values above 1 give increasing hazard. Values below 1 give decreasing hazard.
scales: tuple[float, …] | None = NoneWeibull scale parameter for each cause. Length must equal n_causes. Defaults to 10.0 for every cause.
censoring_scale: float | None = 1.5Controls censoring intensity. The censoring time is drawn from an exponential distribution with scale equal to censoring_scale times the mean latent event time. Larger values produce less censoring. Set to None or 0 to disable censoring entirely. Default is 1.5, which gives roughly 20-30% censoring depending on the shape/scale configuration.
n_covariates: int = 0Number of covariates to generate (default 0). When positive, standard-normal covariates are drawn and cause-specific proportional-hazards effects are applied.
coef: Any | None = NoneCoefficient matrix of shape (n_covariates, n_causes) for the proportional-hazards effect on each cause. When None (default), coefficients are drawn from Uniform(-0.5, 0.5).Ignored when n_covariates=0.
states: tuple[str, …] | None = NoneNames for each cause (e.g., ("relapse", "death")). Length must equal n_causes. Defaults to ("cause1", "cause2", ...).
seed: int | None = NoneGenerate a simple two-cause competing-risks dataset and fit an Aalen-Johansen estimator:
Surv(type=mright, n=300, events=171, states=('cause1', 'cause2'))
AalenJohansen (Aalen-Johansen cumulative incidence)
states: cause1, cause2
n = 300
final CIF
cause1 0.5327
cause2 0.4673
Generate data with covariates for a Fine-Gray model:
sim = gw.simulate_competing_risks(
n=500,
n_causes=2,
n_covariates=3,
states=("relapse", "death"),
seed=99,
)
fg = gw.FineGray(cause="relapse").fit(sim.surv, covariates=sim.covariates)
gw.tidy(fg, format="polars")| term | estimate | std_error | statistic | p_value | conf_low | conf_high |
|---|---|---|---|---|---|---|
| str | f64 | f64 | f64 | f64 | f64 | f64 |
| "x0" | -0.182905 | 0.073823 | -2.477608 | 0.013227 | -0.327596 | -0.038214 |
| "x1" | 0.339535 | 0.079627 | 4.264052 | 0.00002 | 0.183468 | 0.495601 |
| "x2" | 0.020141 | 0.082495 | 0.244152 | 0.807113 | -0.141546 | 0.181829 |
Control the event-time distribution and censoring rate:
import numpy as np
# Cause 1: increasing hazard (shape > 1), Cause 2: constant hazard
sim = gw.simulate_competing_risks(
n=1000,
n_causes=2,
shapes=(2.0, 1.0),
scales=(15.0, 10.0),
censoring_scale=0.8, # heavier censoring
seed=7,
)
# Check the censoring fraction
frac_censored = (sim.surv.status == 0).mean()
print(f"Censored: {frac_censored:.1%}")Censored: 60.1%