Source code for scitex_seizure_metrics.papers.karoly2017

"""Karoly et al. 2017 (Brain) replica metrics.

Paper: 'The circadian profile of epilepsy improves seizure forecasting'.
Reports: AUROC + Brier score + reliability + improvement-over-circadian
baseline. Per-window evaluation; SPH 30–60 min.

Citation: Karoly PJ et al., Brain 2017; 140: 2169–2182.
doi:10.1093/brain/awx173
"""
from __future__ import annotations

import numpy as np

from .. import calibration, detection, forecasting
from ..policy import AlarmPolicy


[docs] def metrics(*, y_true, y_proba, times_seconds=None, seizure_times=None, sph_seconds: float = 30 * 60, sop_seconds: float = 30 * 60, n_surrogate: int = 500, name: str = "karoly2017") -> dict: """Reproduce the metric panel from Karoly 2017. Args: y_true: per-window binary labels. y_proba: per-window predicted probabilities. times_seconds: optional per-window timestamps; required if forecasting metrics are wanted (alarm-based). seizure_times: optional seizure onset timestamps; required if forecasting metrics are wanted. sph_seconds: prediction horizon (Karoly: 30–60 min). sop_seconds: occurrence period. n_surrogate: surrogates for IoC. name: identifier carried into the report. Returns: dict with keys: auroc, brier, reliability, resolution, ece, alarm_sensitivity (if forecasting inputs given), ioc_vs_circadian, ioc_vs_poisson. """ out = {"paper": "karoly2017", "name": name} rep = detection.evaluate(y_true, y_proba, name=name) out["auroc"] = rep.roc_auc out["brier"] = rep.brier cal = calibration.calibration_report(y_true, y_proba, n_bins=10) out["reliability"] = cal.reliability out["resolution"] = cal.resolution out["ece"] = cal.expected_calibration_error if times_seconds is not None and seizure_times is not None: policy = AlarmPolicy( sph_seconds=sph_seconds, sop_seconds=sop_seconds, cadence_seconds=float(np.median(np.diff(times_seconds))), refractory_seconds=sph_seconds + sop_seconds, ) rep_circadian = forecasting.evaluate_stream( y_proba, times_seconds, seizure_times, policy, n_surrogate=n_surrogate, surrogate="circadian", name=name, ) rep_poisson = forecasting.evaluate_stream( y_proba, times_seconds, seizure_times, policy, n_surrogate=n_surrogate, surrogate="poisson", name=name, ) out["alarm_sensitivity"] = rep_circadian.sensitivity out["ioc_vs_circadian"] = rep_circadian.ioc out["ioc_vs_poisson"] = rep_poisson.ioc out["fp_per_hour"] = rep_circadian.fp_per_hour out["time_in_warning_frac"] = rep_circadian.time_in_warning_frac return out