## Parametric


Univariate parametric survival distribution.


Usage

``` python
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()](AFT.md#greenwood.AFT.fit)), with attributes `params_`, [std_error_](KaplanMeier.md#greenwood.KaplanMeier.std_error_), [conf_low_](KaplanMeier.md#greenwood.KaplanMeier.conf_low_), [conf_high_](KaplanMeier.md#greenwood.KaplanMeier.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()](compare_distributions.md#greenwood.compare_distributions) to rank all four families at once.


## Examples

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


``` python
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_distributions.md#greenwood.compare_distributions):


``` python
# 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) | Cumulative hazard function H(t) = -\log S(t) at the given times. |
| [density()](#density) | Probability density function f(t) at the given times. |
| [fit()](#fit) | Fit the distribution to right-censored survival data by maximum likelihood. |
| [hazard()](#hazard) | Hazard function h(t) = f(t) / S(t) at the given times. |
| [mean()](#mean) | Expected survival time E\[T\]. |
| [median()](#median) | Median survival time (the 50th-percentile time). |
| [quantile()](#quantile) | Quantile function: survival-time quantiles at failure probabilities `p`. |
| [survival()](#survival) | Survival function S(t) = P(T \> t) at the given times. |
| [to_frame()](#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

``` python
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:


``` python
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

``` python
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:


``` python
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

``` python
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](Surv.md#greenwood.Surv) response built with [Surv.right()](Surv.md#greenwood.Surv.right).


##### Returns


`Parametric`  
The fitted object (for method chaining), with attributes `params_`, [std_error_](KaplanMeier.md#greenwood.KaplanMeier.std_error_), `loglik_`, `aic_`, `bic_`, etc.


##### Examples

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


``` python
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

``` python
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:


``` python
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

``` python
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:


``` python
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

``` python
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:


``` python
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

``` python
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:


``` python
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

``` python
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):


``` python
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

``` python
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:


``` python
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 |
