Source code for scitex_seizure_metrics.papers.stirling2021

"""Stirling et al. 2021 (Frontiers in Neurology) replica metrics.

Paper: 'Seizure Forecasting Using a Novel Sub-Scalp Ultra-Long Term
EEG Monitoring System'. Reports detection AUC + cycle-based forecasting
IoC + time-in-warning on a 4-channel sub-scalp device cohort.

Citation: Stirling RE et al., Front Neurol 2021; 12: 713794.
doi:10.3389/fneur.2021.713794
"""
from __future__ import annotations

import numpy as np

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


[docs] def metrics(*, y_true, y_proba, times_seconds=None, seizure_times=None, sph_seconds: float = 60 * 60, sop_seconds: float = 60 * 60, n_surrogate: int = 500, name: str = "stirling2021") -> dict: """Reproduce the detection-AUC + forecasting-IoC panel. Args: y_true: per-window binary detection labels. y_proba: per-window predictions. times_seconds: timestamps (optional; for forecasting metrics). seizure_times: seizure onsets (optional). sph_seconds / sop_seconds: forecasting horizon (default 1h/1h). n_surrogate: surrogate count. name: identifier. Returns: dict with detection_auc, alarm_sensitivity (if forecasting inputs given), ioc, fp_per_hour, time_in_warning_frac. """ out = {"paper": "stirling2021", "name": name} rep = detection.evaluate(y_true, y_proba, name=name) out["detection_auc"] = rep.roc_auc if times_seconds is not None and seizure_times is not None: cadence = float(np.median(np.diff(times_seconds))) if len(times_seconds) > 1 else 60.0 pol = AlarmPolicy( sph_seconds=sph_seconds, sop_seconds=sop_seconds, cadence_seconds=cadence, refractory_seconds=sop_seconds, alarm_threshold=0.5, fp_denominator="interictal", ) frep = forecasting.evaluate_stream( y_proba, times_seconds, seizure_times, pol, n_surrogate=n_surrogate, surrogate="circadian", name=name, ) out["alarm_sensitivity"] = frep.sensitivity out["ioc_vs_circadian"] = frep.ioc out["fp_per_hour"] = frep.fp_per_hour out["time_in_warning_frac"] = frep.time_in_warning_frac return out