## split_episodes()


Convert repeated-measurement data into counting-process (episode-split) format.


Usage

``` python
split_episodes(
    baseline,
    visits,
    *,
    id,
    time,
    event,
    visit_time,
    carry_forward=True,
    format=None
)
```


Takes a subject-level baseline table and a long-format visits table, and merges them into the interval-per-row counting-process layout required by [Surv.counting()](Surv.md#greenwood.Surv.counting) and [CoxPH](CoxPH.md#greenwood.CoxPH). Each row in the output represents a constant-covariate interval `(tstart, tstop]` for one subject.

The covariate value measured at visit time `v` applies to the interval `[v, next_v)`. The event indicator is 1 only on the final interval for subjects who experienced the event; all earlier intervals carry 0.


## Parameters


`baseline: Any`  
One row per subject. Must contain the `id`, `time`, and [event](Surv.md#greenwood.Surv.event) columns. Any additional columns are treated as time-fixed covariates and carried through to every output row for that subject.

`visits: Any`  
One row per (subject, visit). Must contain the `id` and `visit_time` columns. Every other column is treated as a time-varying covariate.

`id: str`  
Column name linking `baseline` and `visits`.

`time: str`  
Column in `baseline` giving the end of follow-up (right-censored exit time).

`event: str`  
Column in `baseline` giving the event indicator.

`visit_time: str`  
Column in `visits` giving the measurement time for each row.

`carry_forward: bool = ``True`  
If `True` (default), the last observed covariate value is carried forward to the end of follow-up (LOCF), producing a final interval `(last_visit, time]`. If `False`, follow-up is truncated at the last visit; the trailing interval is dropped and the subject is effectively administratively censored there.

`format: str | None = None`  
Output format: `None` (default), `"pandas"`, `"polars"`, or `"pyarrow"`.

- `None` (default): auto-detect, trying Polars first, then Pandas, then PyArrow.
- `"pandas"`: return a `pandas.DataFrame`.
- `"polars"`: return a `polars.DataFrame`.
- `"pyarrow"`: return a `pyarrow.Table`.


## Returns


`pandas.DataFrame, polars.DataFrame, or pyarrow.Table`  
Counting-process dataset with columns `(id, tstart, tstop, event, [time-fixed covariates], [time-varying covariates])`. Ready to pass directly to `Surv.counting(tstart, tstop, event)` and [CoxPH.fit()](CoxPH.md#greenwood.CoxPH.fit).


## Raises


`ValueError`  
If required columns are missing, if any visit time exceeds the subject's follow-up end, or if the resulting dataset is empty.


## Examples

Build a minimal TVC dataset and fit a Cox model:


``` python
import pandas as pd
import greenwood as gw

baseline = pd.DataFrame({
    "id":    [1, 2, 3],
    "time":  [10.0, 8.0, 12.0],
    "event": [1, 0, 1],
})
visits = pd.DataFrame({
    "id":       [1, 1, 2, 3, 3, 3],
    "day":      [0.0, 5.0, 0.0, 0.0, 4.0, 8.0],
    "bili":     [1.2, 2.4, 0.8, 3.1, 2.9, 4.0],
})

long = gw.split_episodes(
    baseline, visits, id="id", time="time", event="event", visit_time="day"
)
y = gw.Surv.counting(long["tstart"], long["tstop"], long["event"])
cox = gw.CoxPH().fit(y, long[["bili"]])
```
