Auto-generated by analysis/phase1_floors/floors.py. Re-run any time to refresh against current target_snapshots + naive_baselines.
- Train window (used to BUILD naive baselines by the writers): up to 2024-12-31.
- Test window: 2025-01-01 to 2026-05-15.
- Two test slices:
test_2025_current— rows withsource_epoch = source_2025_currentonly. Primary decision basis. 2024 gap (source_2024_gap) is a known source anomaly per the source_epochs catalogue.test_all_post_train— every row in the test window regardless of epoch. Reported for context.
- Continuous: MAE / RMSE per
baseline_kind; bootstrap CI on MAE with 1000 resamples. - Classification: precision at recall = 0.5 (primary), lift over base rate (secondary), AUC (supplementary, not a decision criterion). Stratified bootstrap (positives and negatives resampled separately) preserves class counts on sparse targets like
event_strict_t1_t3.
Eligible test rows: 421
| baseline_kind | n | MAE | RMSE | MAE 95% bootstrap CI |
|---|---|---|---|---|
| persistence_yesterday | 404 | 0.0422 | 0.0578 | [0.0386, 0.0463] |
| rolling_7d_mean | 420 | 0.0261 | 0.0341 | [0.0239, 0.0283] |
| rolling_30d_mean | 420 | 0.0253 | 0.0329 | [0.0233, 0.0273] |
| ewma_45d | 420 | 0.0251 | 0.0324 | [0.0231, 0.0271] |
Best naive baseline (lowest MAE): ewma_45d at MAE = 0.0251.
Eligible test rows: 333
| baseline_kind | n | MAE | RMSE | MAE 95% bootstrap CI |
|---|---|---|---|---|
| persistence_yesterday | 315 | 5.3820 | 7.2855 | [4.8505, 5.9466] |
| rolling_7d_mean | 331 | 3.6197 | 4.5476 | [3.3390, 3.8964] |
| rolling_30d_mean | 331 | 3.3196 | 4.1883 | [3.0543, 3.5879] |
| ewma_45d | 332 | 3.1911 | 4.0647 | [2.9263, 3.4626] |
Best naive baseline (lowest MAE): ewma_45d at MAE = 3.1911.
Eligible test rows: 401, positives: 122, base rate: 0.3042
Metric: precision at recall = 0.5, with lift over base rate at the same recall.
| baseline_kind | n paired | precision@R=0.5 | lift | AUC | precision 95% CI | captured pos |
|---|---|---|---|---|---|---|
| event_base_rate | 400 | 0.328 | 1.08 | 0.557 | [0.296, 0.368] | 61 |
| persistence_yesterday (inline) | 393 | 0.785 | 2.58 | 0.848 | [0.723, 0.845] | 95 |
Best naive baseline (highest precision@recall=0.5): persistence_yesterday (inline) at precision = 0.785 (lift 2.58× over base rate).
Eligible test rows: 401, positives: 9, base rate: 0.0224
Metric: precision at recall = 0.5, with lift over base rate at the same recall.
| baseline_kind | n paired | precision@R=0.5 | lift | AUC | precision 95% CI | captured pos |
|---|---|---|---|---|---|---|
| event_base_rate | 400 | 0.024 | 1.07 | 0.563 | [0.022, 0.086] | 5 |
| persistence_yesterday (inline) | 393 | 0.667 | 29.70 | 0.829 | [0.023, 1.000] | 6 |
Best naive baseline (highest precision@recall=0.5): persistence_yesterday (inline) at precision = 0.667 (lift 29.70× over base rate).
Eligible test rows: 349, positives: 78, base rate: 0.2235
Metric: precision at recall = 0.5, with lift over base rate at the same recall.
| baseline_kind | n paired | precision@R=0.5 | lift | AUC | precision 95% CI | captured pos |
|---|---|---|---|---|---|---|
| event_base_rate | 349 | 0.415 | 1.86 | 0.574 | [0.191, 0.549] | 39 |
| persistence_yesterday (inline) | 341 | 0.947 | 4.24 | 0.979 | [0.900, 0.987] | 72 |
Best naive baseline (highest precision@recall=0.5): persistence_yesterday (inline) at precision = 0.947 (lift 4.24× over base rate).
Eligible test rows: 398, positives: 98, base rate: 0.2462
Metric: precision at recall = 0.5, with lift over base rate at the same recall.
| baseline_kind | n paired | precision@R=0.5 | lift | AUC | precision 95% CI | captured pos |
|---|---|---|---|---|---|---|
| event_base_rate | 397 | 0.368 | 1.49 | 0.676 | [0.323, 0.435] | 50 |
| persistence_yesterday (inline) | 396 | 0.918 | 3.73 | 0.951 | [0.867, 0.967] | 90 |
Best naive baseline (highest precision@recall=0.5): persistence_yesterday (inline) at precision = 0.918 (lift 3.73× over base rate).
Eligible test rows: 421
| baseline_kind | n | MAE | RMSE | MAE 95% bootstrap CI |
|---|---|---|---|---|
| persistence_yesterday | 404 | 0.0422 | 0.0578 | [0.0386, 0.0463] |
| rolling_7d_mean | 420 | 0.0261 | 0.0341 | [0.0239, 0.0283] |
| rolling_30d_mean | 420 | 0.0253 | 0.0329 | [0.0233, 0.0273] |
| ewma_45d | 420 | 0.0251 | 0.0324 | [0.0231, 0.0271] |
Best naive baseline (lowest MAE): ewma_45d at MAE = 0.0251.
Eligible test rows: 333
| baseline_kind | n | MAE | RMSE | MAE 95% bootstrap CI |
|---|---|---|---|---|
| persistence_yesterday | 315 | 5.3820 | 7.2855 | [4.8505, 5.9466] |
| rolling_7d_mean | 331 | 3.6197 | 4.5476 | [3.3390, 3.8964] |
| rolling_30d_mean | 331 | 3.3196 | 4.1883 | [3.0543, 3.5879] |
| ewma_45d | 332 | 3.1911 | 4.0647 | [2.9263, 3.4626] |
Best naive baseline (lowest MAE): ewma_45d at MAE = 3.1911.
Eligible test rows: 401, positives: 122, base rate: 0.3042
Metric: precision at recall = 0.5, with lift over base rate at the same recall.
| baseline_kind | n paired | precision@R=0.5 | lift | AUC | precision 95% CI | captured pos |
|---|---|---|---|---|---|---|
| event_base_rate | 400 | 0.328 | 1.08 | 0.557 | [0.296, 0.368] | 61 |
| persistence_yesterday (inline) | 393 | 0.785 | 2.58 | 0.848 | [0.723, 0.845] | 95 |
Best naive baseline (highest precision@recall=0.5): persistence_yesterday (inline) at precision = 0.785 (lift 2.58× over base rate).
Eligible test rows: 401, positives: 9, base rate: 0.0224
Metric: precision at recall = 0.5, with lift over base rate at the same recall.
| baseline_kind | n paired | precision@R=0.5 | lift | AUC | precision 95% CI | captured pos |
|---|---|---|---|---|---|---|
| event_base_rate | 400 | 0.024 | 1.07 | 0.563 | [0.022, 0.086] | 5 |
| persistence_yesterday (inline) | 393 | 0.667 | 29.70 | 0.829 | [0.023, 1.000] | 6 |
Best naive baseline (highest precision@recall=0.5): persistence_yesterday (inline) at precision = 0.667 (lift 29.70× over base rate).
Eligible test rows: 349, positives: 78, base rate: 0.2235
Metric: precision at recall = 0.5, with lift over base rate at the same recall.
| baseline_kind | n paired | precision@R=0.5 | lift | AUC | precision 95% CI | captured pos |
|---|---|---|---|---|---|---|
| event_base_rate | 349 | 0.415 | 1.86 | 0.574 | [0.191, 0.549] | 39 |
| persistence_yesterday (inline) | 341 | 0.947 | 4.24 | 0.979 | [0.900, 0.987] | 72 |
Best naive baseline (highest precision@recall=0.5): persistence_yesterday (inline) at precision = 0.947 (lift 4.24× over base rate).
Eligible test rows: 398, positives: 98, base rate: 0.2462
Metric: precision at recall = 0.5, with lift over base rate at the same recall.
| baseline_kind | n paired | precision@R=0.5 | lift | AUC | precision 95% CI | captured pos |
|---|---|---|---|---|---|---|
| event_base_rate | 397 | 0.368 | 1.49 | 0.676 | [0.323, 0.435] | 50 |
| persistence_yesterday (inline) | 396 | 0.918 | 3.73 | 0.951 | [0.867, 0.967] | 90 |
Best naive baseline (highest precision@recall=0.5): persistence_yesterday (inline) at precision = 0.918 (lift 3.73× over base rate).
Interpretation note: persistence_yesterday for classification is a window-overlap artifact, not a real floor
persistence_yesterday scores extremely well on every classification target. That does NOT reflect predictive signal. The forward-window labels overlap heavily between adjacent dates:
event_t1_t3for datetcoverst+1..t+3; for datet+1coverst+2..t+4. 2 of 3 days shared, so adjacent labels are by construction correlated. Persistence is exploiting label-window overlap, not predicting unseen physiology.event_strict_t1_t3same overlap shape.chronic_labelandchronic_acute_densitylook 14 days forward; adjacent labels share 13 of 14 days. Persistence is essentially predicting the overlap, which trivially carries.
The honest classification floor is event_base_rate (the 90-day rolling prior probability). Its lift over base rate at recall = 0.5 is the real benchmark a model must beat to add value.
Floors a future model must beat on the test_2025_current slice. For classification, the floor is event_base_rate (per the note above); persistence is reported in the tables for transparency but is not the decision metric.
| target | type | floor (best naive) | floor metric | floor CI half-width | model headroom? |
|---|---|---|---|---|---|
| recovery_stability / rolling_3d | continuous | ewma_45d |
MAE 0.0251 | ±0.002 | low (close to noise floor) — model needs MAE materially below CI lower bound, target SD 0.033 |
| passive_efficiency / rolling_3d | continuous | ewma_45d |
MAE 3.1911 | ±0.268 | low (close to noise floor) — model needs MAE materially below CI lower bound, target SD 4.226 |
| acute_risk / event_t1_t3 | binary | event_base_rate |
precision 0.328, lift 1.08× | ±0.036 | low — AUC 0.557; 122 positives in 401 rows |
| acute_risk / event_strict_t1_t3 | binary | event_base_rate |
precision 0.024, lift 1.07× | ±0.032 | insufficient evidence — AUC 0.563; 9 positives in 401 rows |
| chronic_load / chronic_label | binary | event_base_rate |
precision 0.415, lift 1.86× | ±0.179 | low — AUC 0.574; 78 positives in 349 rows |
| chronic_load / chronic_acute_density | binary | event_base_rate |
precision 0.368, lift 1.49× | ±0.056 | modest — AUC 0.676; 98 positives in 398 rows |
Headroom verdicts derived programmatically:
- Continuous: by MAE / target SD ratio (
<0.4potentially significant,<0.7modest, otherwise low). - Classifier: by
event_base_rateAUC + positive count (positives<20insufficient evidence; AUC<0.5label likely mis-tuned;<0.55very low;<0.60low;<0.70modest;≥0.70potentially significant).
- Retune
chronic_acute_densitythreshold if its positive rate is far from the 15–30% operationally-useful band. Raise event count threshold; bumpchronicLoadFormulaVersion; re-backfill via the admin endpoint; re-run floors. The decision summary above will reflect the change automatically. event_strict_t1_t3is too sparse for an independent classifier while positives stay below ~30. Either accept that strict remains a silent diagnostic only, or relax the strict criterion (e.g. ±1.0σ instead of ±1.5σ) so it becomes informative for Phase 1.- Investigate 2022 strict event spike (5.7% vs 1–2% in other years). Possible illness cluster / lifestyle change / sensor artifact. Narrative review before feeding into trained models.
- Continuous floors are close to noise floor if MAE / target SD exceeds 0.7. Phase 1 should ask whether the extra features (sleep architecture, intraday HR variability) actually shift this number.
- Persistence is not a useful baseline for forward-window classification labels — the window-overlap math dominates. Either drop the persistence column from the report or change classifier labels to disjoint windows (
t+1instead oft+1..t+3) if persistence-style autocorrelation is needed as a real floor.