Parametric

Univariate parametric survival distribution.

Usage

Source

Parametric(
    dist="weibull",
    *,
    conf_level=0.95,
)

Fits a parametric survival distribution to right-censored data by maximum likelihood, without covariates. The result is a fully specified distribution that provides survival, hazard, density, quantile, and mean-life predictions.

Use this when you want to explore which distributional family best describes your data (Weibull vs. log-normal vs. log-logistic) before moving to regression modelling, or when the scientific question is simply “what is the median survival time and its uncertainty?”

Parameters

dist: str = "weibull"

Distribution family: "weibull" (default), "exponential", "lognormal", or "loglogistic".

conf_level: float = 0.95
Confidence level for parameter intervals (default 0.95).

Returns

Parametric
The fitted estimator (after calling fit()), with attributes params_, std_error_, conf_low_, conf_high_, loglik_, aic_, bic_, n_, and n_event_.

Details

Internally every family is fitted in the AFT location–scale parameterisation (\log T = \mu + \sigma\varepsilon), and results are reported back in the natural parameterisation of each distribution (e.g., Weibull shape and scale). Standard errors are obtained via the delta method applied to the observed information matrix.

Model selection between families is straightforward: lower AIC (or BIC) indicates a better fit. Use compare_distributions() to rank all four families at once.

Examples

Fit a Weibull distribution to the lung cancer dataset and inspect the parameter estimates:

import greenwood as gw

# Load data and build a right-censored response
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))

# Fit a Weibull distribution and display the parameter estimates
fit = gw.Parametric("weibull").fit(y)
fit
Parametric (weibull distribution)

       estimate  std_error
shape     1.317    0.08221
scale     417.8       24.7

n = 228, events = 165
Log-likelihood = -1154
AIC = 2312, BIC = 2319

To quickly compare all four distributions and pick the best-fitting family, use the companion function compare_distributions():

# Compare all four distribution families by AIC
gw.compare_distributions(y, format="polars")
shape: (4, 5)
distn_paramsloglikaicbic
stri64f64f64f64
"weibull"2-1153.8511882311.7023762318.561067
"loglogistic"2-1160.9306242325.8612472332.719938
"exponential"1-1162.3381762326.6763522330.105697
"lognormal"2-1169.2690552342.5381112349.396802

Methods

Name Description
cumulative_hazard() Cumulative hazard function H(t) = -\log S(t) at the given times.
density() Probability density function f(t) at the given times.
fit() Fit the distribution to right-censored survival data by maximum likelihood.
hazard() Hazard function h(t) = f(t) / S(t) at the given times.
mean() Expected survival time E[T].
median() Median survival time (the 50th-percentile time).
quantile() Quantile function: survival-time quantiles at failure probabilities p.
survival() Survival function S(t) = P(T > t) at the given times.
to_frame() Return the parameter estimates as a tidy DataFrame.

cumulative_hazard()

Cumulative hazard function H(t) = -\log S(t) at the given times.

Usage

Source

cumulative_hazard(times)

The cumulative hazard summarises the total accumulated risk up to time t. It increases monotonically from zero and is unbounded. A steeper rise indicates higher event rates over that interval.

Parameters
times: Any
Query times (array-like of positive floats).
Returns
ndarray
Cumulative hazard values, same length as times.
Details

Computed as the negative log of the survival function: H(t) = -\log S(t). For a Weibull distribution this simplifies to H(t) = (t/\lambda)^k.

Examples

Compute the cumulative hazard at several time points under a fitted Weibull model:

import greenwood as gw

# Load data and fit a Weibull distribution
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
fit = gw.Parametric("weibull").fit(y)

# Compute cumulative hazard at selected time points
fit.cumulative_hazard([100, 200, 365, 500])
array([0.15217398, 0.37909564, 0.83712486, 1.2669871 ])

density()

Probability density function f(t) at the given times.

Usage

Source

density(times)

Returns the density of the survival-time distribution. The density is the derivative of the CDF, so f(t)\,dt gives the probability of the event occurring in a small interval around t. Useful for plotting the fitted distribution against a histogram of observed times.

Parameters
times: Any
Query times (array-like of positive floats).
Returns
ndarray
Density values, same length as times.
Details

Computed from the standardised density as f_T(t) = f_\varepsilon(z) / (\sigma\,t), where z = (\log t - \mu)/\sigma.

Examples

Evaluate the Weibull density at a grid of time points:

import greenwood as gw

# Load data and fit a Weibull distribution
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
fit = gw.Parametric("weibull").fit(y)

# Evaluate the density at selected time points
fit.density([100, 200, 365, 500])
array([0.00172102, 0.00170849, 0.00130759, 0.00093992])

fit()

Fit the distribution to right-censored survival data by maximum likelihood.

Usage

Source

fit(surv)

Maximises the likelihood of the parametric model \log T = \mu + \sigma\varepsilon (intercept-only AFT) over the observed and censored times. The result is stored on the fitted object and reported in the natural parameterisation of each distribution.

Parameters
surv: Surv
A right-censored Surv response built with Surv.right().
Returns
Parametric
The fitted object (for method chaining), with attributes params_, std_error_, loglik_, aic_, bic_, etc.
Examples

Fit a log-normal distribution and view the estimated parameters with their standard errors:

import greenwood as gw

# Load data and build a right-censored response
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))

# Fit a log-normal distribution
gw.Parametric("lognormal").fit(y)
Parametric (lognormal distribution)

       estimate  std_error
mu        5.663      0.078
sigma     1.098    0.06187

n = 228, events = 165
Log-likelihood = -1169
AIC = 2343, BIC = 2349

hazard()

Hazard function h(t) = f(t) / S(t) at the given times.

Usage

Source

hazard(times)

The hazard (or hazard rate) gives the instantaneous risk of the event at time t, conditional on survival up to that time. Its shape reveals whether risk is increasing, decreasing, or constant over time. This shape is a signature feature of each distribution family.

Parameters
times: Any
Query times (array-like of positive floats).
Returns
ndarray
Hazard rate values, same length as times.
Details

The hazard is the ratio of the density to the survival function: h(t) = f(t) / S(t). For a Weibull distribution, the hazard is monotone (increasing when shape > 1, decreasing when shape < 1, constant when shape = 1). For a log-logistic distribution, the hazard is non-monotone (rises then falls when shape > 1).

Examples

Evaluate the instantaneous hazard rate at several time points under a fitted Weibull model:

import greenwood as gw

# Load data and fit a Weibull distribution
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
fit = gw.Parametric("weibull").fit(y)

# Evaluate the instantaneous hazard rate at selected time points
fit.hazard([100, 200, 365, 500])
array([0.00200389, 0.00249604, 0.00302016, 0.00333684])

mean()

Expected survival time E[T].

Usage

Source

mean()

Returns the mean (expected) survival time under the fitted distribution. This is the area under the survival curve from zero to infinity. For skewed survival distributions, the mean can differ substantially from the median.

Returns
float
The mean survival time under the fitted distribution. Returns inf for log-logistic when \beta \le 1 (the mean is undefined in that regime).
Details

Closed-form expressions are used for each family:

  • Weibull / Exponential: E[T] = e^\mu\,\Gamma(1 + \sigma)
  • Log-normal: E[T] = \exp(\mu + \sigma^2/2)
  • Log-logistic (\beta > 1): E[T] = \alpha\pi/\beta\,/\,\sin(\pi/\beta)
Examples

Compute the mean survival time under a fitted Weibull model:

import greenwood as gw

# Load data and fit a Weibull distribution
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
fit = gw.Parametric("weibull").fit(y)

# Compute the expected survival time
fit.mean()
384.85285283074927

median()

Median survival time (the 50th-percentile time).

Usage

Source

median()

Returns the time at which half of subjects are expected to have experienced the event under the fitted distribution. The median is often preferred over the mean for reporting survival times because it is less sensitive to heavy tails.

Returns
float
The time at which S(t) = 0.5.
Examples

Compute the median survival time under a fitted Weibull model:

import greenwood as gw

# Load data and fit a Weibull distribution
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
fit = gw.Parametric("weibull").fit(y)

# Compute the median survival time
fit.median()
316.26369237571606

quantile()

Quantile function: survival-time quantiles at failure probabilities p.

Usage

Source

quantile(p)

The quantile t_p satisfies P(T \le t_p) = p, so p=0.5 gives the median survival time, p=0.25 the first quartile, etc. This is the inverse of the CDF and provides clinically interpretable time-to-event summaries.

Parameters
p: Any
Failure probabilities in (0, 1). Scalar or array-like.
Returns
ndarray
Survival times corresponding to each probability.
Details

The quantile is computed analytically by inverting the standardised error distribution: t_p = \exp\!\bigl(\mu + \sigma\,F_\varepsilon^{-1}(p)\bigr).

Examples

Compute the first quartile, median, and third quartile of survival time under a fitted Weibull model:

import greenwood as gw

# Load data and fit a Weibull distribution
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
fit = gw.Parametric("weibull").fit(y)

# Compute the quartile survival times
fit.quantile([0.25, 0.5, 0.75])
array([162.19120953, 316.26369238, 535.36451702])

survival()

Survival function S(t) = P(T > t) at the given times.

Usage

Source

survival(times)

Returns the probability that a subject survives beyond each requested time under the fitted parametric distribution. Unlike the non-parametric Kaplan–Meier estimate, this gives a smooth curve that can be evaluated at any time point, including beyond the last observed event.

Parameters
times: Any
Query times (array-like of positive floats).
Returns
ndarray
Survival probabilities, same length as times.
Details

The survival probability is computed from the fitted location–scale model as S(t) = 1 - F_\varepsilon\!\bigl((\log t - \mu)/\sigma\bigr), where F_\varepsilon is the CDF of the standardised error distribution.

Examples

Evaluate the fitted Weibull survival function at a few clinically relevant time points (100, 200, 365, and 500 days):

import greenwood as gw

# Load data and fit a Weibull distribution
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
fit = gw.Parametric("weibull").fit(y)
# Evaluate survival probabilities at selected time points
fit.survival([100, 200, 365, 500])
array([0.85883885, 0.68448015, 0.43295354, 0.28167901])

to_frame()

Return the parameter estimates as a tidy DataFrame.

Usage

Source

to_frame(*, format=None)

One row per parameter, with columns param, estimate, std_error, conf_low, and conf_high.

Parameters
format: str | None = None
Output format: None (auto-detect), "pandas", "polars", or "pyarrow".
Returns
DataFrame
A tidy parameter table.
Examples

Export the parameter estimates as a Polars DataFrame for further analysis or reporting:

import greenwood as gw

# Load data and fit a Weibull distribution
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
fit = gw.Parametric("weibull").fit(y)

# Export the parameter estimates as a Polars DataFrame
fit.to_frame(format="polars")
shape: (2, 5)
paramestimatestd_errorconf_lowconf_high
strf64f64f64f64
"shape"1.316840.082211.1557121.477969
"scale"417.75865924.704538369.338654466.178663