gen_surv¶
Simulate survival data with a known truth. gen_surv generates synthetic
time-to-event datasets from twelve models — proportional hazards, accelerated
failure time, competing risks, cure fractions, piecewise hazards, recurrent
events and two illness-death processes — so you can test an estimator against
parameters you chose yourself.
It is a Python port of the R package genSurv, extended well past the original's four models.
Install it Generate your first dataset
Thirty seconds¶
from gen_surv import generate
df = generate(
model="cphm", # Cox proportional hazards
n=6,
beta=0.5, # log hazard ratio
covariate_range=2.0, # X0 ~ Uniform(0, 2)
model_cens="uniform",
cens_par=1.0,
seed=42,
)
print(df)
time status X0
0 0.438878 0.0 1.547912
1 0.094177 0.0 1.394736
2 0.037041 1.0 1.522279
3 0.370798 0.0 0.900772
4 0.646901 1.0 1.287730
5 0.251113 1.0 0.454477
You picked beta = 0.5, so you know what a correct estimator should recover.
That is the whole point: every column above was produced by a mechanism you
specified.
What it is for¶
-
Method development
Check that a new estimator recovers the parameters that generated the data, across sample sizes and censoring levels.
-
Teaching
Hand students a dataset whose hazard ratio, cure fraction or transition intensities are known, and let them try to find them.
-
Benchmarking
Compare implementations on identical inputs — every generator takes a
seed, so runs are byte-for-byte reproducible. -
Software validation
Exercise an analysis pipeline against edge cases: heavy censoring, a cured subpopulation, non-proportional hazards, panel-observed states.
The twelve models¶
model= |
Family | Returns | Page |
|---|---|---|---|
cphm |
Cox proportional hazards | one row per subject | Cox PH |
aft_ln |
Log-normal AFT | one row per subject | AFT |
aft_weibull |
Weibull AFT | one row per subject | AFT |
aft_log_logistic |
Log-logistic AFT | one row per subject | AFT |
piecewise_exponential |
Piecewise constant hazard | one row per subject | Piecewise |
competing_risks |
Cause-specific constant hazards | one row per subject | Competing risks |
competing_risks_weibull |
Cause-specific Weibull hazards | one row per subject | Competing risks |
mixture_cure |
Logistic cure + exponential failure | one row per subject | Mixture cure |
cmm |
Illness-death, counting-process intervals | two or three rows per subject | CMM |
thmm |
Illness-death, observed state panel | two or three rows per subject | THMM |
tdcm |
Cox with a time-dependent covariate | one row per subject | TDCM |
recurrent_events |
Repeated events per subject (AG, PWP) | one row per at-risk interval | Recurrent events |
There is a thirteenth generator that generate() cannot reach.
gen_multistate takes an arbitrary transition graph as
a list of objects rather than a set of scalars, so it has no model= string and
no command-line form. cmm and thmm are configurations of it.
Not sure which one you need? Choosing a model walks through the decision.
The output shape is not the same for every model
Multi-state generators return several rows per subject, and column names
differ between families — cphm has no id column at all, tdcm uses
covariate where the others use X0. Read
Output schemas before you write code that
consumes a generated frame.
The ground truth, not just the data¶
A generated frame looks like a real one, which means it hides the same things.
simulate() hands back what a real dataset
never could — the coefficients actually used, the event time before censoring
intervened, which subjects are cured, when a covariate crossed over:
from gen_surv import simulate
result = simulate("cphm", n=1000, beta=0.5, covariate_range=2.0,
model_cens="uniform", cens_par=1.0, seed=42)
result.truth["event_time"] # when each subject would have failed
result.truth["censoring_time"] # what censoring hid
Several models draw their coefficients for you when you omit them, and
result.truth["betas"] is the only way to learn what they were.
Beyond generating¶
- Ground truth — configurations, latent times, and the coefficients a model chose for itself.
- Baseline hazards — five families, and the protocol for writing your own.
- Censoring — the two mechanisms wired into every generator, and the standalone samplers for everything else.
- Summarising a dataset — event counts, follow-up, quality checks, dataset comparison.
- Plotting — Kaplan-Meier curves, hazard comparisons, covariate effects.
- Fitting models to the data — handing the frame to lifelines, scikit-survival or scikit-learn.
- Command line — generate and plot without writing Python.
Citing¶
@software{ribeiro_gensurv,
title = {gen_surv: Survival Data Simulation in Python},
author = {Diogo Ribeiro},
url = {https://github.com/DiogoRibeiro7/genSurvPy},
version = {3.1.2}
}
Machine-readable metadata lives in
CITATION.cff
and .zenodo.json.