Univariate parametric survival distribution.
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).
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)| dist | n_params | loglik | aic | bic |
|---|
| str | i64 | f64 | f64 | f64 |
| "weibull" | 2 | -1153.851188 | 2311.702376 | 2318.561067 |
| "loglogistic" | 2 | -1160.930624 | 2325.861247 | 2332.719938 |
| "exponential" | 1 | -1162.338176 | 2326.676352 | 2330.105697 |
| "lognormal" | 2 | -1169.269055 | 2342.538111 | 2349.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.
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.
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.
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.
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.
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].
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()
quantile()
Quantile function: survival-time quantiles at failure probabilities 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.
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.
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)| param | estimate | std_error | conf_low | conf_high |
|---|
| str | f64 | f64 | f64 | f64 |
| "shape" | 1.31684 | 0.08221 | 1.155712 | 1.477969 |
| "scale" | 417.758659 | 24.704538 | 369.338654 | 466.178663 |