Skip to main content

Modern survival analysis for Python: Narwhals-native, R-validated, beautifully visualized.

Project description

Greenwood

Modern survival analysis for Python: Narwhals-native, R-validated, beautifully visualized.

What is Greenwood?

Greenwood is a Python library for survival analysis, the statistical study of time-to-event outcomes. Greenwood gives you lots of powerful features for extracting insights from incomplete data where some observations are censored (i.e., we don't know if the event happened yet).

Why Greenwood?

  • it works with your dataframe library: Pandas, Polars, PyArrow, or anything supported by Narwhals
  • it is rigorously validated, where every statistic is tested to tolerance against R's gold-standard survival package
  • you get beautiful, interactive survival visualizations, with a choice of plotting backends so you can use whichever you prefer
  • you also get publication-ready tables through integration with the Great Tables library
  • batteries are included: from simple Kaplan-Meier curves to Cox proportional hazards, competing risks, and beyond

What's included

Descriptive statistics:

  • Surv response object: Handle right-, left-, and interval-censored data; counting-process form; left truncation; weights; and multi-state endpoints with built-in validation.
  • Kaplan-Meier estimation (KaplanMeier): Survival curves with Greenwood confidence intervals, median/quantile survival, restricted mean survival time, and step-function predictions.
  • Nelson-Aalen estimator (NelsonAalen): Cumulative hazard curves.
  • Visualization (plot_survival): Interactive survival curves with confidence bands, censoring marks, and aligned at-risk tables, with a choice of plotting backends.

Hypothesis testing:

  • Log-rank tests (logrank_test): Standard log-rank test and the G-rho (Fleming-Harrington) family for 2+ groups.

Regression models:

  • Cox proportional hazards (CoxPH): Model covariates as hazard ratios with stratification, robust sandwich variance, clustering, baseline hazard prediction, and model diagnostics (residuals, proportional-hazards test, concordance).
  • Accelerated failure time (AFT): Parametric models (Weibull, exponential, log-normal, log-logistic) validated against R's survreg.
  • Competing risks: Cumulative incidence functions (AalenJohansen), subdistribution hazards (FineGray), and multi-state transition probabilities.

Model performance:

  • Prediction metrics: Concordance index (Harrell's C) and inverse-probability censoring weighted (IPCW) Brier score / integrated Brier score.

Tidy & reproducible:

  • Tidy layer (greenwood.tidy): Broom-compatible summaries aligned with Great Summaries for consistent reporting.
  • Built-in datasets (lung, veteran, ovarian, pbc, colon) and R-parity test harness: Every statistic is validated to tolerance against R's survival package.

Get started

Here's a simple example that loads survival data, estimates a survival curve, and visualizes it.

import greenwood as gw

# Load the data and represent it as a survival object
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))

# Estimate the Kaplan-Meier survival curve
km = gw.KaplanMeier().fit(y)

# Visualize it
gw.plot_survival(km)

# Fit a Cox proportional hazards model
cox = gw.CoxPH().fit(y, lung[["age", "sex"]])

That's it! See the user guide for more details on each step, and scroll down for a comprehensive example covering more of Greenwood's capabilities.

See more

Here's a comprehensive example showcasing more of Greenwood's capabilities:

import greenwood as gw

df = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(df["time"], event=(df["status"] == 2))

# Kaplan-Meier with stratification and detailed summaries
km = gw.KaplanMeier(conf_type="log-log").fit(y, by=df["sex"])
km.to_frame(format="polars")  # tidy: strata, time, n_risk, n_event, estimate, conf_low, conf_high
km.median(ci=True)         # median survival with confidence limits, per stratum
km.rmst(365, ci=True)      # restricted mean survival time up to 365 days
km.predict([180, 365])     # survival probability at specific times

# Statistical tests
gw.logrank_test(y, group=df["sex"])          # standard log-rank test
gw.logrank_test(y, group=df["sex"], rho=1)   # Peto-Peto (G-rho) test

# Visualization with risk tables
gw.plot_survival(km, risk_table=True)

# Cox proportional hazards regression
cox = gw.CoxPH().fit(y, df[["age", "sex"]])
gw.tidy(cox, exponentiate=True, format="polars")  # hazard ratios with confidence intervals
cox.cox_zph()                                # proportional-hazards test
cox.concordance()                            # C-statistic
cox.predict(df[["age", "sex"]].head(), type="survival", times=[180, 365], format="polars")

# Parametric accelerated failure time models
aft = gw.AFT("weibull").fit(y, df[["age", "sex"]])
gw.tidy(aft, format="polars")           # coefficients on the log-time scale

# Competing risks: cumulative incidence per cause
# (mgus2 loaded with pandas here for the Series `.where` construction below)
mg = gw.load_dataset("mgus2", backend="pandas")
etime = mg["ptime"].where(mg["pstat"] == 1, mg["futime"])
cause = mg["pstat"].where(mg["pstat"] == 1, 2 * mg["death"])
cr = gw.Surv.multistate(etime, event=cause, states=("pcm", "death"))
gw.AalenJohansen().fit(cr).to_frame(format="polars")
gw.FineGray("pcm").fit(cr, mg[["age", "sex"]]).to_frame(format="polars")

# Model performance and prediction
gw.concordance_index(y, cox.predict(type="lp"))
S = cox.predict(df[["age", "sex"]], type="survival", times=[180, 365], format="pandas").iloc[:, 1:].to_numpy().T
gw.brier_score(y, S, times=[180, 365])

License

MIT (c) Richard Iannone. See the LICENSE file.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

greenwood-0.1.0.tar.gz (492.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

greenwood-0.1.0-py3-none-any.whl (170.7 kB view details)

Uploaded Python 3

File details

Details for the file greenwood-0.1.0.tar.gz.

File metadata

  • Download URL: greenwood-0.1.0.tar.gz
  • Upload date:
  • Size: 492.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for greenwood-0.1.0.tar.gz
Algorithm Hash digest
SHA256 01b6df421529af6d87fc66e4b9b850f272e30b12bc6cf1411feb824cd2b757e0
MD5 784c0df2ca1a61d9e843bbc8191dd58c
BLAKE2b-256 6ed54cc1262356fa7fd660eba21ad73f6d41a5f23b1b2a8bd9fbfeea1b8e2012

See more details on using hashes here.

File details

Details for the file greenwood-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: greenwood-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 170.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for greenwood-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a247da315be5ac106ea4716640e95dc9c68f569dbc3ed48b453f0a56a6eff31b
MD5 8b20a406c9df997709fe4c8ce60e8114
BLAKE2b-256 81772115b9012dbbe7622bf3004ea1527eb7bd71d1ed84386a9338748422da12

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page