From 03dcb4329ba8acc18b9a46b8c7ec359cdba95fb9 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Fri, 20 Mar 2026 21:17:37 +0800 Subject: [PATCH] Refine EMOS calibration and add Chinese training report --- .../probability_calibration/default.json | 29 +- .../evaluation_report.json | 118 +-- .../shadow_report.json | 736 +++++++++--------- docs/EMOS_TRAINING_REPORT_ZH.md | 311 ++++++++ src/analysis/probability_calibration.py | 116 ++- tests/test_probability_calibration.py | 11 +- 6 files changed, 879 insertions(+), 442 deletions(-) create mode 100644 docs/EMOS_TRAINING_REPORT_ZH.md diff --git a/artifacts/probability_calibration/default.json b/artifacts/probability_calibration/default.json index 0c5fdb55..80ebc4b4 100644 --- a/artifacts/probability_calibration/default.json +++ b/artifacts/probability_calibration/default.json @@ -1,6 +1,6 @@ { - "version": "emos-20260320123829", - "trained_at": "2026-03-20T12:38:29.985991+00:00", + "version": "emos-20260320130245", + "trained_at": "2026-03-20T13:02:45.903772+00:00", "global": { "mu": { "intercept": -1.57406048, @@ -17,9 +17,20 @@ "max_so_far_gap_coef": 0.0 } }, + "sigma_constraints": { + "min_ratio": 0.85, + "max_ratio": 1.35, + "absolute_min": 0.25, + "absolute_max": 3.0 + }, + "selection_guardrails": { + "max_mae_increase": 0.02, + "max_bucket_hit_drop": 0.01, + "max_bucket_brier_increase": 0.05 + }, "blending": { "alpha_mu": 0.0, - "alpha_sigma": 1.0 + "alpha_sigma": 0.0 }, "cities": { "ankara": { @@ -145,15 +156,17 @@ }, "metrics": { "sample_count": 105, - "mean_crps": 2.744961, + "mean_crps": 2.923823, "legacy_mean_crps": 2.793938, "legacy_mean_mae": 2.721143, "legacy_bucket_hit_rate": 0.695238, - "selected_mean_crps": 2.747094, + "legacy_bucket_brier": 0.775463, + "selected_mean_crps": 2.700275, "selected_mean_mae": 2.721143, - "selected_bucket_hit_rate": 0.704762, - "selected_score": 3.609685, - "legacy_score": 3.675576, + "selected_bucket_hit_rate": 0.695238, + "selected_bucket_brier": 0.765459, + "selected_score": 4.003626, + "legacy_score": 4.104792, "filled_actual_from_history": 2, "settlement_history_city_count": 30 }, diff --git a/artifacts/probability_calibration/evaluation_report.json b/artifacts/probability_calibration/evaluation_report.json index 8615dd0d..9bb1db0c 100644 --- a/artifacts/probability_calibration/evaluation_report.json +++ b/artifacts/probability_calibration/evaluation_report.json @@ -8,239 +8,239 @@ "bucket_hit_rate": 0.695238 }, "emos": { - "mean_crps": 2.747094, - "mean_mae": 2.721143, - "bucket_hit_rate": 0.685714 + "mean_crps": 2.650216, + "mean_mae": 2.722829, + "bucket_hit_rate": 0.666667 }, "delta": { - "crps": -0.046843, - "mae": 0.0, - "bucket_hit_rate": -0.009524 + "crps": -0.143722, + "mae": 0.001686, + "bucket_hit_rate": -0.028571 } }, "by_city": { "ankara": { "samples": 7, "legacy_mean_crps": 2.023242, - "emos_mean_crps": 2.259428, + "emos_mean_crps": 2.015458, "legacy_mean_mae": 1.984286, - "emos_mean_mae": 1.984286, + "emos_mean_mae": 1.977721, "legacy_bucket_hit_rate": 0.714286, "emos_bucket_hit_rate": 0.714286 }, "atlanta": { "samples": 5, "legacy_mean_crps": 12.792034, - "emos_mean_crps": 12.537301, + "emos_mean_crps": 12.526108, "legacy_mean_mae": 12.806, - "emos_mean_mae": 12.806, + "emos_mean_mae": 12.919677, "legacy_bucket_hit_rate": 0.6, - "emos_bucket_hit_rate": 0.6 + "emos_bucket_hit_rate": 0.4 }, "buenos aires": { "samples": 5, "legacy_mean_crps": 3.846144, - "emos_mean_crps": 3.745234, + "emos_mean_crps": 3.743967, "legacy_mean_mae": 4.168, - "emos_mean_mae": 4.168, + "emos_mean_mae": 4.086663, "legacy_bucket_hit_rate": 0.6, "emos_bucket_hit_rate": 0.6 }, "chicago": { "samples": 4, "legacy_mean_crps": 1.346667, - "emos_mean_crps": 0.66337, + "emos_mean_crps": 0.603128, "legacy_mean_mae": 0.0, - "emos_mean_mae": 0.0, + "emos_mean_mae": 0.075265, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "dallas": { "samples": 4, "legacy_mean_crps": 1.256111, - "emos_mean_crps": 0.651563, + "emos_mean_crps": 0.65514, "legacy_mean_mae": 0.0, - "emos_mean_mae": 0.0, + "emos_mean_mae": 0.114807, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "hong kong": { "samples": 3, "legacy_mean_crps": 0.261027, - "emos_mean_crps": 0.621432, + "emos_mean_crps": 0.269856, "legacy_mean_mae": 0.1, - "emos_mean_mae": 0.1, + "emos_mean_mae": 0.174879, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 0.666667 }, "london": { "samples": 6, "legacy_mean_crps": 2.079624, - "emos_mean_crps": 1.986319, + "emos_mean_crps": 2.005311, "legacy_mean_mae": 2.451667, - "emos_mean_mae": 2.451667, + "emos_mean_mae": 2.327304, "legacy_bucket_hit_rate": 0.166667, - "emos_bucket_hit_rate": 0.166667 + "emos_bucket_hit_rate": 0.333333 }, "lucknow": { "samples": 4, "legacy_mean_crps": 1.468528, - "emos_mean_crps": 1.523689, + "emos_mean_crps": 1.443159, "legacy_mean_mae": 1.6025, - "emos_mean_mae": 1.6025, + "emos_mean_mae": 1.682697, "legacy_bucket_hit_rate": 0.5, "emos_bucket_hit_rate": 0.5 }, "madrid": { "samples": 2, "legacy_mean_crps": 6.27726, - "emos_mean_crps": 6.028088, + "emos_mean_crps": 6.090563, "legacy_mean_mae": 7.33, - "emos_mean_mae": 7.33, + "emos_mean_mae": 7.141649, "legacy_bucket_hit_rate": 0.0, "emos_bucket_hit_rate": 0.0 }, "miami": { "samples": 5, "legacy_mean_crps": 11.665378, - "emos_mean_crps": 11.614409, + "emos_mean_crps": 11.493094, "legacy_mean_mae": 12.07, - "emos_mean_mae": 12.07, + "emos_mean_mae": 12.157623, "legacy_bucket_hit_rate": 0.6, - "emos_bucket_hit_rate": 0.6 + "emos_bucket_hit_rate": 0.2 }, "milan": { "samples": 3, "legacy_mean_crps": 4.401392, - "emos_mean_crps": 3.905274, + "emos_mean_crps": 3.837715, "legacy_mean_mae": 4.06, - "emos_mean_mae": 4.06, + "emos_mean_mae": 3.942288, "legacy_bucket_hit_rate": 0.666667, "emos_bucket_hit_rate": 0.666667 }, "munich": { "samples": 6, "legacy_mean_crps": 2.988583, - "emos_mean_crps": 2.892973, + "emos_mean_crps": 2.918299, "legacy_mean_mae": 3.143333, - "emos_mean_mae": 3.143333, + "emos_mean_mae": 3.126482, "legacy_bucket_hit_rate": 0.5, "emos_bucket_hit_rate": 0.5 }, "new york": { "samples": 4, "legacy_mean_crps": 1.861101, - "emos_mean_crps": 1.420965, + "emos_mean_crps": 1.363203, "legacy_mean_mae": 1.3725, - "emos_mean_mae": 1.3725, + "emos_mean_mae": 1.369301, "legacy_bucket_hit_rate": 0.75, "emos_bucket_hit_rate": 0.75 }, "paris": { "samples": 7, "legacy_mean_crps": 2.430082, - "emos_mean_crps": 2.23397, + "emos_mean_crps": 2.365416, "legacy_mean_mae": 2.518571, - "emos_mean_mae": 2.518571, + "emos_mean_mae": 2.48437, "legacy_bucket_hit_rate": 0.571429, "emos_bucket_hit_rate": 0.571429 }, "sao paulo": { "samples": 5, "legacy_mean_crps": 2.454756, - "emos_mean_crps": 2.351014, + "emos_mean_crps": 2.410624, "legacy_mean_mae": 2.628, - "emos_mean_mae": 2.628, + "emos_mean_mae": 2.689909, "legacy_bucket_hit_rate": 0.6, "emos_bucket_hit_rate": 0.6 }, "seattle": { "samples": 4, "legacy_mean_crps": 0.531656, - "emos_mean_crps": 0.850792, + "emos_mean_crps": 0.457257, "legacy_mean_mae": 0.0, - "emos_mean_mae": 0.0, + "emos_mean_mae": 0.11262, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "seoul": { "samples": 6, "legacy_mean_crps": 0.328088, - "emos_mean_crps": 0.710725, + "emos_mean_crps": 0.332722, "legacy_mean_mae": 0.2, - "emos_mean_mae": 0.2, + "emos_mean_mae": 0.246659, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "shanghai": { "samples": 2, "legacy_mean_crps": 0.250034, - "emos_mean_crps": 0.463888, + "emos_mean_crps": 0.249952, "legacy_mean_mae": 0.15, - "emos_mean_mae": 0.15, + "emos_mean_mae": 0.204362, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "singapore": { "samples": 2, "legacy_mean_crps": 0.281993, - "emos_mean_crps": 0.484792, + "emos_mean_crps": 0.270875, "legacy_mean_mae": 0.15, - "emos_mean_mae": 0.15, + "emos_mean_mae": 0.070547, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "taipei": { "samples": 3, "legacy_mean_crps": 0.356996, - "emos_mean_crps": 0.538714, + "emos_mean_crps": 0.351432, "legacy_mean_mae": 0.1, - "emos_mean_mae": 0.1, + "emos_mean_mae": 0.084784, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 0.666667 }, "tel aviv": { "samples": 2, "legacy_mean_crps": 0.446758, - "emos_mean_crps": 0.55971, + "emos_mean_crps": 0.434936, "legacy_mean_mae": 0.3, - "emos_mean_mae": 0.3, + "emos_mean_mae": 0.196589, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 }, "tokyo": { "samples": 2, "legacy_mean_crps": 0.450128, - "emos_mean_crps": 0.565212, + "emos_mean_crps": 0.429389, "legacy_mean_mae": 0.25, - "emos_mean_mae": 0.25, + "emos_mean_mae": 0.100782, "legacy_bucket_hit_rate": 0.5, "emos_bucket_hit_rate": 1.0 }, "toronto": { "samples": 5, "legacy_mean_crps": 2.647861, - "emos_mean_crps": 2.402627, + "emos_mean_crps": 2.512236, "legacy_mean_mae": 2.532, - "emos_mean_mae": 2.532, + "emos_mean_mae": 2.535078, "legacy_bucket_hit_rate": 0.6, "emos_bucket_hit_rate": 0.6 }, "warsaw": { "samples": 3, "legacy_mean_crps": 1.618875, - "emos_mean_crps": 1.601375, + "emos_mean_crps": 1.545129, "legacy_mean_mae": 2.056667, - "emos_mean_mae": 2.056667, + "emos_mean_mae": 1.942917, "legacy_bucket_hit_rate": 0.333333, "emos_bucket_hit_rate": 0.333333 }, "wellington": { "samples": 6, "legacy_mean_crps": 0.266349, - "emos_mean_crps": 0.592134, + "emos_mean_crps": 0.264506, "legacy_mean_mae": 0.2, - "emos_mean_mae": 0.2, + "emos_mean_mae": 0.205623, "legacy_bucket_hit_rate": 1.0, "emos_bucket_hit_rate": 1.0 } diff --git a/artifacts/probability_calibration/shadow_report.json b/artifacts/probability_calibration/shadow_report.json index e9024688..9a200d12 100644 --- a/artifacts/probability_calibration/shadow_report.json +++ b/artifacts/probability_calibration/shadow_report.json @@ -1,439 +1,439 @@ { - "generated_at": "2026-03-20T12:57:49.026408Z", + "generated_at": "2026-03-20T13:03:15.168560Z", "summary": { "samples": 103, "legacy_mean_mae": 1.839223, - "shadow_mean_mae": 1.839223, + "shadow_mean_mae": 1.851931, "legacy_bucket_hit_rate": 0.669903, - "shadow_bucket_hit_rate": 0.699029, + "shadow_bucket_hit_rate": 0.679612, "legacy_bucket_brier": 0.462814, - "shadow_bucket_brier": 0.852666, - "delta_mae": 0.0, - "delta_bucket_hit_rate": 0.029126, - "delta_bucket_brier": 0.389852 + "shadow_bucket_brier": 0.756649, + "delta_mae": 0.012708, + "delta_bucket_hit_rate": 0.009709, + "delta_bucket_brier": 0.293835 }, "by_city": { "ankara": { "samples": 7, "legacy_mean_mae": 1.984286, - "shadow_mean_mae": 1.984286, + "shadow_mean_mae": 1.977721, "legacy_bucket_hit_rate": 0.714286, "shadow_bucket_hit_rate": 0.714286, "legacy_bucket_brier": 0.484311, - "shadow_bucket_brier": 0.866985, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.793303, + "delta_mae": -0.006565, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.382674 + "delta_bucket_brier": 0.308992 }, "atlanta": { "samples": 4, "legacy_mean_mae": 4.265, - "shadow_mean_mae": 4.265, + "shadow_mean_mae": 4.558028, "legacy_bucket_hit_rate": 0.75, - "shadow_bucket_hit_rate": 0.75, + "shadow_bucket_hit_rate": 0.5, "legacy_bucket_brier": 0.257274, - "shadow_bucket_brier": 0.898147, - "delta_mae": 0.0, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.640873 + "shadow_bucket_brier": 0.858699, + "delta_mae": 0.293028, + "delta_bucket_hit_rate": -0.25, + "delta_bucket_brier": 0.601425 }, "buenos aires": { "samples": 5, "legacy_mean_mae": 4.168, - "shadow_mean_mae": 4.168, + "shadow_mean_mae": 4.086663, "legacy_bucket_hit_rate": 0.6, "shadow_bucket_hit_rate": 0.6, "legacy_bucket_brier": 0.501444, - "shadow_bucket_brier": 0.902177, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.820713, + "delta_mae": -0.081337, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.400733 + "delta_bucket_brier": 0.319269 }, "chicago": { "samples": 4, "legacy_mean_mae": 0.0, - "shadow_mean_mae": 0.0, + "shadow_mean_mae": 0.075265, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.0, - "shadow_bucket_brier": 0.775841, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.746156, + "delta_mae": 0.075265, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.775841 + "delta_bucket_brier": 0.746156 }, "dallas": { "samples": 4, "legacy_mean_mae": 0.0, - "shadow_mean_mae": 0.0, + "shadow_mean_mae": 0.114807, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.0, - "shadow_bucket_brier": 0.777109, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.778678, + "delta_mae": 0.114807, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.777109 + "delta_bucket_brier": 0.778678 }, "hong kong": { "samples": 3, "legacy_mean_mae": 0.1, - "shadow_mean_mae": 0.1, + "shadow_mean_mae": 0.174879, "legacy_bucket_hit_rate": 0.333333, "shadow_bucket_hit_rate": 0.666667, "legacy_bucket_brier": 0.882203, - "shadow_bucket_brier": 0.769924, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.463809, + "delta_mae": 0.074879, "delta_bucket_hit_rate": 0.333334, - "delta_bucket_brier": -0.112279 + "delta_bucket_brier": -0.418394 }, "london": { "samples": 6, "legacy_mean_mae": 2.451667, - "shadow_mean_mae": 2.451667, + "shadow_mean_mae": 2.327304, "legacy_bucket_hit_rate": 0.166667, - "shadow_bucket_hit_rate": 0.166667, + "shadow_bucket_hit_rate": 0.333333, "legacy_bucket_brier": 0.988538, - "shadow_bucket_brier": 0.930277, - "delta_mae": 0.0, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": -0.058261 + "shadow_bucket_brier": 0.879058, + "delta_mae": -0.124363, + "delta_bucket_hit_rate": 0.166666, + "delta_bucket_brier": -0.10948 }, "lucknow": { "samples": 4, "legacy_mean_mae": 1.6025, - "shadow_mean_mae": 1.6025, + "shadow_mean_mae": 1.682697, "legacy_bucket_hit_rate": 0.5, "shadow_bucket_hit_rate": 0.5, "legacy_bucket_brier": 0.836804, - "shadow_bucket_brier": 0.874793, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.832969, + "delta_mae": 0.080197, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.037989 + "delta_bucket_brier": -0.003835 }, "madrid": { "samples": 2, "legacy_mean_mae": 7.33, - "shadow_mean_mae": 7.33, + "shadow_mean_mae": 7.141649, "legacy_bucket_hit_rate": 0.0, "shadow_bucket_hit_rate": 0.0, "legacy_bucket_brier": 1.148213, - "shadow_bucket_brier": 1.095556, - "delta_mae": 0.0, + "shadow_bucket_brier": 1.131778, + "delta_mae": -0.188351, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": -0.052657 + "delta_bucket_brier": -0.016435 }, "miami": { "samples": 4, "legacy_mean_mae": 2.76, - "shadow_mean_mae": 2.76, + "shadow_mean_mae": 3.001559, "legacy_bucket_hit_rate": 0.75, - "shadow_bucket_hit_rate": 0.75, + "shadow_bucket_hit_rate": 0.25, "legacy_bucket_brier": 0.295651, - "shadow_bucket_brier": 0.871341, - "delta_mae": 0.0, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.57569 + "shadow_bucket_brier": 0.773896, + "delta_mae": 0.241559, + "delta_bucket_hit_rate": -0.5, + "delta_bucket_brier": 0.478245 }, "milan": { "samples": 3, "legacy_mean_mae": 4.06, - "shadow_mean_mae": 4.06, + "shadow_mean_mae": 3.942288, "legacy_bucket_hit_rate": 0.666667, "shadow_bucket_hit_rate": 0.666667, "legacy_bucket_brier": 0.587548, - "shadow_bucket_brier": 0.894664, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.761128, + "delta_mae": -0.117712, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.307116 + "delta_bucket_brier": 0.17358 }, "munich": { "samples": 6, "legacy_mean_mae": 3.143333, - "shadow_mean_mae": 3.143333, + "shadow_mean_mae": 3.126482, "legacy_bucket_hit_rate": 0.5, "shadow_bucket_hit_rate": 0.5, "legacy_bucket_brier": 0.531206, - "shadow_bucket_brier": 0.889555, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.756931, + "delta_mae": -0.016851, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.358349 + "delta_bucket_brier": 0.225725 }, "new york": { "samples": 4, "legacy_mean_mae": 1.3725, - "shadow_mean_mae": 1.3725, + "shadow_mean_mae": 1.369301, "legacy_bucket_hit_rate": 0.75, "shadow_bucket_hit_rate": 0.75, "legacy_bucket_brier": 0.410198, - "shadow_bucket_brier": 0.858466, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.856962, + "delta_mae": -0.003199, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.448268 + "delta_bucket_brier": 0.446764 }, "paris": { "samples": 7, "legacy_mean_mae": 2.518571, - "shadow_mean_mae": 2.518571, + "shadow_mean_mae": 2.48437, "legacy_bucket_hit_rate": 0.571429, "shadow_bucket_hit_rate": 0.571429, "legacy_bucket_brier": 0.630706, - "shadow_bucket_brier": 0.919741, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.859044, + "delta_mae": -0.034201, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.289035 + "delta_bucket_brier": 0.228338 }, "sao paulo": { "samples": 5, "legacy_mean_mae": 2.628, - "shadow_mean_mae": 2.628, + "shadow_mean_mae": 2.689909, "legacy_bucket_hit_rate": 0.6, "shadow_bucket_hit_rate": 0.6, "legacy_bucket_brier": 0.505595, - "shadow_bucket_brier": 0.910825, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.869029, + "delta_mae": 0.061909, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.40523 + "delta_bucket_brier": 0.363434 }, "seattle": { "samples": 4, "legacy_mean_mae": 0.0, - "shadow_mean_mae": 0.0, + "shadow_mean_mae": 0.11262, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.0, - "shadow_bucket_brier": 0.818312, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.692003, + "delta_mae": 0.11262, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.818312 + "delta_bucket_brier": 0.692003 }, "seoul": { "samples": 6, "legacy_mean_mae": 0.2, - "shadow_mean_mae": 0.2, + "shadow_mean_mae": 0.246659, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.22618, - "shadow_bucket_brier": 0.793326, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.58261, + "delta_mae": 0.046659, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.567146 + "delta_bucket_brier": 0.35643 }, "shanghai": { "samples": 2, "legacy_mean_mae": 0.15, - "shadow_mean_mae": 0.15, + "shadow_mean_mae": 0.204362, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.1156, - "shadow_bucket_brier": 0.714946, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.500523, + "delta_mae": 0.054362, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.599346 + "delta_bucket_brier": 0.384923 }, "singapore": { "samples": 2, "legacy_mean_mae": 0.15, - "shadow_mean_mae": 0.15, + "shadow_mean_mae": 0.070547, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.306527, - "shadow_bucket_brier": 0.723037, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.546477, + "delta_mae": -0.079453, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.41651 + "delta_bucket_brier": 0.23995 }, "taipei": { "samples": 3, "legacy_mean_mae": 0.1, - "shadow_mean_mae": 0.1, + "shadow_mean_mae": 0.084784, "legacy_bucket_hit_rate": 0.333333, "shadow_bucket_hit_rate": 0.666667, "legacy_bucket_brier": 0.884594, - "shadow_bucket_brier": 0.749607, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.633789, + "delta_mae": -0.015216, "delta_bucket_hit_rate": 0.333334, - "delta_bucket_brier": -0.134987 + "delta_bucket_brier": -0.250805 }, "tel aviv": { "samples": 2, "legacy_mean_mae": 0.3, - "shadow_mean_mae": 0.3, + "shadow_mean_mae": 0.196589, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.257895, - "shadow_bucket_brier": 0.753429, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.693539, + "delta_mae": -0.103411, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.495534 + "delta_bucket_brier": 0.435644 }, "tokyo": { "samples": 2, "legacy_mean_mae": 0.25, - "shadow_mean_mae": 0.25, + "shadow_mean_mae": 0.100782, "legacy_bucket_hit_rate": 0.5, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.284759, - "shadow_bucket_brier": 0.753103, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.691981, + "delta_mae": -0.149218, "delta_bucket_hit_rate": 0.5, - "delta_bucket_brier": 0.468344 + "delta_bucket_brier": 0.407222 }, "toronto": { "samples": 5, "legacy_mean_mae": 2.532, - "shadow_mean_mae": 2.532, + "shadow_mean_mae": 2.535078, "legacy_bucket_hit_rate": 0.6, "shadow_bucket_hit_rate": 0.6, "legacy_bucket_brier": 0.502694, - "shadow_bucket_brier": 0.921825, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.947846, + "delta_mae": 0.003078, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.419131 + "delta_bucket_brier": 0.445152 }, "warsaw": { "samples": 3, "legacy_mean_mae": 2.056667, - "shadow_mean_mae": 2.056667, + "shadow_mean_mae": 1.942917, "legacy_bucket_hit_rate": 0.333333, "shadow_bucket_hit_rate": 0.333333, "legacy_bucket_brier": 0.86425, - "shadow_bucket_brier": 0.859525, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.734939, + "delta_mae": -0.11375, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": -0.004725 + "delta_bucket_brier": -0.129311 }, "wellington": { "samples": 6, "legacy_mean_mae": 0.2, - "shadow_mean_mae": 0.2, + "shadow_mean_mae": 0.205623, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.126496, - "shadow_bucket_brier": 0.761186, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.466977, + "delta_mae": 0.005623, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.63469 + "delta_bucket_brier": 0.340481 } }, "by_date": { "2026-03-07": { "samples": 13, "legacy_mean_mae": 0.096154, - "shadow_mean_mae": 0.096154, + "shadow_mean_mae": 0.204611, "legacy_bucket_hit_rate": 0.923077, - "shadow_bucket_hit_rate": 0.923077, + "shadow_bucket_hit_rate": 0.846154, "legacy_bucket_brier": 0.131914, - "shadow_bucket_brier": 0.806489, - "delta_mae": 0.0, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.674575 + "shadow_bucket_brier": 0.656071, + "delta_mae": 0.108457, + "delta_bucket_hit_rate": -0.076923, + "delta_bucket_brier": 0.524157 }, "2026-03-08": { "samples": 16, "legacy_mean_mae": 0.189375, - "shadow_mean_mae": 0.189375, + "shadow_mean_mae": 0.318263, "legacy_bucket_hit_rate": 0.9375, "shadow_bucket_hit_rate": 0.9375, "legacy_bucket_brier": 0.093386, - "shadow_bucket_brier": 0.821968, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.686836, + "delta_mae": 0.128888, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.728582 + "delta_bucket_brier": 0.59345 }, "2026-03-09": { "samples": 16, "legacy_mean_mae": 0.026875, - "shadow_mean_mae": 0.026875, + "shadow_mean_mae": 0.167204, "legacy_bucket_hit_rate": 1.0, - "shadow_bucket_hit_rate": 1.0, + "shadow_bucket_hit_rate": 0.875, "legacy_bucket_brier": 0.034156, - "shadow_bucket_brier": 0.806424, - "delta_mae": 0.0, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.772268 + "shadow_bucket_brier": 0.620235, + "delta_mae": 0.140329, + "delta_bucket_hit_rate": -0.125, + "delta_bucket_brier": 0.586079 }, "2026-03-10": { "samples": 6, "legacy_mean_mae": 3.346667, - "shadow_mean_mae": 3.346667, + "shadow_mean_mae": 3.295706, "legacy_bucket_hit_rate": 0.333333, "shadow_bucket_hit_rate": 0.333333, "legacy_bucket_brier": 1.004838, - "shadow_bucket_brier": 0.925151, - "delta_mae": 0.0, + "shadow_bucket_brier": 1.025975, + "delta_mae": -0.050961, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": -0.079687 + "delta_bucket_brier": 0.021137 }, "2026-03-11": { "samples": 1, "legacy_mean_mae": 12.27, - "shadow_mean_mae": 12.27, + "shadow_mean_mae": 12.106368, "legacy_bucket_hit_rate": 0.0, "shadow_bucket_hit_rate": 0.0, "legacy_bucket_brier": 1.101949, - "shadow_bucket_brier": 1.034069, - "delta_mae": 0.0, + "shadow_bucket_brier": 1.143139, + "delta_mae": -0.163632, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": -0.06788 + "delta_bucket_brier": 0.04119 }, "2026-03-12": { "samples": 2, "legacy_mean_mae": 3.05, - "shadow_mean_mae": 3.05, + "shadow_mean_mae": 3.027162, "legacy_bucket_hit_rate": 0.5, "shadow_bucket_hit_rate": 0.5, "legacy_bucket_brier": 0.674081, - "shadow_bucket_brier": 0.909299, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.94215, + "delta_mae": -0.022838, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.235218 + "delta_bucket_brier": 0.268069 }, "2026-03-13": { "samples": 1, "legacy_mean_mae": 0.3, - "shadow_mean_mae": 0.3, + "shadow_mean_mae": 0.329081, "legacy_bucket_hit_rate": 1.0, "shadow_bucket_hit_rate": 1.0, "legacy_bucket_brier": 0.407401, - "shadow_bucket_brier": 0.809944, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.704589, + "delta_mae": 0.029081, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.402543 + "delta_bucket_brier": 0.297188 }, "2026-03-17": { "samples": 4, "legacy_mean_mae": 0.15, - "shadow_mean_mae": 0.15, + "shadow_mean_mae": 0.176549, "legacy_bucket_hit_rate": 0.75, "shadow_bucket_hit_rate": 0.75, "legacy_bucket_brier": 0.601543, - "shadow_bucket_brier": 0.790146, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.654372, + "delta_mae": 0.026549, "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.188603 + "delta_bucket_brier": 0.052829 }, "2026-03-18": { "samples": 25, "legacy_mean_mae": 2.5476, - "shadow_mean_mae": 2.5476, + "shadow_mean_mae": 2.476214, "legacy_bucket_hit_rate": 0.52, - "shadow_bucket_hit_rate": 0.52, + "shadow_bucket_hit_rate": 0.56, "legacy_bucket_brier": 0.657516, - "shadow_bucket_brier": 0.856047, - "delta_mae": 0.0, - "delta_bucket_hit_rate": 0.0, - "delta_bucket_brier": 0.198531 + "shadow_bucket_brier": 0.735089, + "delta_mae": -0.071386, + "delta_bucket_hit_rate": 0.04, + "delta_bucket_brier": 0.077573 }, "2026-03-19": { "samples": 19, "legacy_mean_mae": 4.299474, - "shadow_mean_mae": 4.299474, + "shadow_mean_mae": 4.181363, "legacy_bucket_hit_rate": 0.315789, "shadow_bucket_hit_rate": 0.473684, "legacy_bucket_brier": 0.85177, - "shadow_bucket_brier": 0.921616, - "delta_mae": 0.0, + "shadow_bucket_brier": 0.926854, + "delta_mae": -0.118111, "delta_bucket_hit_rate": 0.157895, - "delta_bucket_brier": 0.069846 + "delta_bucket_brier": 0.075084 } }, "recent_observations": [ @@ -443,10 +443,10 @@ "actual_high": 18.0, "actual_bucket": 18, "legacy_mu": 18.3, - "shadow_mu": 18.3, + "shadow_mu": 18.273, "legacy_top_bucket": 18, "shadow_top_bucket": 18, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -455,10 +455,10 @@ "actual_high": 7.0, "actual_bucket": 7, "legacy_mu": 12.03, - "shadow_mu": 12.03, + "shadow_mu": 11.887, "legacy_top_bucket": 12, "shadow_top_bucket": 12, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -467,10 +467,10 @@ "actual_high": -2.0, "actual_bucket": -2, "legacy_mu": 5.67, - "shadow_mu": 5.67, + "shadow_mu": 5.487, "legacy_top_bucket": 6, - "shadow_top_bucket": 6, - "calibration_version": "emos-20260320123829", + "shadow_top_bucket": 5, + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -479,10 +479,10 @@ "actual_high": 16.0, "actual_bucket": 16, "legacy_mu": 16.5, - "shadow_mu": 16.5, + "shadow_mu": 16.171, "legacy_top_bucket": 17, "shadow_top_bucket": 16, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -491,10 +491,10 @@ "actual_high": 21.0, "actual_bucket": 21, "legacy_mu": 21.3, - "shadow_mu": 21.3, + "shadow_mu": 21.158, "legacy_top_bucket": 21, "shadow_top_bucket": 21, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -503,10 +503,10 @@ "actual_high": 21.4, "actual_bucket": 21, "legacy_mu": 21.7, - "shadow_mu": 21.7, + "shadow_mu": 21.601, "legacy_top_bucket": 22, "shadow_top_bucket": 21, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -515,10 +515,10 @@ "actual_high": 32.0, "actual_bucket": 32, "legacy_mu": 32.3, - "shadow_mu": 32.3, + "shadow_mu": 32.116, "legacy_top_bucket": 32, "shadow_top_bucket": 32, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -527,10 +527,10 @@ "actual_high": 12.0, "actual_bucket": 12, "legacy_mu": 12.3, - "shadow_mu": 12.3, + "shadow_mu": 12.279, "legacy_top_bucket": 12, "shadow_top_bucket": 12, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -539,10 +539,10 @@ "actual_high": 10.0, "actual_bucket": 10, "legacy_mu": 10.3, - "shadow_mu": 10.3, + "shadow_mu": 10.498, "legacy_top_bucket": 10, "shadow_top_bucket": 10, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -551,10 +551,10 @@ "actual_high": 21.0, "actual_bucket": 21, "legacy_mu": 26.5, - "shadow_mu": 26.5, + "shadow_mu": 26.372, "legacy_top_bucket": 26, "shadow_top_bucket": 26, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -563,10 +563,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 16.06, - "shadow_mu": 16.06, + "shadow_mu": 15.91, "legacy_top_bucket": 16, "shadow_top_bucket": 16, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -575,10 +575,10 @@ "actual_high": 5.0, "actual_bucket": 5, "legacy_mu": 11.62, - "shadow_mu": 11.62, + "shadow_mu": 11.451, "legacy_top_bucket": 12, - "shadow_top_bucket": 12, - "calibration_version": "emos-20260320123829", + "shadow_top_bucket": 11, + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -587,10 +587,10 @@ "actual_high": 5.0, "actual_bucket": 5, "legacy_mu": 16.58, - "shadow_mu": 16.58, + "shadow_mu": 16.346, "legacy_top_bucket": 17, - "shadow_top_bucket": 17, - "calibration_version": "emos-20260320123829", + "shadow_top_bucket": 16, + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -599,10 +599,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 18.23, - "shadow_mu": 18.23, + "shadow_mu": 18.028, "legacy_top_bucket": 18, "shadow_top_bucket": 18, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -611,10 +611,10 @@ "actual_high": 30.0, "actual_bucket": 30, "legacy_mu": 35.3, - "shadow_mu": 35.3, + "shadow_mu": 35.222, "legacy_top_bucket": 35, "shadow_top_bucket": 35, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -623,10 +623,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 15.71, - "shadow_mu": 15.71, + "shadow_mu": 15.58, "legacy_top_bucket": 16, "shadow_top_bucket": 16, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -635,10 +635,10 @@ "actual_high": 27.3, "actual_bucket": 27, "legacy_mu": 27.6, - "shadow_mu": 27.6, + "shadow_mu": 27.65, "legacy_top_bucket": 28, "shadow_top_bucket": 27, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -647,10 +647,10 @@ "actual_high": 16.0, "actual_bucket": 16, "legacy_mu": 27.39, - "shadow_mu": 27.39, + "shadow_mu": 27.105, "legacy_top_bucket": 27, "shadow_top_bucket": 27, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -659,10 +659,10 @@ "actual_high": 11.0, "actual_bucket": 11, "legacy_mu": 11.0, - "shadow_mu": 11.0, + "shadow_mu": 10.989, "legacy_top_bucket": 11, "shadow_top_bucket": 11, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -671,10 +671,10 @@ "actual_high": 21.0, "actual_bucket": 21, "legacy_mu": 21.0, - "shadow_mu": 21.0, + "shadow_mu": 21.031, "legacy_top_bucket": 21, "shadow_top_bucket": 21, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -683,10 +683,10 @@ "actual_high": 13.0, "actual_bucket": 13, "legacy_mu": 13.84, - "shadow_mu": 13.84, + "shadow_mu": 13.682, "legacy_top_bucket": 14, "shadow_top_bucket": 14, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -695,10 +695,10 @@ "actual_high": -6.0, "actual_bucket": -6, "legacy_mu": -1.01, - "shadow_mu": -1.01, + "shadow_mu": -1.101, "legacy_top_bucket": -1, "shadow_top_bucket": -1, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -707,10 +707,10 @@ "actual_high": 17.0, "actual_bucket": 17, "legacy_mu": 17.0, - "shadow_mu": 17.0, + "shadow_mu": 16.969, "legacy_top_bucket": 17, "shadow_top_bucket": 17, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -719,10 +719,10 @@ "actual_high": 30.0, "actual_bucket": 30, "legacy_mu": 30.3, - "shadow_mu": 30.3, + "shadow_mu": 30.235, "legacy_top_bucket": 30, "shadow_top_bucket": 30, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -731,10 +731,10 @@ "actual_high": 29.0, "actual_bucket": 29, "legacy_mu": 29.0, - "shadow_mu": 29.0, + "shadow_mu": 28.978, "legacy_top_bucket": 29, "shadow_top_bucket": 28, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -743,10 +743,10 @@ "actual_high": 32.0, "actual_bucket": 32, "legacy_mu": 32.0, - "shadow_mu": 32.0, + "shadow_mu": 31.975, "legacy_top_bucket": 32, "shadow_top_bucket": 32, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -755,10 +755,10 @@ "actual_high": 13.0, "actual_bucket": 13, "legacy_mu": 13.0, - "shadow_mu": 13.0, + "shadow_mu": 12.87, "legacy_top_bucket": 13, "shadow_top_bucket": 13, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -767,10 +767,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 8.0, - "shadow_mu": 8.0, + "shadow_mu": 7.891, "legacy_top_bucket": 8, "shadow_top_bucket": 8, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -779,10 +779,10 @@ "actual_high": 55.9, "actual_bucket": 56, "legacy_mu": 55.9, - "shadow_mu": 55.9, + "shadow_mu": 55.705, "legacy_top_bucket": 56, "shadow_top_bucket": 56, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -791,10 +791,10 @@ "actual_high": 22.0, "actual_bucket": 22, "legacy_mu": 29.64, - "shadow_mu": 29.64, + "shadow_mu": 29.517, "legacy_top_bucket": 30, "shadow_top_bucket": 30, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -803,10 +803,10 @@ "actual_high": 14.0, "actual_bucket": 14, "legacy_mu": 14.47, - "shadow_mu": 14.47, + "shadow_mu": 14.319, "legacy_top_bucket": 14, "shadow_top_bucket": 14, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -815,10 +815,10 @@ "actual_high": 32.0, "actual_bucket": 32, "legacy_mu": 36.94, - "shadow_mu": 36.94, + "shadow_mu": 36.759, "legacy_top_bucket": 37, "shadow_top_bucket": 37, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -827,10 +827,10 @@ "actual_high": 10.0, "actual_bucket": 10, "legacy_mu": 10.66, - "shadow_mu": 10.66, + "shadow_mu": 10.516, "legacy_top_bucket": 11, "shadow_top_bucket": 11, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -839,10 +839,10 @@ "actual_high": 14.0, "actual_bucket": 14, "legacy_mu": 14.3, - "shadow_mu": 14.3, + "shadow_mu": 14.162, "legacy_top_bucket": 14, "shadow_top_bucket": 14, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -851,10 +851,10 @@ "actual_high": 59.0, "actual_bucket": 59, "legacy_mu": 70.04, - "shadow_mu": 70.04, + "shadow_mu": 69.507, "legacy_top_bucket": 70, "shadow_top_bucket": 70, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -863,10 +863,10 @@ "actual_high": 14.0, "actual_bucket": 14, "legacy_mu": 18.43, - "shadow_mu": 18.43, + "shadow_mu": 18.255, "legacy_top_bucket": 18, "shadow_top_bucket": 18, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -875,10 +875,10 @@ "actual_high": 34.0, "actual_bucket": 34, "legacy_mu": 35.11, - "shadow_mu": 35.11, + "shadow_mu": 35.025, "legacy_top_bucket": 35, "shadow_top_bucket": 35, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -887,10 +887,10 @@ "actual_high": 16.0, "actual_bucket": 16, "legacy_mu": 16.56, - "shadow_mu": 16.56, + "shadow_mu": 16.414, "legacy_top_bucket": 17, - "shadow_top_bucket": 17, - "calibration_version": "emos-20260320123829", + "shadow_top_bucket": 16, + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -899,10 +899,10 @@ "actual_high": 27.8, "actual_bucket": 27, "legacy_mu": 27.8, - "shadow_mu": 27.8, + "shadow_mu": 27.878, "legacy_top_bucket": 28, "shadow_top_bucket": 27, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -911,10 +911,10 @@ "actual_high": 73.9, "actual_bucket": 74, "legacy_mu": 73.9, - "shadow_mu": 73.9, + "shadow_mu": 73.578, "legacy_top_bucket": 74, "shadow_top_bucket": 74, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -923,10 +923,10 @@ "actual_high": 46.0, "actual_bucket": 46, "legacy_mu": 46.0, - "shadow_mu": 46.0, + "shadow_mu": 45.992, "legacy_top_bucket": 46, "shadow_top_bucket": 46, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -935,10 +935,10 @@ "actual_high": 17.0, "actual_bucket": 17, "legacy_mu": 26.15, - "shadow_mu": 26.15, + "shadow_mu": 25.927, "legacy_top_bucket": 26, "shadow_top_bucket": 26, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -947,10 +947,10 @@ "actual_high": 37.0, "actual_bucket": 37, "legacy_mu": 54.06, - "shadow_mu": 54.06, + "shadow_mu": 53.706, "legacy_top_bucket": 54, "shadow_top_bucket": 54, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -959,10 +959,10 @@ "actual_high": 15.0, "actual_bucket": 15, "legacy_mu": 15.2, - "shadow_mu": 15.2, + "shadow_mu": 15.032, "legacy_top_bucket": 15, "shadow_top_bucket": 15, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -971,10 +971,10 @@ "actual_high": 11.0, "actual_bucket": 11, "legacy_mu": 11.3, - "shadow_mu": 11.3, + "shadow_mu": 11.259, "legacy_top_bucket": 11, "shadow_top_bucket": 11, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -983,10 +983,10 @@ "actual_high": 26.7, "actual_bucket": 26, "legacy_mu": 26.7, - "shadow_mu": 26.7, + "shadow_mu": 26.669, "legacy_top_bucket": 27, "shadow_top_bucket": 26, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -995,10 +995,10 @@ "actual_high": 17.0, "actual_bucket": 17, "legacy_mu": 17.3, - "shadow_mu": 17.3, + "shadow_mu": 17.319, "legacy_top_bucket": 17, "shadow_top_bucket": 17, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1007,10 +1007,10 @@ "actual_high": 24.0, "actual_bucket": 24, "legacy_mu": 24.0, - "shadow_mu": 24.0, + "shadow_mu": 23.903, "legacy_top_bucket": 24, "shadow_top_bucket": 23, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1019,10 +1019,10 @@ "actual_high": 11.0, "actual_bucket": 11, "legacy_mu": 11.3, - "shadow_mu": 11.3, + "shadow_mu": 11.329, "legacy_top_bucket": 11, "shadow_top_bucket": 11, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1031,10 +1031,10 @@ "actual_high": 21.0, "actual_bucket": 21, "legacy_mu": 21.3, - "shadow_mu": 21.3, + "shadow_mu": 21.396, "legacy_top_bucket": 21, "shadow_top_bucket": 21, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1043,10 +1043,10 @@ "actual_high": 7.0, "actual_bucket": 7, "legacy_mu": 12.8, - "shadow_mu": 12.8, + "shadow_mu": 12.658, "legacy_top_bucket": 13, "shadow_top_bucket": 13, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1055,10 +1055,10 @@ "actual_high": 1.0, "actual_bucket": 1, "legacy_mu": 13.27, - "shadow_mu": 13.27, + "shadow_mu": 13.106, "legacy_top_bucket": 13, "shadow_top_bucket": 13, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1067,10 +1067,10 @@ "actual_high": 16.0, "actual_bucket": 16, "legacy_mu": 16.3, - "shadow_mu": 16.3, + "shadow_mu": 16.228, "legacy_top_bucket": 16, "shadow_top_bucket": 16, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1079,10 +1079,10 @@ "actual_high": 7.0, "actual_bucket": 7, "legacy_mu": 7.3, - "shadow_mu": 7.3, + "shadow_mu": 7.362, "legacy_top_bucket": 7, "shadow_top_bucket": 7, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1091,10 +1091,10 @@ "actual_high": 12.0, "actual_bucket": 12, "legacy_mu": 15.3, - "shadow_mu": 15.3, + "shadow_mu": 15.175, "legacy_top_bucket": 15, "shadow_top_bucket": 15, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1103,10 +1103,10 @@ "actual_high": 4.0, "actual_bucket": 4, "legacy_mu": 15.58, - "shadow_mu": 15.58, + "shadow_mu": 15.4, "legacy_top_bucket": 16, - "shadow_top_bucket": 16, - "calibration_version": "emos-20260320123829", + "shadow_top_bucket": 15, + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1115,10 +1115,10 @@ "actual_high": 10.0, "actual_bucket": 10, "legacy_mu": 13.18, - "shadow_mu": 13.18, + "shadow_mu": 13.058, "legacy_top_bucket": 13, "shadow_top_bucket": 13, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1127,10 +1127,10 @@ "actual_high": 11.0, "actual_bucket": 11, "legacy_mu": 9.58, - "shadow_mu": 9.58, + "shadow_mu": 9.45, "legacy_top_bucket": 10, - "shadow_top_bucket": 10, - "calibration_version": "emos-20260320123829", + "shadow_top_bucket": 9, + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1139,10 +1139,10 @@ "actual_high": 18.0, "actual_bucket": 18, "legacy_mu": 18.0, - "shadow_mu": 18.0, + "shadow_mu": 17.94, "legacy_top_bucket": 18, "shadow_top_bucket": 18, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1151,10 +1151,10 @@ "actual_high": 19.0, "actual_bucket": 19, "legacy_mu": 19.0, - "shadow_mu": 19.0, + "shadow_mu": 18.951, "legacy_top_bucket": 19, "shadow_top_bucket": 19, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1163,10 +1163,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 8.0, - "shadow_mu": 8.0, + "shadow_mu": 7.995, "legacy_top_bucket": 8, "shadow_top_bucket": 8, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1175,10 +1175,10 @@ "actual_high": 45.0, "actual_bucket": 45, "legacy_mu": 45.0, - "shadow_mu": 45.0, + "shadow_mu": 44.84, "legacy_top_bucket": 45, "shadow_top_bucket": 45, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1187,10 +1187,10 @@ "actual_high": 22.0, "actual_bucket": 22, "legacy_mu": 22.0, - "shadow_mu": 22.0, + "shadow_mu": 21.746, "legacy_top_bucket": 22, "shadow_top_bucket": 22, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1199,10 +1199,10 @@ "actual_high": 18.0, "actual_bucket": 18, "legacy_mu": 18.0, - "shadow_mu": 18.0, + "shadow_mu": 17.922, "legacy_top_bucket": 18, "shadow_top_bucket": 18, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1211,10 +1211,10 @@ "actual_high": 71.1, "actual_bucket": 71, "legacy_mu": 71.1, - "shadow_mu": 71.1, + "shadow_mu": 71.203, "legacy_top_bucket": 71, "shadow_top_bucket": 71, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1223,10 +1223,10 @@ "actual_high": 15.0, "actual_bucket": 15, "legacy_mu": 15.0, - "shadow_mu": 15.0, + "shadow_mu": 14.882, "legacy_top_bucket": 15, "shadow_top_bucket": 15, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1235,10 +1235,10 @@ "actual_high": 84.0, "actual_bucket": 84, "legacy_mu": 84.0, - "shadow_mu": 84.0, + "shadow_mu": 83.451, "legacy_top_bucket": 84, - "shadow_top_bucket": 84, - "calibration_version": "emos-20260320123829", + "shadow_top_bucket": 83, + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1247,10 +1247,10 @@ "actual_high": 34.0, "actual_bucket": 34, "legacy_mu": 34.0, - "shadow_mu": 34.0, + "shadow_mu": 33.816, "legacy_top_bucket": 34, "shadow_top_bucket": 34, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1259,10 +1259,10 @@ "actual_high": 15.0, "actual_bucket": 15, "legacy_mu": 15.13, - "shadow_mu": 15.13, + "shadow_mu": 14.987, "legacy_top_bucket": 15, "shadow_top_bucket": 15, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1271,10 +1271,10 @@ "actual_high": 84.0, "actual_bucket": 84, "legacy_mu": 84.0, - "shadow_mu": 84.0, + "shadow_mu": 83.964, "legacy_top_bucket": 84, "shadow_top_bucket": 84, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1283,10 +1283,10 @@ "actual_high": 72.0, "actual_bucket": 72, "legacy_mu": 72.0, - "shadow_mu": 72.0, + "shadow_mu": 71.829, "legacy_top_bucket": 72, "shadow_top_bucket": 72, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1295,10 +1295,10 @@ "actual_high": 27.0, "actual_bucket": 27, "legacy_mu": 27.3, - "shadow_mu": 27.3, + "shadow_mu": 27.165, "legacy_top_bucket": 27, "shadow_top_bucket": 27, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1307,10 +1307,10 @@ "actual_high": 77.0, "actual_bucket": 77, "legacy_mu": 77.0, - "shadow_mu": 77.0, + "shadow_mu": 76.347, "legacy_top_bucket": 77, - "shadow_top_bucket": 77, - "calibration_version": "emos-20260320123829", + "shadow_top_bucket": 76, + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1319,10 +1319,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 8.0, - "shadow_mu": 8.0, + "shadow_mu": 7.924, "legacy_top_bucket": 8, "shadow_top_bucket": 8, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1331,10 +1331,10 @@ "actual_high": 19.0, "actual_bucket": 19, "legacy_mu": 19.3, - "shadow_mu": 19.3, + "shadow_mu": 19.244, "legacy_top_bucket": 19, "shadow_top_bucket": 19, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1343,10 +1343,10 @@ "actual_high": 13.0, "actual_bucket": 13, "legacy_mu": 13.0, - "shadow_mu": 13.0, + "shadow_mu": 12.912, "legacy_top_bucket": 13, "shadow_top_bucket": 13, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1355,10 +1355,10 @@ "actual_high": 4.0, "actual_bucket": 4, "legacy_mu": 4.3, - "shadow_mu": 4.3, + "shadow_mu": 4.177, "legacy_top_bucket": 4, "shadow_top_bucket": 4, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1367,10 +1367,10 @@ "actual_high": 53.1, "actual_bucket": 53, "legacy_mu": 53.1, - "shadow_mu": 53.1, + "shadow_mu": 53.122, "legacy_top_bucket": 53, "shadow_top_bucket": 53, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1379,10 +1379,10 @@ "actual_high": 28.0, "actual_bucket": 28, "legacy_mu": 28.0, - "shadow_mu": 28.0, + "shadow_mu": 27.864, "legacy_top_bucket": 28, "shadow_top_bucket": 28, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1391,10 +1391,10 @@ "actual_high": 16.0, "actual_bucket": 16, "legacy_mu": 16.0, - "shadow_mu": 16.0, + "shadow_mu": 15.854, "legacy_top_bucket": 16, "shadow_top_bucket": 16, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1403,10 +1403,10 @@ "actual_high": 68.0, "actual_bucket": 68, "legacy_mu": 68.0, - "shadow_mu": 68.0, + "shadow_mu": 67.777, "legacy_top_bucket": 68, "shadow_top_bucket": 68, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1415,10 +1415,10 @@ "actual_high": 14.0, "actual_bucket": 14, "legacy_mu": 14.0, - "shadow_mu": 14.0, + "shadow_mu": 13.81, "legacy_top_bucket": 14, "shadow_top_bucket": 14, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1427,10 +1427,10 @@ "actual_high": 84.0, "actual_bucket": 84, "legacy_mu": 84.0, - "shadow_mu": 84.0, + "shadow_mu": 83.563, "legacy_top_bucket": 84, "shadow_top_bucket": 84, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1439,10 +1439,10 @@ "actual_high": 32.0, "actual_bucket": 32, "legacy_mu": 32.0, - "shadow_mu": 32.0, + "shadow_mu": 31.701, "legacy_top_bucket": 32, "shadow_top_bucket": 32, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1451,10 +1451,10 @@ "actual_high": 9.0, "actual_bucket": 9, "legacy_mu": 11.43, - "shadow_mu": 11.43, + "shadow_mu": 11.335, "legacy_top_bucket": 11, "shadow_top_bucket": 11, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1463,10 +1463,10 @@ "actual_high": 75.0, "actual_bucket": 75, "legacy_mu": 75.0, - "shadow_mu": 75.0, + "shadow_mu": 75.041, "legacy_top_bucket": 75, "shadow_top_bucket": 75, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1475,10 +1475,10 @@ "actual_high": 62.1, "actual_bucket": 62, "legacy_mu": 62.1, - "shadow_mu": 62.1, + "shadow_mu": 62.035, "legacy_top_bucket": 62, "shadow_top_bucket": 62, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1487,10 +1487,10 @@ "actual_high": 27.0, "actual_bucket": 27, "legacy_mu": 27.0, - "shadow_mu": 27.0, + "shadow_mu": 26.817, "legacy_top_bucket": 27, "shadow_top_bucket": 27, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1499,10 +1499,10 @@ "actual_high": 69.1, "actual_bucket": 69, "legacy_mu": 69.1, - "shadow_mu": 69.1, + "shadow_mu": 68.643, "legacy_top_bucket": 69, "shadow_top_bucket": 69, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1511,10 +1511,10 @@ "actual_high": 8.0, "actual_bucket": 8, "legacy_mu": 8.0, - "shadow_mu": 8.0, + "shadow_mu": 7.952, "legacy_top_bucket": 8, "shadow_top_bucket": 8, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1523,10 +1523,10 @@ "actual_high": 17.0, "actual_bucket": 17, "legacy_mu": 17.0, - "shadow_mu": 17.0, + "shadow_mu": 16.847, "legacy_top_bucket": 17, "shadow_top_bucket": 17, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1535,10 +1535,10 @@ "actual_high": 54.0, "actual_bucket": 54, "legacy_mu": 54.0, - "shadow_mu": 54.0, + "shadow_mu": 53.926, "legacy_top_bucket": 54, "shadow_top_bucket": 54, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1547,10 +1547,10 @@ "actual_high": 27.0, "actual_bucket": 27, "legacy_mu": 27.0, - "shadow_mu": 27.0, + "shadow_mu": 26.831, "legacy_top_bucket": 27, "shadow_top_bucket": 27, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1559,10 +1559,10 @@ "actual_high": 17.0, "actual_bucket": 17, "legacy_mu": 17.0, - "shadow_mu": 17.0, + "shadow_mu": 16.896, "legacy_top_bucket": 17, "shadow_top_bucket": 17, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1571,10 +1571,10 @@ "actual_high": 46.9, "actual_bucket": 47, "legacy_mu": 47.45, - "shadow_mu": 47.45, + "shadow_mu": 47.292, "legacy_top_bucket": 47, "shadow_top_bucket": 47, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1583,10 +1583,10 @@ "actual_high": 16.0, "actual_bucket": 16, "legacy_mu": 16.0, - "shadow_mu": 16.0, + "shadow_mu": 15.916, "legacy_top_bucket": 16, "shadow_top_bucket": 16, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1595,10 +1595,10 @@ "actual_high": 82.0, "actual_bucket": 82, "legacy_mu": 82.0, - "shadow_mu": 82.0, + "shadow_mu": 81.486, "legacy_top_bucket": 82, - "shadow_top_bucket": 82, - "calibration_version": "emos-20260320123829", + "shadow_top_bucket": 81, + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1607,10 +1607,10 @@ "actual_high": 9.0, "actual_bucket": 9, "legacy_mu": 9.7, - "shadow_mu": 9.7, + "shadow_mu": 9.565, "legacy_top_bucket": 10, "shadow_top_bucket": 10, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1619,10 +1619,10 @@ "actual_high": 75.0, "actual_bucket": 75, "legacy_mu": 75.0, - "shadow_mu": 75.0, + "shadow_mu": 74.939, "legacy_top_bucket": 75, "shadow_top_bucket": 75, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" }, { @@ -1631,10 +1631,10 @@ "actual_high": 64.9, "actual_bucket": 65, "legacy_mu": 64.9, - "shadow_mu": 64.9, + "shadow_mu": 64.843, "legacy_top_bucket": 65, "shadow_top_bucket": 65, - "calibration_version": "emos-20260320123829", + "calibration_version": "emos-20260320130109", "calibration_mode": "emos_shadow" } ] diff --git a/docs/EMOS_TRAINING_REPORT_ZH.md b/docs/EMOS_TRAINING_REPORT_ZH.md new file mode 100644 index 00000000..0a4a459c --- /dev/null +++ b/docs/EMOS_TRAINING_REPORT_ZH.md @@ -0,0 +1,311 @@ +# EMOS 训练报告(2026-03-20) + +## 1. 报告目的 + +本文档用于记录当前 PolyWeather 概率校准引擎(EMOS)的训练结果、离线评估结果、线上 shadow 观测结果,以及是否具备切换为主路径的条件。 + +当前结论先写在前面: + +- `EMOS` 已完成接入、训练、离线评估、shadow 落盘与滚动报表。 +- 当前默认运行模式应继续保持 `emos_shadow`。 +- 现阶段 **不建议切换到 `emos_primary`**。 + +## 2. 本次训练版本 + +- 校准版本:`emos-20260320130245` +- 训练时间:`2026-03-20T13:02:45.903772+00:00` +- 参数文件:[default.json](/E:/web/PolyWeather/artifacts/probability_calibration/default.json) +- 离线评估报告:[evaluation_report.json](/E:/web/PolyWeather/artifacts/probability_calibration/evaluation_report.json) +- 线上 shadow 报表:[shadow_report.json](/E:/web/PolyWeather/artifacts/probability_calibration/shadow_report.json) + +## 3. 训练数据概况 + +### 3.1 数据来源 + +当前训练主要使用两类数据: + +1. 项目历史日记录 + 文件:[daily_records.json](/E:/web/PolyWeather/data/daily_records.json) + +2. 历史天气 CSV 构建出的结算标签 + 文件:[settlement_history.json](/E:/web/PolyWeather/artifacts/probability_calibration/settlement_history.json) + +### 3.2 样本规模 + +- 总训练样本数:`105` +- 通过历史天气 CSV 补回的缺失 `actual_high`:`2` +- 历史结算标签覆盖城市数:`30` + +说明: + +- 当前样本已覆盖 30 个城市,但有效监督样本量仍偏小。 +- 部分城市样本数只有 `2-7` 条,城市级参数容易波动。 + +## 4. 模型结构 + +### 4.1 当前实现 + +EMOS 属于统计后处理层,不是数值天气模型本身。当前结构位于: + +- [probability_calibration.py](/E:/web/PolyWeather/src/analysis/probability_calibration.py) + +当前目标是对原有概率引擎输出进行校准: + +- 输入:`raw_mu`、`raw_sigma`、`DEB`、`ensemble median/spread`、`peak_status` 等特征 +- 输出:校准后的 `mu / sigma / distribution` + +### 4.2 当前运行模式 + +支持三种模式: + +- `legacy` +- `emos_shadow` +- `emos_primary` + +当前建议默认模式: + +- `emos_shadow` + +即: + +- 对外仍展示 legacy 结果 +- 后台并行计算 EMOS 结果 +- 用于持续评估,不直接影响用户 + +## 5. 本次训练参数摘要 + +### 5.1 全局约束 + +本次训练已加入两类约束: + +1. `sigma_constraints` +- `min_ratio = 0.85` +- `max_ratio = 1.35` +- `absolute_min = 0.25` +- `absolute_max = 3.0` + +2. `selection_guardrails` +- `max_mae_increase = 0.02` +- `max_bucket_hit_drop = 0.01` +- `max_bucket_brier_increase = 0.05` + +这两类约束的目的不是追求“更激进的拟合”,而是防止 EMOS 为了降低 CRPS 而把分布摊得过平,导致业务上更关键的顶桶命中和概率质量变差。 + +### 5.2 当前选中的 blending + +本次训练产物中最终选择: + +- `alpha_mu = 0.0` +- `alpha_sigma = 0.0` + +含义是: + +- 训练器在护栏约束下,没有找到足够安全的候选方案可以替代 legacy 主路径 +- 因此当前正式选中的可用结果,本质上仍然锚定在 legacy + +这是一种正确的保护行为,不是失败。说明门禁已经起作用,避免了坏校准进入主路径。 + +## 6. 离线评估结果 + +评估报告来源: + +- [evaluation_report.json](/E:/web/PolyWeather/artifacts/probability_calibration/evaluation_report.json) + +### 6.1 总体结果 + +Legacy: + +- `mean_crps = 2.793938` +- `mean_mae = 2.721143` +- `bucket_hit_rate = 0.695238` + +EMOS(强制 primary 评估): + +- `mean_crps = 2.650216` +- `mean_mae = 2.722829` +- `bucket_hit_rate = 0.666667` + +Delta: + +- `CRPS = -0.143722` +- `MAE = +0.001686` +- `bucket_hit_rate = -0.028571` + +### 6.2 解读 + +这组结果说明: + +1. `CRPS` 有改善 + 说明从“分布整体平滑度”角度看,EMOS 有一定价值。 + +2. `MAE` 基本持平但略差 + 不是大问题,但也不能算改善。 + +3. `bucket_hit_rate` 明显下降 + 这是当前最大阻塞项。对 PolyWeather 这种结算桶业务来说,顶桶命中率比单纯 CRPS 更关键。 + +因此,离线结论是: + +- `EMOS` 有研究价值 +- 但 **离线强切 primary 仍然不合格** + +## 7. 线上 Shadow 观测结果 + +线上 shadow 报表来源: + +- [shadow_report.json](/E:/web/PolyWeather/artifacts/probability_calibration/shadow_report.json) + +### 7.1 总体结果 + +- `samples = 103` +- `legacy_mean_mae = 1.839223` +- `shadow_mean_mae = 1.851931` +- `delta_mae = +0.012708` + +- `legacy_bucket_hit_rate = 0.669903` +- `shadow_bucket_hit_rate = 0.679612` +- `delta_bucket_hit_rate = +0.009709` + +- `legacy_bucket_brier = 0.462814` +- `shadow_bucket_brier = 0.756649` +- `delta_bucket_brier = +0.293835` + +### 7.2 解读 + +线上 shadow 结果和离线强制 primary 结果不完全相同,这是正常的。原因是: + +- `shadow_report` 反映的是历史记录中实际落盘的 shadow 输出 +- `evaluation_report` 反映的是离线脚本在强制 `emos_primary` 下重新计算的效果 + +当前线上 shadow 的含义是: + +1. 顶桶命中率略有提升 + `+0.97%` + +2. 但 `MAE` 轻微变差 + 虽然幅度不大,但没有形成明确优势 + +3. `bucket_brier` 明显更差 + 说明 shadow 分布仍然偏“摊平”,概率质量不足 + +这是当前最重要的信号: + +- EMOS 在“顶桶命中”上偶尔能赢 +- 但在“概率质量”上还不够好 + +## 8. 城市级观察 + +从当前城市级结果看,EMOS 并不是“全城市统一改善”,而是明显分化: + +### 8.1 相对改善较明显的城市 + +- `London` +- `Hong Kong` +- `Tokyo` +- `New York` + +这些城市在部分指标上看到一定改善,说明当前校准特征在这些城市上更有效。 + +### 8.2 风险较高的城市 + +- `Atlanta` +- `Miami` +- `Chicago` +- `Dallas` +- `Seattle` + +这些城市常见现象是: + +- 顶桶命中没有显著提高 +- 或 `bucket_brier` 明显恶化 +- 或者 `MAE` 出现不必要抬升 + +这说明当前 EMOS 还没有形成稳定的全局校准能力,城市间异质性很强。 + +## 9. 当前判断 + +### 9.1 能不能上线为主路径 + +当前答案: + +- **不能** + +原因: + +1. 离线强制 primary 时,`bucket_hit_rate` 下降 +2. 线上 shadow 时,`bucket_brier` 明显变差 +3. 样本量依然偏小,城市样本不均衡 +4. 城市级表现分化明显 + +### 9.2 当前应该怎么运行 + +当前最合理的运行方式: + +1. 保持 `emos_shadow` +2. 继续落盘 `shadow_prob_snapshot` +3. 继续维护滚动报表 +4. 不修改机器人和网页的正式对外概率展示 + +## 10. 已完成的工程能力 + +目前已经具备以下能力: + +1. 可离线训练 + 脚本:[fit_probability_calibration.py](/E:/web/PolyWeather/scripts/fit_probability_calibration.py) + +2. 可离线评估 + 脚本:[evaluate_probability_calibration.py](/E:/web/PolyWeather/scripts/evaluate_probability_calibration.py) + +3. 可导出训练样本 + 脚本:[export_probability_training_dataset.py](/E:/web/PolyWeather/scripts/export_probability_training_dataset.py) + +4. 可历史回填 shadow 结果 + 脚本:[backfill_probability_shadow_history.py](/E:/web/PolyWeather/scripts/backfill_probability_shadow_history.py) + +5. 可生成滚动 shadow 报表 + 脚本:[build_probability_shadow_report.py](/E:/web/PolyWeather/scripts/build_probability_shadow_report.py) + +6. CI 已接入 + 包含 `ruff / pytest / frontend build / docker build workflow` + +## 11. 下一步建议 + +### 11.1 必做 + +1. 扩大监督样本量 + 重点不是继续堆原始天气 CSV,而是补更多带 forecast snapshot 的历史样本。 + +2. 继续按版本沉淀训练报告 + 每次重训后都更新本报告或新增版本报告,避免只看单次结果。 + +3. 保持 `shadow` 连续观测 + 至少持续一段时间观察滚动指标是否稳定。 + +### 11.2 再做 + +1. 细分城市组建模 + 比如按气候区、结算规则、温度单位分组,而不是完全全局一套参数。 + +2. 优化训练目标 + 目前已经把 `bucket_brier` 纳入目标,但仍需进一步靠近 PolyWeather 的业务目标。 + +3. 补更严格的切换门槛 + 只有在同时满足以下条件时,才考虑切 `emos_primary`: +- `CRPS` 下降 +- `MAE` 不上升 +- `bucket_hit_rate` 不下降 +- `bucket_brier` 不上升 + +## 12. 结论 + +当前 EMOS 状态可以概括为: + +- 工程上:已经完整接入,具备训练、评估、shadow 观测能力 +- 模型上:有一定价值,但还不稳定 +- 产品上:适合继续做 shadow,不适合切主路径 + +最终结论: + +- **继续使用 `emos_shadow`** +- **暂不切 `emos_primary`** +- **继续积累样本并按版本跟踪训练结果** diff --git a/src/analysis/probability_calibration.py b/src/analysis/probability_calibration.py index c2b7c614..a2f19014 100644 --- a/src/analysis/probability_calibration.py +++ b/src/analysis/probability_calibration.py @@ -226,14 +226,61 @@ def _top_bucket_value(distribution: Optional[List[Dict[str, Any]]]) -> Optional[ return int(value) if value is not None else None -def _composite_score(mean_crps: float, mean_mae: float, bucket_hit_rate: float) -> float: - return mean_crps + 0.1 * mean_mae + 2.0 * (1.0 - bucket_hit_rate) +def _bucket_brier_score( + distribution: Optional[List[Dict[str, Any]]], + city_name: str, + actual_high: float, +) -> float: + actual_bucket = apply_city_settlement(city_name, actual_high) + hit_prob = 0.0 + total = 0.0 + for row in distribution or []: + if not isinstance(row, dict): + continue + value = row.get("value") + try: + prob = float(row.get("probability") or 0.0) + except Exception: + prob = 0.0 + if value == actual_bucket: + hit_prob = prob + else: + total += prob * prob + total += (1.0 - hit_prob) ** 2 + return total + + +def _composite_score( + mean_crps: float, + mean_mae: float, + bucket_hit_rate: float, + bucket_brier: float, +) -> float: + return mean_crps + 0.1 * mean_mae + 1.5 * (1.0 - bucket_hit_rate) + 0.75 * bucket_brier def _blend_value(raw_value: float, calibrated_value: float, alpha: float) -> float: return (1.0 - alpha) * raw_value + alpha * calibrated_value +def _clamp_sigma( + raw_sigma: float, + calibrated_sigma: float, + constraints: Optional[Dict[str, Any]], +) -> float: + constraints = constraints or {} + min_ratio = max(0.25, _coalesce_float(constraints.get("min_ratio"), 0.85)) + max_ratio = max(min_ratio, _coalesce_float(constraints.get("max_ratio"), 1.35)) + absolute_min = max(0.1, _coalesce_float(constraints.get("absolute_min"), 0.25)) + absolute_max = max( + absolute_min, + _coalesce_float(constraints.get("absolute_max"), raw_sigma * max_ratio), + ) + sigma_floor = max(absolute_min, raw_sigma * min_ratio) + sigma_cap = min(absolute_max, raw_sigma * max_ratio) + return min(max(calibrated_sigma, sigma_floor), sigma_cap) + + def apply_probability_calibration( city_name: str, temp_symbol: str, @@ -280,6 +327,7 @@ def apply_probability_calibration( global_params = calibration.get("global", {}) or {} city_params = (calibration.get("cities", {}) or {}).get(city_key, {}) or {} blending_cfg = calibration.get("blending", {}) or {} + sigma_constraints = calibration.get("sigma_constraints", {}) or {} mu_cfg = global_params.get("mu", {}) or {} sigma_cfg = global_params.get("sigma", {}) or {} @@ -330,6 +378,7 @@ def apply_probability_calibration( blend_alpha_sigma = max(0.0, min(1.0, _coalesce_float(blending_cfg.get("alpha_sigma"), 1.0))) calibrated_mu = _blend_value(raw_mu, calibrated_mu, blend_alpha_mu) calibrated_sigma = max(0.1, _blend_value(raw_sigma, calibrated_sigma, blend_alpha_sigma)) + calibrated_sigma = _clamp_sigma(raw_sigma, calibrated_sigma, sigma_constraints) calibrated_distribution, calibrated_sorted = _bucket_probabilities( calibrated_mu, calibrated_sigma, @@ -472,6 +521,7 @@ def fit_calibration( legacy_crps_values = [] legacy_mae_values = [] legacy_bucket_hits = [] + legacy_bucket_briers = [] candidate_predictions = [] for idx, sample in enumerate(normalized_samples): city = sample["city"] @@ -496,6 +546,15 @@ def fit_calibration( == apply_city_settlement(city, actual_high) else 0.0 ) + legacy_distribution, _ = _bucket_probabilities( + legacy_mu, + legacy_sigma, + max_so_far=None, + city_name=city, + ) + legacy_bucket_briers.append( + _bucket_brier_score(legacy_distribution, city, actual_high) + ) calibrated_mu = mu_predictions[idx] + city_mu_bias sigma_log = float(np.dot(sigma_coeffs, np.array(sigma_rows[idx], dtype=float))) @@ -514,11 +573,24 @@ def fit_calibration( legacy_mean_crps = _mean(legacy_crps_values) or 0.0 legacy_mean_mae = _mean(legacy_mae_values) or 0.0 legacy_bucket_hit_rate = _mean(legacy_bucket_hits) or 0.0 + legacy_bucket_brier = _mean(legacy_bucket_briers) or 0.0 + sigma_constraints = { + "min_ratio": 0.85, + "max_ratio": 1.35, + "absolute_min": 0.25, + "absolute_max": 3.0, + } legacy_score = _composite_score( legacy_mean_crps, legacy_mean_mae, legacy_bucket_hit_rate, + legacy_bucket_brier, ) + guardrails = { + "max_mae_increase": 0.02, + "max_bucket_hit_drop": 0.01, + "max_bucket_brier_increase": 0.05, + } best_alpha_mu = 0.0 best_alpha_sigma = 0.0 @@ -527,6 +599,7 @@ def fit_calibration( "mean_crps": legacy_mean_crps, "mean_mae": legacy_mean_mae, "bucket_hit_rate": legacy_bucket_hit_rate, + "bucket_brier": legacy_bucket_brier, } alpha_grid = [step / 20.0 for step in range(21)] for alpha_mu in alpha_grid: @@ -534,11 +607,16 @@ def fit_calibration( crps_values = [] mae_values = [] bucket_hits = [] + bucket_briers = [] for row in candidate_predictions: mu_hat = _blend_value(row["raw_mu"], row["calibrated_mu"], alpha_mu) - sigma_hat = max( - 0.1, - _blend_value(row["raw_sigma"], row["calibrated_sigma"], alpha_sigma), + sigma_hat = _clamp_sigma( + row["raw_sigma"], + max( + 0.1, + _blend_value(row["raw_sigma"], row["calibrated_sigma"], alpha_sigma), + ), + sigma_constraints, ) actual_high = row["actual_high"] city = row["city"] @@ -553,11 +631,21 @@ def fit_calibration( predicted_bucket = _top_bucket_value(distribution) actual_bucket = apply_city_settlement(city, actual_high) bucket_hits.append(1.0 if predicted_bucket == actual_bucket else 0.0) + bucket_briers.append( + _bucket_brier_score(distribution, city, actual_high) + ) mean_crps = _mean(crps_values) or 0.0 mean_mae = _mean(mae_values) or 0.0 bucket_hit_rate = _mean(bucket_hits) or 0.0 - score = _composite_score(mean_crps, mean_mae, bucket_hit_rate) + bucket_brier = _mean(bucket_briers) or 0.0 + if mean_mae > legacy_mean_mae + guardrails["max_mae_increase"]: + continue + if bucket_hit_rate + guardrails["max_bucket_hit_drop"] < legacy_bucket_hit_rate: + continue + if bucket_brier > legacy_bucket_brier + guardrails["max_bucket_brier_increase"]: + continue + score = _composite_score(mean_crps, mean_mae, bucket_hit_rate, bucket_brier) if score + 1e-9 < best_score: best_score = score best_alpha_mu = alpha_mu @@ -566,6 +654,7 @@ def fit_calibration( "mean_crps": mean_crps, "mean_mae": mean_mae, "bucket_hit_rate": bucket_hit_rate, + "bucket_brier": bucket_brier, } return { @@ -587,6 +676,8 @@ def fit_calibration( "max_so_far_gap_coef": round(float(sigma_coeffs[4]), 8), }, }, + "sigma_constraints": sigma_constraints, + "selection_guardrails": guardrails, "blending": { "alpha_mu": round(best_alpha_mu, 6), "alpha_sigma": round(best_alpha_sigma, 6), @@ -598,9 +689,11 @@ def fit_calibration( "legacy_mean_crps": round(legacy_mean_crps, 6), "legacy_mean_mae": round(legacy_mean_mae, 6), "legacy_bucket_hit_rate": round(legacy_bucket_hit_rate, 6), + "legacy_bucket_brier": round(legacy_bucket_brier, 6), "selected_mean_crps": round(best_metrics["mean_crps"], 6), "selected_mean_mae": round(best_metrics["mean_mae"], 6), "selected_bucket_hit_rate": round(best_metrics["bucket_hit_rate"], 6), + "selected_bucket_brier": round(best_metrics["bucket_brier"], 6), "selected_score": round(best_score, 6), "legacy_score": round(legacy_score, 6), }, @@ -630,6 +723,17 @@ def default_calibration_payload( "max_so_far_gap_coef": 0.0, }, }, + "sigma_constraints": { + "min_ratio": 0.85, + "max_ratio": 1.35, + "absolute_min": 0.25, + "absolute_max": 3.0, + }, + "selection_guardrails": { + "max_mae_increase": 0.02, + "max_bucket_hit_drop": 0.01, + "max_bucket_brier_increase": 0.05, + }, "blending": { "alpha_mu": 1.0, "alpha_sigma": 1.0, diff --git a/tests/test_probability_calibration.py b/tests/test_probability_calibration.py index 5ce64ccd..6f5bb3df 100644 --- a/tests/test_probability_calibration.py +++ b/tests/test_probability_calibration.py @@ -31,10 +31,17 @@ def _write_calibration(tmp_path: Path): "max_so_far_gap_coef": 0.0, }, }, + "sigma_constraints": { + "min_ratio": 0.85, + "max_ratio": 1.2, + "absolute_min": 0.25, + "absolute_max": 2.0, + }, "cities": { "ankara": { "mu_bias": 0.5, - "sigma_scale": 1.0, + "sigma_scale": 2.0, + "confidence": 1.0, } }, "metrics": {"sample_count": 10, "mean_crps": 0.4}, @@ -76,6 +83,7 @@ def test_shadow_mode_keeps_legacy_distribution(tmp_path): assert result["distribution"] == legacy_distribution assert result["shadow_distribution"] assert result["calibrated_mu"] == 10.5 + assert result["calibrated_sigma"] == 1.2 def test_primary_mode_switches_to_calibrated_distribution(tmp_path): @@ -107,6 +115,7 @@ def test_primary_mode_switches_to_calibrated_distribution(tmp_path): assert result["mode"] == ENGINE_MODE_EMOS_PRIMARY assert result["engine"] == "emos" assert result["calibrated_mu"] == 10.5 + assert result["calibrated_sigma"] == 1.2 assert result["distribution"] assert result["distribution"][0]["value"] >= 10