Full API

scitex_seizure_metrics — unified evaluation for seizure detection / forecasting.

Public API:

  • detection.evaluate(y_true, y_proba, threshold, fs, name)

  • forecasting.evaluate(alarms, seizures, policy, total_recording_time, …)

  • forecasting.evaluate_stream(proba, times, seizures, policy, …)

  • forecasting.sweep_thresholds(proba, times, seizures, policy, …)

  • forecasting.sweep_policies(proba, times, seizures, policies, …)

  • forecasting.bootstrap_ci(values, n_boot, ci, rng_seed)

  • bridge.sample_to_alarm(…) / bridge.alarm_to_sample(…)

  • sensitivity_tiw.sensitivity_tiw_curve(scores, policy, labels|seizure_times, …) — empirical sensitivity vs time-in-warning (Karoly 2017 Fig 6)

  • sensitivity_tiw.{chance_sensitivity, binomial_above_chance, surrogate_above_chance}

  • surrogates.{poisson, periodic, persistence} (registered)

  • plots.{sensitivity_vs_fp_per_hour, sensitivity_tiw, sample_vs_alarm_scatter, cadence_ablation, ioc_vs_surrogate, metric_correlation_heatmap}

Data classes:

  • AlarmPolicy(sph_seconds, sop_seconds, cadence_seconds, refractory_seconds, alarm_threshold, merge_consecutive, fp_denominator)

  • MetricsReport (frozen single-row report; .to_frame(), .to_json()). The forecasting regime additionally fills specificity / ppv (alarm precision) / npv / forecasting_f1 on the alarm-vs-interictal-opportunity confusion basis, plus n_tn / n_opportunities and observed lead_time_mean / lead_time_median (per-seizure lead_times_seconds in .extras).

class scitex_seizure_metrics.AlarmPolicy(sph_seconds, sop_seconds, cadence_seconds, refractory_seconds, alarm_threshold=0.5, merge_consecutive=True, fp_denominator='interictal')[source]

Bases: object

Knobs that govern how a continuous prediction stream is converted into discrete alarms, and how those alarms are matched to seizures.

Every alarm-based metric in scitex_seizure_metrics requires an explicit AlarmPolicy so reports are reproducible across papers.

Parameters:
  • sph_seconds (float) – Seizure Prediction Horizon (lead time required between an alarm and the earliest valid seizure). Andrade et al. 2024.

  • sop_seconds (float) – Seizure Occurrence Period (validity window after SPH within which the seizure must occur).

  • cadence_seconds (float) – Time step between successive predictions in the continuous stream. 60 s ≈ once-per-minute, 360 s ≈ once-per- 6-min. Defines the maximum theoretical alarm rate before refractory.

  • refractory_seconds (float) – Minimum gap between consecutive alarms. After an alarm fires, the next earliest alarm is suppressed until this much time has passed. Common choices: SOP, 30 min, 1 h.

  • alarm_threshold (float) – Probability threshold above which a window’s prediction triggers an alarm-candidate.

  • merge_consecutive (bool) – If True, runs of contiguous above-threshold windows count as one alarm (fired at the first window).

  • fp_denominator (Literal['interictal', 'total']) – Whether FP/hr is normalised by total recording time or by interictal-only time (with seizure ± SOP windows removed). The Mormann tradition is “interictal”.

alarm_threshold: float = 0.5
cadence_seconds: float
describe()[source]

Compact dict suitable for serialising into a metric report.

Return type:

dict

fp_denominator: Literal['interictal', 'total'] = 'interictal'
merge_consecutive: bool = True
refractory_seconds: float
sop_seconds: float
sph_seconds: float
class scitex_seizure_metrics.MetricsReport(name='', regime='', roc_auc=None, pr_auc=None, brier=None, balanced_accuracy=None, mcc=None, sensitivity=None, precision=None, f1=None, fp_per_day=None, fp_per_hour=None, n_ref_events=None, n_tp=None, n_fp=None, sph_seconds=None, sop_seconds=None, time_in_warning_frac=None, ioc=None, surrogate_sensitivity=None, specificity=None, ppv=None, npv=None, forecasting_f1=None, n_tn=None, n_opportunities=None, lead_time_mean=None, lead_time_median=None, extras=<factory>)[source]

Bases: object

Single-row evaluation result.

Fields are deliberately flat so the report stacks cleanly across patients/folds via pd.concat([r.to_frame() for r in reports]).

Parameters:
  • name (str)

  • regime (str)

  • roc_auc (float | None)

  • pr_auc (float | None)

  • brier (float | None)

  • balanced_accuracy (float | None)

  • mcc (float | None)

  • sensitivity (float | None)

  • precision (float | None)

  • f1 (float | None)

  • fp_per_day (float | None)

  • fp_per_hour (float | None)

  • n_ref_events (int | None)

  • n_tp (int | None)

  • n_fp (int | None)

  • sph_seconds (float | None)

  • sop_seconds (float | None)

  • time_in_warning_frac (float | None)

  • ioc (float | None)

  • surrogate_sensitivity (float | None)

  • specificity (float | None)

  • ppv (float | None)

  • npv (float | None)

  • forecasting_f1 (float | None)

  • n_tn (int | None)

  • n_opportunities (int | None)

  • lead_time_mean (float | None)

  • lead_time_median (float | None)

  • extras (dict[str, Any])

balanced_accuracy: float | None = None
brier: float | None = None
extras: dict[str, Any]
f1: float | None = None
forecasting_f1: float | None = None
fp_per_day: float | None = None
fp_per_hour: float | None = None
ioc: float | None = None
lead_time_mean: float | None = None
lead_time_median: float | None = None
mcc: float | None = None
n_fp: int | None = None
n_opportunities: int | None = None
n_ref_events: int | None = None
n_tn: int | None = None
n_tp: int | None = None
name: str = ''
npv: float | None = None
ppv: float | None = None
pr_auc: float | None = None
precision: float | None = None
regime: str = ''
roc_auc: float | None = None
sensitivity: float | None = None
sop_seconds: float | None = None
specificity: float | None = None
sph_seconds: float | None = None
surrogate_sensitivity: float | None = None
time_in_warning_frac: float | None = None
to_dict()[source]
Return type:

dict[str, Any]

to_frame()[source]
Return type:

DataFrame

to_json()[source]
Return type:

str