Statistical Ideas in Code
  • Home
  • Papers
    • Random Effects
    • False Discovery Rate
    • Two Cultures
    • Bootstrap
    • EM Algorithm
    • Baum-Welch
    • MCMC
    • Cox Model
    • Propensity Scores
    • GAM
    • Conformal Prediction
    • Gradient Boosting
    • Marginal Structural Models
    • Lasso

On this page

  • Core Contribution
  • Minimal Implementation
  • Implementations

Regression Models and Life-Tables

David Cox (1972)

Core Contribution

Cox introduced a survival regression model with unspecified baseline hazard:

\[ h(t\mid x)=h_0(t)\exp(x'\beta). \]

The baseline \(h_0(t)\) can be left unspecified because the ordered failure times imply a partial likelihood:

\[ L(\beta)=\prod_{i:\delta_i=1} \frac{\exp(x_i'\beta)}{\sum_{j:t_j\ge t_i}\exp(x_j'\beta)}. \]

This estimates relative hazards while avoiding a full parametric survival distribution.

Minimal Implementation

Simulate observed event/censoring times and the risk sets induced by their ordering.

n = 180
x = rng.normal(size=n)
beta_true = 0.8
t_event = rng.exponential(scale=np.exp(-beta_true * x))
t_cens = rng.exponential(scale=2.1, size=n)
time = np.minimum(t_event, t_cens)
event = t_event <= t_cens
event.mean()
np.float64(0.6277777777777778)

Define the negative partial log-likelihood using the risk set \(R(t_i)=\{j:t_j\ge t_i\}\).

def neg_pl(beta):
    xb = beta * x
    out = 0.0
    for ti, xi, di in zip(time, x, event):
        if di:
            out += beta * xi - special.logsumexp(xb[time >= ti])
    return -out

beta_hat = optimize.minimize_scalar(neg_pl, bracket=(-1, 1)).x
beta_hat
np.float64(0.9973838746212481)

Evaluate and plot the profile of the partial likelihood.

grid = np.linspace(-0.2, 1.6, 180)
pll = np.array([-neg_pl(b) for b in grid])

fig, ax = plt.subplots(figsize=(6, 3.4))
ax.plot(grid, pll - pll.max())
ax.axvline(beta_hat, color="#ffcc66", lw=2.5, label=f"partial MLE={beta_hat:.2f}")
ax.axvline(beta_true, color="#66ff99", ls="--", label=f"truth={beta_true:.2f}")
ax.set(xlabel="log hazard ratio", ylabel="relative log partial likelihood")
ax.legend()
plt.show()

The partial likelihood recovers a log hazard ratio without estimating the baseline hazard.

Implementations

lifelines CoxPHFitter, scikit-survival CoxPHSurvivalAnalysis, R survival