CoxPH

Cox proportional hazards family for survival analysis.

Usage

Source

CoxPH(
    status="event",
    ties="breslow",
)

CoxPH fits a semiparametric proportional hazards model, allowing smooth (via s()) and linear covariate effects on the log hazard while leaving the baseline hazard h0(t) unspecified. Use this family whenever the response is a time-to-event outcome that may be right-censored — for example, time to failure, time to churn, or time to death/relapse in survival data — and the goal is to model how covariates shift the instantaneous risk of the event over time. Rather than a per-observation deviance and log-likelihood in the usual GLM sense, CoxPH maximizes the Cox partial likelihood via a custom irls_update, so the “response” y passed to GAM.fit() is the observed survival/censoring time, and the event indicator is supplied separately through set_data() (populated automatically by GAM.fit() from the column named by status).

Parameters

status: str = "event"

Name of the column in the data dict containing the event indicator (1 = event observed, 0 = right-censored). This column is looked up automatically from the data passed to GAM.fit().

ties: str = "breslow"
Tie-handling method for the partial likelihood when multiple observations share the same event time: "breslow" (default, simpler and faster) or "efron" (more accurate when ties are frequent).

Notes

The hazard is modeled multiplicatively as

h(t \mid x) = h_0(t)\, e^{\eta(x)}, \qquad \eta(x) = X\beta,

where h0(t) is an unspecified baseline hazard and eta is the (possibly smooth) linear predictor, so link and link_inverse are both the identity. There is no closed-form variance function or unit deviance in the usual GLM sense; instead, model fitting maximizes the Cox partial log-likelihood,

\ell(\beta) = \sum_{i:\, \delta_i = 1} \left[ \eta_i - \log\!\left( \sum_{j \in R(t_i)} e^{\eta_j} \right) \right],

where \delta_i is the event indicator and R(t_i) is the risk set at time t_i (those still under observation just before t_i). The overall “deviance” reported by GAM.summary() is -2\ell(\beta). After fitting, baseline_hazard() and survival_function() expose the Breslow estimate of the cumulative baseline hazard and the implied survival curve.

Examples

Fit a Cox proportional hazards GAM with a smooth effect of age on the hazard:

import numpy as np
import whittaker as wk

rng = np.random.default_rng(0)
n = 300
age = rng.uniform(40, 80, n)
risk = np.exp(0.03 * (age - 60))
time = rng.exponential(1.0 / risk)
censor_time = rng.exponential(2.0, n)
observed_time = np.minimum(time, censor_time)
event = (time <= censor_time).astype(float)

data = {"time": observed_time, "age": age, "event": event}

model = wk.GAM("time ~ s(age)", family=wk.CoxPH(status="event"))
model.fit(data, method="REML")
print(model.summary())
GAM fit summary
============================================================
Formula:    time ~ s(age)
Family:     CoxPH(ties='breslow')
Inference:  REML
Observations: 300
Coefficients: 10

Parametric coefficients:
  Term                       Estimate    Std.Err    z value    p-value
  ------------------------ ---------- ---------- ---------- ----------
  (Intercept)                  0.0787     0.0731      1.077     0.2817

Approximate significance of smooth terms:
  Term                        EDF Ref.df     Chi.sq    p-value
  ------------------------ ------ ------ ---------- ----------
  s(age)                     1.00      2     23.722   7.06e-06

Total EDF:  2.00
Scale est:  1.000000
Deviance:   1824.6258
Null dev:   1848.4760
Dev. expl:  1.3%
GCV score:  6.164023
AIC:        1828.63
BIC:        1836.04

Attributes

Name Description
scale_known Whether the dispersion parameter is fixed rather than estimated.
ties Tie-handling method used for the partial likelihood.

scale_known

Whether the dispersion parameter is fixed rather than estimated.

scale_known: bool


ties

Tie-handling method used for the partial likelihood.

ties: str

Methods

Name Description
baseline_hazard() Breslow estimate of the cumulative baseline hazard H_0(t).
deviance() Total deviance D = -2\,\ell(\beta) based on the Cox partial log-likelihood.
initialize() Store the observed survival times and seed the linear predictor at zero.
irls_update() Newton step for the Cox partial likelihood, supplying custom working values.
link() Identity link, \eta = \mu.
link_derivative() Derivative of the identity link, g'(\mu) = 1.
link_inverse() Inverse identity link, \mu = \eta.
log_likelihood() Cox partial log-likelihood \ell(\beta) at the current linear predictor.
set_data() Extract the event/censoring indicator from the fitting data.
simulate() Simulate survival times by inverting the fitted cumulative baseline hazard.
survival_function() Fitted survival probability at the last event time.
unit_deviance() Per-observation deviance placeholder (not decomposable for a partial likelihood).
variance() Variance function V(\mu) = 1.

baseline_hazard()

Breslow estimate of the cumulative baseline hazard H_0(t).

Usage

Source

baseline_hazard()

Returns the step-function estimate of H_0(t) = \int_0^t h_0(u)\, du evaluated at each observed event time, computed by _compute_baseline_hazard from the most recent linear predictor seen during fitting.

Returns

tuple of NDArray
(times, cumhaz): the sorted unique event times and the corresponding cumulative baseline hazard values, each shape (n_events,).

Raises

RuntimeError
If the model has not yet been fitted, so no baseline hazard exists.

deviance()

Total deviance D = -2\,\ell(\beta) based on the Cox partial log-likelihood.

Usage

Source

deviance(
    y,
    mu,
    *,
    weights=None,
)

Implements the family-specific version of Family.deviance. Since there is no saturated-model decomposition for the partial likelihood, this simply returns minus twice the partial log-likelihood evaluated at the current linear predictor, which GAM.summary() reports as the model deviance.

Parameters

y: NDArray

Observed survival/censoring times, shape (n,) (unused; retained for interface compatibility).

mu: NDArray

Current linear predictor values (eta), shape (n,).

weights: NDArray | None = None
Unused; CoxPH does not support prior weights.

Returns

float
-2\ell(\beta), the deviance.

initialize()

Store the observed survival times and seed the linear predictor at zero.

Usage

Source

initialize(y)

Implements the family-specific version of Family.initialize. Records the sorted order of the observed times y (used throughout this file to walk risk sets from latest to earliest time) and starts P-IRLS from eta = 0 for every observation, i.e. an initial hazard ratio of exp(0) = 1 relative to the baseline.

Parameters

y: NDArray
Observed survival/censoring times, shape (n,).

Returns

NDArray
Array of zeros with the same shape as y, used as the initial linear predictor.

irls_update()

Newton step for the Cox partial likelihood, supplying custom working values.

Usage

Source

irls_update(
    y,
    mu,
    eta,
)

Implements the family-specific version of Family.irls_update. Rather than deriving the working response and weights from link, link_derivative, and variance, this computes the gradient U(\eta) and diagonal Hessian H(\eta) of the partial log-likelihood directly (via _breslow_grad_hess or _efron_grad_hess, depending on ties), and forms a Newton update

z = \eta + H(\eta)^{-1} U(\eta), \qquad W = \max(H(\eta), \epsilon),

so that a weighted least-squares fit of z on W reproduces one Newton-Raphson step on the partial log-likelihood. As a side effect, also refreshes the Breslow estimate of the cumulative baseline hazard via _compute_baseline_hazard, so that baseline_hazard() and survival_function() reflect the current fit.

Parameters

y: NDArray

Observed survival/censoring times, shape (n,) (unused directly; times were captured by initialize).

mu: NDArray

Current fitted values, identical to eta for this family, shape (n,).

eta: NDArray
Current linear predictor values, shape (n,).

Returns

tuple of NDArray
(z, W), the pseudo-response and diagonal working-weight vector, each shape (n,).

Raises

RuntimeError
If called before set_data() has supplied the event indicator.




log_likelihood()

Cox partial log-likelihood \ell(\beta) at the current linear predictor.

Usage

Source

log_likelihood(
    y,
    mu,
    scale,
    *,
    weights=None,
)

Implements the family-specific version of Family.log_likelihood. Delegates to _partial_log_likelihood, which sums \eta_i - \log \sum_{j \in R(t_i)} e^{\eta_j} over the observed events, using the Breslow or Efron tie-handling scheme selected by ties.

Parameters

y: NDArray

Observed survival/censoring times, shape (n,) (unused; retained for interface compatibility).

mu: NDArray

Current linear predictor values (eta), shape (n,).

scale: float

Unused; CoxPH has no free dispersion parameter (see scale_known).

weights: NDArray | None = None
Unused; CoxPH does not support prior weights.

Returns

float
The partial log-likelihood \ell(\beta).

set_data()

Extract the event/censoring indicator from the fitting data.

Usage

Source

set_data(data)

Implements the family-specific version of Family.set_data. Looks up the column named by the status constructor argument in data and stores it as the event indicator used by irls_update, deviance, and log_likelihood to identify which observations are actual events (1) versus right-censored (0).

Parameters

data: dict[str, NDArray]
Mapping of column names to arrays, as passed to GAM.fit().

Raises

KeyError
If the status column is not present in data.

simulate()

Simulate survival times by inverting the fitted cumulative baseline hazard.

Usage

Source

simulate(
    mu,
    scale,
    rng,
)

Implements the family-specific version of Family.simulate. Draws u \sim \mathrm{Uniform}(0, 1) for each observation and solves for the target cumulative baseline hazard H_0(t) = -\log(u) / e^{\eta} implied by the proportional-hazards model, then looks up the smallest fitted baseline event time whose cumulative baseline hazard (from baseline_hazard()) meets or exceeds that target. Observations whose target exceeds the largest observed cumulative hazard are assigned the last baseline time.

Parameters

mu: NDArray

Current linear predictor values (eta), shape (n,).

scale: float

Unused; CoxPH has no free dispersion parameter.

rng: np.random.Generator
A numpy.random.Generator instance used to draw the uniform variates.

Returns

NDArray
Simulated survival times, shape (n,).

Raises

RuntimeError
If called before the model has been fitted (so no baseline hazard is available).

survival_function()

Fitted survival probability at the last event time.

Usage

Source

survival_function(eta)

S(t \mid x) = \exp(-H_0(t)\, e^{\eta}).

Combines the given linear predictor with the final value of the Breslow cumulative baseline hazard (i.e. H_0 evaluated at the largest observed event time) to give the implied survival probability for each observation at that time, following the proportional-hazards relationship S(t \mid x) = S_0(t)^{\exp(\eta)}.

Parameters

eta: NDArray
Linear predictor values, shape (n,).

Returns

NDArray
Fitted survival probabilities at the last observed event time, shape (n,).

Raises

RuntimeError
If the model has not yet been fitted, so no baseline hazard exists.

unit_deviance()

Per-observation deviance placeholder (not decomposable for a partial likelihood).

Usage

Source

unit_deviance(
    y,
    mu,
)

Implements the family-specific version of Family.unit_deviance. The Cox partial log-likelihood does not decompose into independent per-observation contributions the way an ordinary GLM deviance does, so this returns an array of ones purely to satisfy the Family interface; use deviance or log_likelihood for the actual fit statistics.

Parameters

y: NDArray

Observed survival/censoring times, shape (n,).

mu: NDArray
Current linear predictor values, shape (n,).

Returns

NDArray
Array of ones with the same shape as y.

variance()

Variance function V(\mu) = 1.

Usage

Source

variance(mu)

CoxPH fits via the Cox partial likelihood rather than a GLM variance function, so this returns a constant 1 for every observation; it exists only to satisfy the Family interface and is not used by irls_update, which supplies its own working weights directly from the partial-likelihood Hessian.

Parameters

mu: NDArray
Conditional mean values, shape (n,).

Returns

NDArray
Array of ones with the same shape as mu.