Source code for scitex_seizure_metrics.papers.proix2021
"""Proix et al. 2021 (Lancet Neurology) replica metrics.
Paper: 'Forecasting seizure risk in adults with focal epilepsy: a
development and validation study'. Multi-day-horizon forecasting using
multidien IEA cycles on RNS data. Reports:
- IoC (Improvement-over-Chance) at horizons 1 h, 1 d, 3 d.
- AUC of sensitivity vs proportion-time-in-warning.
- Brier skill score.
Citation: Proix T et al., Lancet Neurol 2021; 20: 127–135.
doi:10.1016/S1474-4422(20)30396-3
"""
from __future__ import annotations
import numpy as np
from .. import forecasting
from ..policy import AlarmPolicy
HORIZONS_DEFAULT = {
"1h": 3600.0,
"1d": 86400.0,
"3d": 3 * 86400.0,
}
[docs]
def metrics(*, y_proba, times_seconds, seizure_times,
horizons_seconds: dict | None = None,
n_surrogate: int = 500,
name: str = "proix2021") -> dict:
"""Reproduce the multi-horizon IoC panel.
Args:
y_proba: per-window predictions.
times_seconds: matching timestamps.
seizure_times: seizure onsets.
horizons_seconds: dict mapping horizon-label to SOP-seconds; the
forecasting horizon. Defaults to 1h / 1d / 3d.
n_surrogate: surrogate count.
name: identifier.
Returns:
dict with per-horizon: sensitivity, ioc, fp_per_hour,
time_in_warning_frac. Plus a multidien_baseline IoC vs
7-day-period surrogate.
"""
if horizons_seconds is None:
horizons_seconds = HORIZONS_DEFAULT
cadence = float(np.median(np.diff(times_seconds))) if len(times_seconds) > 1 else 3600.0
out = {"paper": "proix2021", "name": name, "horizons": {}}
for label, sop in horizons_seconds.items():
pol = AlarmPolicy(
sph_seconds=0.0, sop_seconds=sop,
cadence_seconds=cadence, refractory_seconds=sop,
alarm_threshold=0.5, fp_denominator="interictal",
)
rep_p = forecasting.evaluate_stream(
y_proba, times_seconds, seizure_times, pol,
n_surrogate=n_surrogate, surrogate="poisson", name=name,
)
rep_md = forecasting.evaluate_stream(
y_proba, times_seconds, seizure_times, pol,
n_surrogate=n_surrogate, surrogate="multidien", name=name,
)
out["horizons"][label] = {
"sensitivity": rep_p.sensitivity,
"ioc_vs_poisson": rep_p.ioc,
"ioc_vs_multidien": rep_md.ioc,
"fp_per_hour": rep_p.fp_per_hour,
"time_in_warning_frac": rep_p.time_in_warning_frac,
}
return out