Free-Day Outcomes#

Source-agnostic “free-days-through-day-N” outcomes — ventilator-free days, RRT-free days, vasopressor-free days, and so on. free_days() counts the days in a follow-up horizon free of a clinical event and, optionally, emits the competing-risk components the VFD literature recommends reporting alongside the composite.

The FreeDaysVariable variable type wraps this engine so an outcome is declared entirely in vars.json ("type": "free_days") with a single episode dependency, and add_horizon_variable() adds one over a [t0, t0 + horizon] window.

corr_vars.utils.outcomes.free_days(obs, episodes, *, primary_key, window, method='last_event', death_rule='zero_if_dead', recovery_threshold=None, death_col=None, censor_col=None, presence=None, recordtime='recordtime', recordtime_end='recordtime_end', merge_gap=None, output_name='free_days', with_detail=False)[source]#

Count the days in a follow-up horizon free of some clinical event.

The horizon [T0, T0 + H] is taken from window (T0 = tmin, H = tmax - tmin in whole 24h days) and split into H day-blocks anchored at T0. Each block is scored free or not by method; the free blocks are summed.

Parameters:
  • obs (DataFrame) – One row per observation, providing the window anchor columns, the death column and (optionally) the censoring expression’s inputs.

  • episodes (DataFrame) – Event intervals (recordtime / recordtime_end) for the underlying concept, e.g. ventilation or vasopressor episodes. May hold several rows per observation, or none (then every day is free).

  • primary_key (str) – The observation key shared by obs and episodes.

  • window (TimeWindow) – The follow-up window; tmin is T0, tmax is T0 + horizon.

  • method (Literal['last_event', 'day_grid']) – "last_event" (free tail after the last episode end) or "day_grid" (per-day union; gaps restore freedom).

  • death_rule (Literal['zero_if_dead', 'alive_days', 'negative_if_death']) – "zero_if_dead" (any death in the horizon scores 0, ARDSnet), "negative_if_death" (death scores -1, the newer ordinal definition that ranks death below every survivor), or "alive_days" (days before death still count).

  • recovery_threshold (str | timedelta | None) – day_grid only — a day stays non-free until this long after the last episode end (e.g. "7d" for RRT recovery).

  • death_col (str | Expr | None) – Column name or expression over obs giving the death timestamp. None (the default, source-agnostic) or a name absent from obs disables the death rule.

  • censor_col (str | Expr | None) – Column name or expression over obs giving the last observable time per observation; when it precedes END the horizon is unobserved and the result is null. None or a name absent from obs disables censoring.

  • presence (DataFrame | None) – Optional observation-window intervals (recordtime / recordtime_end, e.g. in-hospital stays), keyed by primary_key. When given, a day counts as free only if it is also observed (covered by a presence interval) — the standard scoring intersected with presence — so an unobserved gap (discharge → readmission) is not miscredited as free. An open (null-end) interval is treated as observed through END. None keeps the standard behaviour (every day in [T0, END] is a candidate).

  • recordtime_end (str) – Episode interval columns in episodes.

  • merge_gap (str | timedelta | None) – When set (e.g. "48h"), episodes separated by at most this long are first merged into one continuous interval (_merge_episodes()), so a short gap — a reintubation within 48h — does not count as free. Under last_event this bites when a re-event just past the horizon bridges the last in-horizon episode; under day_grid it also drops short interior gaps while keeping genuine long ones.

  • output_name (str) – Name of the produced count column.

  • with_detail (bool) – Also emit a {output_name}_detail struct carrying the competing-risk components (event_time_days, event_type, died_in_horizon, censored, n_episodes) plus unobserved_days (free days removed by the presence intersection, else 0). See _detail_frame().

  • recordtime (str)

  • recordtime_end

Returns:

[primary_key, output_name] (one row per observation, an Int32 free-day count, null where censored), plus a {output_name}_detail struct column when with_detail is set.

Return type:

pl.DataFrame

Type Aliases#

corr_vars.utils.outcomes.FreeDaysMethod#

alias of Literal[‘last_event’, ‘day_grid’]

corr_vars.utils.outcomes.DeathRule#

alias of Literal[‘zero_if_dead’, ‘alive_days’, ‘negative_if_death’]

corr_vars.utils.outcomes.EventType#

Terminal follow-up status recorded in the detail struct. Concept-neutral so the same schema serves ventilation, vasopressor, RRT, … — the “event” is named by the variable itself.

alias of Literal[‘liberated’, ‘died’, ‘censored’, ‘ongoing_at_horizon’]