# first_event()


Build a competing-risks response from several endpoints: the earliest observed event wins.


Usage

``` python
first_event(
    endpoints,
    *,
    censor_at=None,
    start=None,
)
```


Some datasets record each endpoint in its own pair of columns rather than in one outcome column. `mgus2` is an example: `ptime`/`pstat` hold the time to plasma cell malignancy (PCM) and whether it occurred, and `futime`/`death` do the same for death. A competing-risks analysis needs one time and one cause per subject: the first endpoint observed, or censoring if none was.

For each row, the endpoint with the earliest observed event becomes the cause and its time becomes the event time. Ties go to the endpoint listed first. Rows with no observed event are censored at the latest endpoint time (the last time the subject was known to be event-free), or at `censor_at` if given. This helper is Greenwood's own: R's `survival` has no direct equivalent.


## Parameters


`endpoints: Mapping[str, tuple[Any, Any]]`  
A mapping of state name to a `(time, event)` pair, in priority order for ties. `event` is logical or `0`/`1`.

`censor_at: Any = None`  
The time at which rows with no observed event are censored. The default is the latest of the endpoint times.

`start: Any = None`  
Entry times for late entry. When given, the result is a multi-state counting-process response.


## Returns


`Surv`  
A multi-state response whose states are the endpoint names, in order.


## Warns


`UserWarning`  
When a row's event is recorded after another endpoint's follow-up had already ended without an event. This often means the time columns don't share an origin or a unit.


## Examples

Two endpoints for three subjects. Subject 1 has endpoint `"a"` at time 5, subject 2 has `"b"` at time 8, and subject 3 is censored at time 9:


``` python
import greenwood as gw

gw.first_event(
    endpoints={
        "a": ([5.0, 9.0, 4.0], [1, 0, 0]),
        "b": ([7.0, 8.0, 9.0], [0, 1, 0]),
    }
)
```


    Surv(type=mright, n=3, events=2, states=('a', 'b'))


For a data frame such as the bundled `mgus2` (one column pair per endpoint), name the columns with [Outcome.first_event()](Outcome.md#greenwood.Outcome.first_event) and pass `data=` when fitting. PCM is listed first, so a PCM diagnosed at the same time as death counts as PCM:


``` python
mgus2 = gw.load_dataset("mgus2")

cr = gw.Outcome.first_event(endpoints={"pcm": ("ptime", "pstat"), "death": ("futime", "death")})
gw.AalenJohansen().fit(cr, data=mgus2)
```


    AalenJohansen (Aalen-Johansen cumulative incidence)

    states: pcm, death
    n = 1384

           final CIF
    pcm       0.1613
    death     0.8387
