Survival Analysis

Kaplan-Meier estimation, log-rank test (G-rho family), Cox proportional hazards (CPU), and discrete-time survival models (GPU-accelerated).

Survival analysis.

Public API:

kaplan_meier(time, event, …) -> KMSolution survdiff(time, event, group, …) -> LogRankSolution coxph(time, event, X, …) -> CoxSolution # CPU only discrete_time(time, event, X, …) -> DiscreteTimeSolution # GPU accelerated

pystatistics.survival.cox_zph(fit, *, transform='km')[source]

Test the proportional-hazards assumption of a fitted Cox model.

Score test on scaled Schoenfeld residuals — the survival >= 3.0 formulation of survival::cox.zph (not the pre-3.0 correlation test). Reports one chi-square per covariate plus a GLOBAL test, and carries the scaled Schoenfeld residuals for plotting.

Parameters:
  • fit (CoxSolution) – A fitted Cox model from coxph() (stratified or not). The fit retains its data for exactly this purpose.

  • transform (str) – Time transform g(t): “km” (default, left-continuous KM CDF of the pooled sample — R’s default), “rank”, “identity”, or “log”.

Return type:

CoxZphSolution

pystatistics.survival.coxph(time, event, X, *, terms=None, names=None, strata=None, start=None, robust=False, cluster=None, ties='efron', tol=1e-09, max_iter=20, conf_level=0.95)[source]

Cox proportional hazards model.

CPU only — no backend parameter. Matches R’s survival::coxph().

Parameters:
  • time (array-like) – Time to event or censoring. With start, this is the risk-interval exit (R’s stop).

  • event (array-like) – Event indicator (1=event, 0=censored).

  • X (array-like or DataSource) – Covariate matrix (n, p). No intercept — Cox model has no intercept. When terms is given, X is instead the data source (a DataSource or column mapping) from which the term spec pulls columns.

  • terms (sequence or None) – Structured term spec for categorical predictors and interactions (bare column names, C(name, ref=…), or tuples of those). When given, the covariate matrix is built from X (the source) with no intercept, and the expanded column labels are used automatically. Mutually exclusive with names.

  • strata (array-like or None) – Stratum label per observation. When given, fits a stratified Cox model: one shared coefficient vector, a separate baseline hazard (separate risk sets) per stratum. Matches coxph(Surv(t, e) ~ x + strata(g)).

  • start (array-like or None) – Counting-process start time per ROW: the row is at risk on (start, time]. A subject may span several rows with different covariate values (time-varying covariates), or a single row with a delayed entry (left truncation). Matches coxph(Surv(start, stop, event) ~ x) with time as the stop. Each start must be strictly less than its time (R NA-drops such rows with a warning; PyStatistics refuses loudly instead).

  • robust (bool) – If True, report the Lin-Wei sandwich (robust / Huber-White) standard errors instead of the model-based ones; .z_values / .p_values / .conf_int then use the robust SE, and .naive_standard_errors keeps the model-based SE. Matches coxph(..., robust=TRUE). (Distinct from timeseries’s LOESS-robustness robust — CONVENTIONS A9: a robust variance estimator here, not outlier downweighting.)

  • cluster (array-like or None) – Cluster label per row for grouped-robust SE (correlated rows of one subject/cluster count as one independent unit). Implies robust=True. Matches coxph(..., cluster=id).

  • ties (str) – Method for handling tied event times: “efron” (default) or “breslow”.

  • tol (float) – Convergence tolerance for Newton-Raphson.

  • max_iter (int) – Maximum Newton-Raphson iterations.

  • conf_level (float) – Confidence level for .conf_int (default 0.95). Wald intervals on the coefficient (log-hazard-ratio) scale; exp(.conf_int) gives hazard- ratio intervals.

  • names (list[str] | None)

Return type:

CoxSolution

pystatistics.survival.discrete_time(time, event, X, *, names=None, intervals=None, backend=None, conf_level=0.95)[source]

Discrete-time survival via person-period logistic regression.

GPU-accelerated — delegates to regression.fit(family=’binomial’).

Parameters:
  • time (array-like) – Time to event or censoring.

  • event (array-like) – Event indicator (1=event, 0=censored).

  • X (array-like) – Covariate matrix (n, p). No intercept — interval dummies serve as the intercept.

  • intervals (array-like or None) – Time interval boundaries. If None, uses unique event times.

  • backend (str or None) – Backend for the person-period logistic regression, forwarded to regression.fit. Default None → ‘cpu’ (the R-reference path). Explicit values: “cpu” (float64), “gpu” (float32, CUDA or Apple Silicon), “gpu_fp64” (float64, CUDA only — the exact double-precision GPU path), or “auto” (GPU-fp32 if CUDA present, else CPU).

  • conf_level (float) – Confidence level for .conf_int (default 0.95). Wald intervals on the covariate coefficient scale; exp(.conf_int) gives discrete-time hazard-ratio intervals.

  • names (list[str] | None)

Return type:

DiscreteTimeSolution

pystatistics.survival.kaplan_meier(time, event, *, strata=None, entry=None, conf_level=0.95, conf_type='log')[source]

Kaplan-Meier survival curve estimation.

Matches R’s survival::survfit(Surv(time, event) ~ 1).

Parameters:
  • time (array-like) – Time to event or censoring.

  • event (array-like) – Event indicator (1=event, 0=censored).

  • strata (array-like or None) – Stratum label per observation. When given, returns a StratifiedKMSolution holding one product-limit curve per stratum (matching survfit(Surv(time, event) ~ g)).

  • entry (array-like or None) – Delayed-entry (left-truncation) time per subject: the subject is at risk on (entry, time], so early risk sets exclude subjects who have not yet entered. Matches survfit(Surv(entry, time, event)). Each entry must be strictly less than the corresponding time.

  • conf_level (float) – Confidence level for CI (default 0.95).

  • conf_type (str) – CI transformation: “log” (R default), “plain”, “log-log”.

Return type:

KMSolution

pystatistics.survival.survdiff(time, event, group, *, rho=0.0)[source]

Log-rank test (and G-rho family).

Matches R’s survival::survdiff().

Parameters:
  • time (array-like) – Time to event or censoring.

  • event (array-like) – Event indicator (1=event, 0=censored).

  • group (array-like) – Group labels (e.g. treatment vs control).

  • rho (float) – G-rho weight parameter. rho=0 (default) gives the standard log-rank test. rho=1 gives Peto & Peto / Gehan-Wilcoxon.

Return type:

LogRankSolution

class pystatistics.survival.CoxSolution(_result, _names=None, _design=None)[source]

Bases: SolutionReprMixin

Cox proportional hazards solution.

Properties mirror R’s coxph() output.

Parameters:
property coefficients
property coef: dict[str, float]

Named coefficient mapping (like R’s coef()).

property hr: dict[str, float]

Named hazard ratio mapping (exp(coef)).

property hazard_ratios
property standard_errors
property z_values
property p_values
property loglik
property concordance: float
property n_events: int
property n_observations: int
property n_iter: int
property converged: bool
property ties: str
property conf_level: float

Confidence level for conf_int (default 0.95).

property n_strata: int

Number of strata (1 for an unstratified fit).

property robust: bool

Whether standard_errors are the sandwich (robust) estimator.

property naive_standard_errors

Model-based SEs when robust — else the same as standard_errors.

property conf_int

Wald confidence intervals for the coefficients, shape (p, 2).

coef ± z * se on the coefficient (log-hazard-ratio) scale, where z is the normal quantile for conf_level (Cox inference is asymptotic-normal). exp(conf_int) gives hazard-ratio intervals.

property backend_name: str
property timing
property warnings: tuple[str, ...]
summary()[source]

R-style summary of Cox PH fit.

Return type:

str

class pystatistics.survival.CoxZphSolution(_data, _names)[source]

Bases: SolutionReprMixin

Proportional-hazards test result (one row per covariate + GLOBAL).

Mirrors R’s cox.zph object: .chisq / .df / .p_values are aligned with .row_names (covariates first, "GLOBAL" last); .residuals holds the scaled Schoenfeld residuals (one row per event, time-ordered within stratum), .x the transformed event times, .time the raw event times.

Parameters:
property row_names: tuple[str, ...]
property chisq: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property df: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property p_values: ndarray[tuple[Any, ...], dtype[_ScalarT]]
property residuals: ndarray[tuple[Any, ...], dtype[_ScalarT]]

Scaled Schoenfeld residuals, shape (n_events, p).

property x: ndarray[tuple[Any, ...], dtype[_ScalarT]]

Transformed event times aligned with residuals rows.

property time: ndarray[tuple[Any, ...], dtype[_ScalarT]]

Raw event times aligned with residuals rows.

property var: ndarray[tuple[Any, ...], dtype[_ScalarT]]

Inverse average per-event covariance (R’s zph$var).

property transform: str
summary()[source]
Return type:

str

class pystatistics.survival.DiscreteTimeSolution(_result, _names=None, _conf_level=0.95)[source]

Bases: SolutionReprMixin

Discrete-time survival model solution.

Properties mirror the logistic regression on person-period data.

Parameters:
property coefficients
property coef: dict[str, float]

Named coefficient mapping.

property hr: dict[str, float]

Named hazard ratio mapping (exp(coef)).

property standard_errors
property z_values
property p_values
property conf_level: float

Confidence level for conf_int (default 0.95).

property conf_int

Wald confidence intervals for the covariate coefficients, shape (p, 2).

coef ± z * se on the (discrete-time log-hazard) coefficient scale, with the normal quantile for conf_level (the person-period logistic fit is asymptotic-normal). exp(conf_int) gives discrete-time hazard-ratio intervals.

property hazard_ratios
property baseline_hazard
property interval_labels
property person_period_n: int
property n_intervals: int
property n_observations: int
property n_events: int
property glm_deviance: float
property glm_aic: float
property converged: bool

Whether the person-period binomial IRLS converged.

False means the underlying logistic fit hit the iteration cap (or, for an all-censored design with no events, that no fit ran) — treat the coefficients as unreliable. Mirrors CoxSolution.converged.

property n_iter: int

IRLS iterations used by the person-period binomial GLM.

Mirrors CoxSolution.n_iter. A value at the solver’s iteration cap alongside converged == False indicates a fit that did not settle.

property backend_name: str
property timing
property warnings: tuple[str, ...]
summary()[source]

Summary of discrete-time survival model.

Return type:

str

class pystatistics.survival.KMSolution(_result)[source]

Bases: SolutionReprMixin

Kaplan-Meier survival curve solution.

Properties mirror R’s survfit() output.

Parameters:

_result (Result[KMParams])

property time

Unique event times.

property survival

S(t) at each event time.

property n_risk

Number at risk just before each event time.

property n_events

Number of events at each event time.

property n_censored

Number censored in each interval.

property se

Greenwood standard error of S(t).

property standard_errors

Greenwood standard error of S(t) (uniform-accessor alias of se).

property ci_lower

Lower confidence bound for S(t).

property ci_upper

Upper confidence bound for S(t).

property conf_int

Confidence band for S(t) at each event time, shape (m, 2).

Columns are [lower, upper] — the uniform-accessor form of ci_lower / ci_upper (which remain available).

property conf_level: float
property conf_type: str
property n_observations: int
property n_events_total: int
property median_survival: float | None

Median survival time, matching R survfit’s minmin convention.

The median is the smallest t with S(t) <= 0.5; but when the curve touches exactly 0.5 (a flat step at 0.5), R averages that time with the next time the curve drops strictly below 0.5. Returns None if the curve never reaches 0.5.

property backend_name: str
property timing
property warnings: tuple[str, ...]
summary()[source]

R-style summary of Kaplan-Meier fit.

Return type:

str

class pystatistics.survival.LogRankSolution(_result)[source]

Bases: SolutionReprMixin

Log-rank test solution.

Properties mirror R’s survdiff() output.

Parameters:

_result (Result[LogRankParams])

property statistic: float
property df: int
property p_value: float
property n_groups: int
property observed
property expected
property n_per_group
property rho: float
property group_labels
property backend_name: str
property timing
property warnings: tuple[str, ...]
summary()[source]

R-style summary of log-rank test.

Return type:

str

class pystatistics.survival.StratifiedKMSolution(_curves, _timing=None)[source]

Bases: SolutionReprMixin

Stratified Kaplan-Meier result: one survival curve per stratum.

Wraps an ordered mapping {stratum_label: KMSolution}. Index by label (sol["A"]) or iterate sol.curves.items() to reach each stratum’s ordinary KMSolution.

Parameters:

_curves (dict)

property strata: tuple

Stratum labels, in curve order.

property n_strata: int
property curves: dict

Ordered {label: KMSolution} mapping.

stratum(label)[source]

The KMSolution for one stratum.

property timing
property warnings: tuple[str, ...]

Union of the per-stratum warnings, prefixed by stratum label.

summary()[source]
Return type:

str