split_episodes()

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

Usage

Source

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() and 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 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().

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:

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"]])