## AalenJohansen


Aalen-Johansen estimator of cumulative incidence functions for competing risks.


Usage

``` python
AalenJohansen(
    *,
    conf_level=0.95,
)
```


In survival analysis, competing risks occur when subjects can experience multiple types of events (e.g., progression to malignancy vs. death from other causes), and experiencing one event precludes the others. The Aalen-Johansen estimator extends the Kaplan-Meier approach to this setting by estimating the cumulative incidence function (CIF) for each cause: the probability of experiencing that specific cause by time t, accounting for competition from other causes.

Unlike naive estimates that ignore censoring or competing events, the Aalen-Johansen CIF correctly accounts for both. It is computed using transition probabilities between states via generalized Kaplan-Meier estimates. Call [fit()](AFT.md#greenwood.AFT.fit) with a multi-state [Surv](Surv.md#greenwood.Surv) response (built with [Surv.multistate()](Surv.md#greenwood.Surv.multistate)) to obtain estimates for each competing cause. Results are returned as tidy DataFrames with one row per combination of stratum, cause, and time.

The estimator uses the formula \\\mathrm{CIF}\_j(t) = \sum\_{s \le t} \hat{S}(s^-) P\_{0j}(s)\\, where \\\hat{S}(s^-)\\ is the probability of being event-free before time \\s\\, and \\P\_{0j}(s)\\ is the transition probability from censoring to cause \\j\\. Confidence intervals use the Greenwood-style variance estimator on the complementary log-log scale for improved coverage.


## Parameters


`conf_level: float = ``0.95`  
Confidence level for the (Wald) confidence intervals (default 0.95).


## Returns


`Fitted estimator`  
Call [fit()](AFT.md#greenwood.AFT.fit) to produce a fitted estimator with cached results (`states_`, and internal transition matrices), accessible as tidy DataFrames.


## Details

Call `fit(surv, by=...)` with a multi-state [Surv](Surv.md#greenwood.Surv) response (built with [Surv.multistate](Surv.md#greenwood.Surv.multistate), where [event](Surv.md#greenwood.Surv.event) codes are 0 for censoring and `1..K` for the competing causes). Results are tidy frames via [to_frame()](AFT.md#greenwood.AFT.to_frame) (optionally `format=`) with one row per stratum, cause, and time.


## Examples

The bundled `mgus2` dataset follows monoclonal-gammopathy patients who may progress to plasma-cell malignancy (`"pcm"`) or die first, a competing-risks setup. Build the competing-risks response by combining the progression and death indicators into a single cause code (0 censored, 1 progression, 2 death), then fit the estimator. Printing the fitted object reports the final cumulative incidence for each cause.


``` python
import greenwood as gw

mg = gw.load_dataset("mgus2", backend="pandas")
etime = mg["ptime"].where(mg["pstat"] == 1, mg["futime"])
cause = mg["pstat"].where(mg["pstat"] == 1, 2 * mg["death"])
cr = gw.Surv.multistate(etime, event=cause, states=("pcm", "death"))
aj = gw.AalenJohansen().fit(cr)
aj
```


    AalenJohansen (Aalen-Johansen cumulative incidence)

    states: pcm, death
    n = 1384

           final CIF
    pcm       0.1613
    death     0.8387


## Methods

| Name | Description |
|----|----|
| [fit()](#fit) | Fit cumulative incidence functions to a competing-risks response. |
| [to_frame()](#to_frame) | Return cumulative-incidence estimates as a DataFrame. |

------------------------------------------------------------------------


#### fit()


Fit cumulative incidence functions to a competing-risks response.


Usage

``` python
fit(surv, *, by=None)
```


Computes the cumulative incidence function (CIF) for each cause-of-interest from a multi-state [Surv](Surv.md#greenwood.Surv) response. Unlike Kaplan-Meier (which handles only a single event type), the Aalen-Johansen estimator accounts for competing events: subjects who experience a competing cause are removed from the risk set, preventing overly optimistic estimates of the probability of experiencing the target cause. Results are stored in the fitted object; access them via [to_frame()](AFT.md#greenwood.AFT.to_frame) (optionally `format=`).

The Aalen-Johansen estimator generalizes both Kaplan-Meier and Nelson-Aalen to the competing-risks setting. For each cause \\j\\, it estimates \\F_j(t)\\, the cumulative probability of experiencing cause \\j\\ by time \\t\\, accounting for all competing causes. The CIFs sum to the overall event probability at any time. Pass `by=` to produce separate CIF estimates per group (stratified competing-risks analysis).


##### Parameters


`surv: Surv`  
A multi-state [Surv](Surv.md#greenwood.Surv) response built with [Surv.multistate()](Surv.md#greenwood.Surv.multistate). Must have multiple causes-of-interest. Raises `ValueError` if a single-event response is passed (use [KaplanMeier](KaplanMeier.md#greenwood.KaplanMeier) for that).

`by: Any = None`  
Optional grouping variable (e.g., a column or array). Produces one set of cumulative incidence functions per unique value of `by`. Default (`None`): fit a single, unstratified set of CIFs.


##### Returns


`AalenJohansen`  
The fitted estimator object itself (for method chaining) with cached cumulative incidence results (time arrays, CIF per cause, confidence bands) accessible via [to_frame()](AFT.md#greenwood.AFT.to_frame) (optionally `format=`).


##### Details

The Aalen-Johansen estimator is a product-integral estimator of the CIF: \\F_j(t) = \int \hat{S}\_{-}(u) \\ dM_j(u)\\, where \\\hat{S}\_{-}(u)\\ is the estimated probability of surviving (remaining uncensored) just before \\u\\, and \\M_j(u)\\ is the counting process for cause \\j\\. It reduces to Kaplan-Meier when there is only one cause and no censoring.

Left truncation is not yet supported. Multi-state responses must be built with [Surv.multistate()](Surv.md#greenwood.Surv.multistate).


##### Examples

Fit cumulative incidence functions on the competing-risks `mgus2` dataset, where subjects can experience plasma-cell malignancy (pcm) or death:


``` python
import greenwood as gw

mg = gw.load_dataset("mgus2", backend="pandas")
etime = mg["ptime"].where(mg["pstat"] == 1, mg["futime"])
cause = mg["pstat"].where(mg["pstat"] == 1, 2 * mg["death"])
cr = gw.Surv.multistate(etime, event=cause, states=("pcm", "death"))
aj = gw.AalenJohansen().fit(cr)
aj
```


    AalenJohansen (Aalen-Johansen cumulative incidence)

    states: pcm, death
    n = 1384

           final CIF
    pcm       0.1613
    death     0.8387


Fit stratified cumulative incidence functions by sex to compare risk accumulation:


``` python
aj_stratified = gw.AalenJohansen().fit(cr, by=mg["sex"])
aj_stratified
```


    AalenJohansen (Aalen-Johansen cumulative incidence)

    states: pcm, death
    strata: 2


------------------------------------------------------------------------


#### to_frame()


Return cumulative-incidence estimates as a DataFrame.


Usage

``` python
to_frame(*, format=None)
```


Exports the Aalen-Johansen fit with one row per cause and time point, including the risk set, cumulative-incidence estimate, 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 `cause`, `time`, `n_risk`, `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 the estimator on the competing-risks `mgus2` data and export the cumulative- incidence functions as a Polars frame:


``` python
import greenwood as gw

mg = gw.load_dataset("mgus2", backend="pandas")
etime = mg["ptime"].where(mg["pstat"] == 1, mg["futime"])
cause = mg["pstat"].where(mg["pstat"] == 1, 2 * mg["death"])
cr = gw.Surv.multistate(etime, event=cause, states=("pcm", "death"))
aj = gw.AalenJohansen().fit(cr)
aj.to_frame(format="polars")
```


shape: (536, 7)

| cause   | time  | n_risk | estimate | std_error | conf_low | conf_high |
|---------|-------|--------|----------|-----------|----------|-----------|
| str     | f64   | f64    | f64      | f64       | f64      | f64       |
| "pcm"   | 1.0   | 1384.0 | 0.0      | 0.0       | 0.0      | 0.0       |
| "pcm"   | 2.0   | 1341.0 | 0.001446 | 0.001022  | 0.0      | 0.003449  |
| "pcm"   | 3.0   | 1311.0 | 0.001446 | 0.001022  | 0.0      | 0.003449  |
| "pcm"   | 4.0   | 1296.0 | 0.002169 | 0.001251  | 0.0      | 0.004621  |
| "pcm"   | 5.0   | 1279.0 | 0.002892 | 0.001444  | 0.000062 | 0.005723  |
| …       | …     | …      | …        | …         | …        | …         |
| "death" | 341.0 | 5.0    | 0.784208 | 0.020933  | 0.743179 | 0.825237  |
| "death" | 350.0 | 4.0    | 0.784208 | 0.020933  | 0.743179 | 0.825237  |
| "death" | 373.0 | 3.0    | 0.784208 | 0.020933  | 0.743179 | 0.825237  |
| "death" | 394.0 | 2.0    | 0.784208 | 0.020933  | 0.743179 | 0.825237  |
| "death" | 424.0 | 1.0    | 0.838708 | 0.028288  | 0.783265 | 0.894152  |


Request a different backend with `format=`:


``` python
aj.to_frame(format="pandas")
```


|     | cause | time  | n_risk | estimate | std_error | conf_low | conf_high |
|-----|-------|-------|--------|----------|-----------|----------|-----------|
| 0   | pcm   | 1.0   | 1384.0 | 0.000000 | 0.000000  | 0.000000 | 0.000000  |
| 1   | pcm   | 2.0   | 1341.0 | 0.001446 | 0.001022  | 0.000000 | 0.003449  |
| 2   | pcm   | 3.0   | 1311.0 | 0.001446 | 0.001022  | 0.000000 | 0.003449  |
| 3   | pcm   | 4.0   | 1296.0 | 0.002169 | 0.001251  | 0.000000 | 0.004621  |
| 4   | pcm   | 5.0   | 1279.0 | 0.002892 | 0.001444  | 0.000062 | 0.005723  |
| ... | ...   | ...   | ...    | ...      | ...       | ...      | ...       |
| 531 | death | 341.0 | 5.0    | 0.784208 | 0.020933  | 0.743179 | 0.825237  |
| 532 | death | 350.0 | 4.0    | 0.784208 | 0.020933  | 0.743179 | 0.825237  |
| 533 | death | 373.0 | 3.0    | 0.784208 | 0.020933  | 0.743179 | 0.825237  |
| 534 | death | 394.0 | 2.0    | 0.784208 | 0.020933  | 0.743179 | 0.825237  |
| 535 | death | 424.0 | 1.0    | 0.838708 | 0.028288  | 0.783265 | 0.894152  |

536 rows × 7 columns
