Nelson-Aalen estimator of the cumulative hazard.
NelsonAalen(
*,
conf_type="log",
conf_level=0.95,
)
The Nelson-Aalen estimator provides a non-parametric estimate of the cumulative hazard function, which represents the total “accumulated risk” up to a given time. Unlike the Kaplan-Meier estimator which models survival directly, this approach models the force of mortality. The cumulative hazard at each event time is computed as a running sum of the ratio of events to subjects at risk:
\[
H(t) = \sum_{t_i \le t} \frac{d_i}{n_i}
\]
This estimator is useful when you want to examine the hazard directly rather than survival probabilities, and is often used as the basis for other analyses. You can convert the cumulative hazard to a survival estimate via \(S(t) = \exp(-H(t))\), though the Kaplan-Meier estimator is typically preferred for direct survival estimation. Call fit() with a right-censored Surv response to compute cumulative hazard at each event time.
The variance of the cumulative hazard estimate uses Aalen’s formula:
\[
\mathrm{Var}(H(t)) = \sum_{t_i \le t} \frac{d_i}{n_i^2}
\]
Confidence intervals can be constructed on the plain or log scale, with the log scale providing better coverage in the tails.
Parameters
conf_type: str = "log"
-
Confidence-interval transform: "plain" (default for Nelson-Aalen) or "log".
conf_level: float = 0.95
-
Confidence level for the interval (default 0.95).
Returns
Fitted estimator
-
Call fit() to produce a fitted estimator with cached results (
time_, cumulative_hazard_, std_error_, conf_low_, conf_high_, n_risk_, n_event_, n_censor_), accessible as aligned arrays or exported to DataFrames.
Examples
Build a Surv response from the bundled lung dataset and fit the estimator. Printing the fitted object reports the counts and the maximum cumulative hazard reached.
import greenwood as gw
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
na = gw.NelsonAalen().fit(y)
na
NelsonAalen (Nelson-Aalen cumulative hazard estimate)
n events max cumhaz
228 165 2.889
Methods
|
Name
|
Description
|
|
fit()
|
Fit the Nelson-Aalen estimator to survival data.
|
|
to_frame()
|
Return the fitted cumulative hazard as a DataFrame.
|
fit()
Fit the Nelson-Aalen estimator to survival data.
fit(surv, *, by=None, weights=None)
Computes the cumulative hazard function \(H(t)\) from a Surv response (time-to-event data). Like Kaplan-Meier, this is a non-parametric estimate requiring no distributional assumptions. The Nelson-Aalen estimator is an alternative to Kaplan-Meier; it estimates the cumulative hazard directly (sum of \(d/n\) at each event time), from which the survival probability can be derived via \(S(t) = \exp(-H(t))\). Results are stored in the fitted object; access them via attributes or export to a DataFrame with to_frame() (optionally format=).
Pass by= to produce separate cumulative hazard curves per group (stratified analysis), enabling covariate-free comparison of hazard accumulation across groups. Optionally supply weights to adjust for selection bias or survey design.
Parameters
surv: Surv
-
A Surv response (typically right-censored). Built from data using Surv.right(), Surv.interval(), etc.
by: Any = None
-
Optional grouping variable (e.g., a column or array). Produces one fit (one cumulative hazard curve) per unique value of by, enabling stratified Nelson-Aalen analysis. Default (None): fit a single, unstratified curve.
weights: Any = None
-
Optional weights (e.g., from survey design or inverse-probability-of-censoring adjustments). Must have the same length as
surv. Default (None): unit weights.
Returns
NelsonAalen
-
The fitted estimator object itself (for method chaining) with cached results (
time_, cumulative_hazard_, conf_low_, conf_high_, n_risk_, n_event_ as attributes).
Details
The Nelson-Aalen estimator is
\[
H(t) = \sum_{t_i \le t} \frac{d_i}{n_i}
\]
where \(d_i\) and \(n_i\) are events and number at risk at time \(t_i\). Its variance is estimated using Aalen’s formula:
\[
\mathrm{Var}(H) = \sum \frac{d_i}{n_i^2}
\]
The survival function can be recovered as \(S(t) = \exp(-H(t))\). Confidence intervals are point-wise.
Examples
Fit a single (unstratified) cumulative hazard curve on the bundled lung dataset:
import greenwood as gw
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
na = gw.NelsonAalen().fit(y)
na
NelsonAalen (Nelson-Aalen cumulative hazard estimate)
n events max cumhaz
228 165 2.889
Fit stratified curves by sex to compare cumulative hazard accumulation:
na_stratified = gw.NelsonAalen().fit(y, by=lung["sex"])
na_stratified
NelsonAalen (Nelson-Aalen cumulative hazard estimate)
n events max cumhaz
1 138 112 3.163
2 90 53 2.322
to_frame()
Return the fitted cumulative hazard as a DataFrame.
Exports the Nelson-Aalen estimate with one row per event time, including risk-set counts, the cumulative hazard estimate, its standard error, confidence limits, and optional strata labels.
Parameters
format: str | None = None
-
Output format:
None (default), "pandas", "polars", or "pyarrow". When None, a backend is auto-detected (Polars, then Pandas, then PyArrow).
Returns
pandas.DataFrame, polars.DataFrame, or pyarrow.Table
-
A tidy table with columns
time, n_risk, n_event, estimate, std_error, conf_low, conf_high, and optionally strata.
Raises
ImportError
-
If the requested (or, when auto-detecting, any) DataFrame library is not installed.
Examples
Fit a Nelson-Aalen estimator on the bundled lung dataset, then export the fitted cumulative-hazard curve as a Polars frame:
import greenwood as gw
lung = gw.load_dataset("lung", backend="polars")
y = gw.Surv.right(lung["time"], event=(lung["status"] == 2))
na = gw.NelsonAalen().fit(y)
na.to_frame(format="polars")
shape: (186, 7)| time | n_risk | n_event | estimate | std_error | conf_low | conf_high |
|---|
| f64 | f64 | f64 | f64 | f64 | f64 | f64 |
| 5.0 | 228.0 | 1.0 | 0.004386 | 0.004386 | 0.000618 | 0.031136 |
| 11.0 | 227.0 | 3.0 | 0.017602 | 0.008801 | 0.006606 | 0.046899 |
| 12.0 | 224.0 | 1.0 | 0.022066 | 0.009868 | 0.009184 | 0.053015 |
| 13.0 | 223.0 | 2.0 | 0.031035 | 0.01173 | 0.014795 | 0.065101 |
| 15.0 | 221.0 | 1.0 | 0.03556 | 0.012573 | 0.017783 | 0.071108 |
| … | … | … | … | … | … | … |
| 840.0 | 5.0 | 0.0 | 2.639267 | 0.335859 | 2.056667 | 3.386903 |
| 883.0 | 4.0 | 1.0 | 2.889267 | 0.41869 | 2.174895 | 3.838285 |
| 965.0 | 3.0 | 0.0 | 2.889267 | 0.41869 | 2.174895 | 3.838285 |
| 1010.0 | 2.0 | 0.0 | 2.889267 | 0.41869 | 2.174895 | 3.838285 |
| 1022.0 | 1.0 | 0.0 | 2.889267 | 0.41869 | 2.174895 | 3.838285 |
Pass a different format= for pandas or PyArrow output:
na.to_frame(format="pandas")
|
time |
n_risk |
n_event |
estimate |
std_error |
conf_low |
conf_high |
| 0 |
5.0 |
228.0 |
1.0 |
0.004386 |
0.004386 |
0.000618 |
0.031136 |
| 1 |
11.0 |
227.0 |
3.0 |
0.017602 |
0.008801 |
0.006606 |
0.046899 |
| 2 |
12.0 |
224.0 |
1.0 |
0.022066 |
0.009868 |
0.009184 |
0.053015 |
| 3 |
13.0 |
223.0 |
2.0 |
0.031035 |
0.011730 |
0.014795 |
0.065101 |
| 4 |
15.0 |
221.0 |
1.0 |
0.035560 |
0.012573 |
0.017783 |
0.071108 |
| ... |
... |
... |
... |
... |
... |
... |
... |
| 181 |
840.0 |
5.0 |
0.0 |
2.639267 |
0.335859 |
2.056667 |
3.386903 |
| 182 |
883.0 |
4.0 |
1.0 |
2.889267 |
0.418690 |
2.174895 |
3.838285 |
| 183 |
965.0 |
3.0 |
0.0 |
2.889267 |
0.418690 |
2.174895 |
3.838285 |
| 184 |
1010.0 |
2.0 |
0.0 |
2.889267 |
0.418690 |
2.174895 |
3.838285 |
| 185 |
1022.0 |
1.0 |
0.0 |
2.889267 |
0.418690 |
2.174895 |
3.838285 |
186 rows × 7 columns