Thibaut Forest Claude Opus 5 (1M context) commited on
Commit
79a4af2
·
1 Parent(s): 11cbd93

all48oof: static fit protocol is the default (user-shaped) - one fit per fold on the other buildings' FULL closed history, deployment's exact shape; 40s runtime; new reference panel 1893.4 / ALL-48 1913.3; 'cv all48oof wf' keeps the walk-forward variant

Browse files
Files changed (1) hide show
  1. batteryswap_example/cv.py +46 -6
batteryswap_example/cv.py CHANGED
@@ -610,7 +610,7 @@ def ablation_report(df, ns, label, ref='base'):
610
 
611
  def run_all48_oof(n_folds=5, seed=0, origins=range(48),
612
  dataset_path=Path('dataset'), kind=None, variant='base',
613
- arms=('self', 'oof'), blend=None):
614
  """The walk-forward cost harness with BUILDING-CLEAN predictions.
615
 
616
  all48 itself is temporal, not fold-based, and its PLANNING must stay
@@ -637,6 +637,16 @@ def run_all48_oof(n_folds=5, seed=0, origins=range(48),
637
  a post-hoc blend whose beliefs disagree with the count machinery fails
638
  for that reason alone).
639
  """
 
 
 
 
 
 
 
 
 
 
640
  kind = kind or CHAMPION['model']
641
  t = load_table(dataset_path)
642
  mc.FEATURES = list(VARIANTS[variant](t))
@@ -653,12 +663,31 @@ def run_all48_oof(n_folds=5, seed=0, origins=range(48),
653
  p.split_days = CHAMPION['split_days']
654
  p.floor_scale, p.recent_deaths = 0.0, 0.0
655
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
656
  recs = []
657
  for idx in origins:
658
  c = ctx[idx]
659
  T = c['start_time']
660
  tr = mc.training_pairs(t, T)
661
- if tr['dies42'].sum() < 3:
662
  continue
663
  rows = (t[t['origin_idx'] == idx].set_index('device_id')
664
  .reindex(c['locs']['battery']).dropna(subset=['v_last']))
@@ -670,6 +699,14 @@ def run_all48_oof(n_folds=5, seed=0, origins=range(48),
670
  row_fold = rows.index.to_series().map(dev_bldg).map(bldg_fold)
671
 
672
  def _pred(k, arm):
 
 
 
 
 
 
 
 
673
  if k == 'tau':
674
  # fit-free pseudo-model: the physics timer as a rank source
675
  # (only meaningful inside a value-preserving blend)
@@ -835,11 +872,14 @@ def main():
835
  elif proto == 'screen':
836
  screen()
837
  elif proto == 'all48oof':
838
- # THE SCORE (user directive 2026-08-22): oof arm only by default.
839
- # `cv all48oof self` additionally runs the self arm - the validity
840
- # check (must reproduce panel 1679.2) and the flattery-term readout.
 
 
841
  arms = ('self', 'oof') if variant == 'self' else ('oof',)
842
- df = run_all48_oof(arms=arms)
 
843
  df.to_csv('/tmp/cv_all48oof.csv', index=False)
844
  oof_report(df)
845
  elif proto == 'oofcand':
 
610
 
611
  def run_all48_oof(n_folds=5, seed=0, origins=range(48),
612
  dataset_path=Path('dataset'), kind=None, variant='base',
613
+ arms=('self', 'oof'), blend=None, fit='static'):
614
  """The walk-forward cost harness with BUILDING-CLEAN predictions.
615
 
616
  all48 itself is temporal, not fold-based, and its PLANNING must stay
 
637
  a post-hoc blend whose beliefs disagree with the count machinery fails
638
  for that reason alone).
639
  """
640
+ # fit='static' (default; user-shaped 2026-08-22): each fold's model is
641
+ # fitted ONCE on the OTHER buildings' FULL closed history and scores all
642
+ # 48 origins - exactly deployment's shape (the shipped static model is
643
+ # one fit on the train fleet's full history through data end, applied at
644
+ # public origins that are mostly in its past; the competition itself
645
+ # hands the model future-of-origin FOREIGN-building knowledge, so
646
+ # respecting a temporal cutoff for other buildings is stricter than the
647
+ # thing being estimated and it starves warm-up in a way deployment never
648
+ # does). Calendar co-movement across buildings is therefore IN scope by
649
+ # design. fit='walkforward' keeps the old per-origin refits.
650
  kind = kind or CHAMPION['model']
651
  t = load_table(dataset_path)
652
  mc.FEATURES = list(VARIANTS[variant](t))
 
663
  p.split_days = CHAMPION['split_days']
664
  p.floor_scale, p.recent_deaths = 0.0, 0.0
665
 
666
+ static_models = {}
667
+ if fit == 'static':
668
+ # one fit per fold on the full closed foreign history (+ one all-
669
+ # buildings fit for the self arm) - the deployment-shaped protocol
670
+ hazard = kind in ('aft', 'dthaz', 'dthaz_aux', 'logbag_open',
671
+ 'blend_dh', 'blend_dhaux')
672
+ pool = (mc.censored_pairs(t, t['origin'].max()) if hazard
673
+ else t[t['origin'] <= t['origin'].max()
674
+ - pd.Timedelta(days=WINDOW_DAYS)])
675
+ pool_fold = pool['device_id'].map(dev_bldg).map(bldg_fold)
676
+ make = ((lambda: mc.MODELS[kind]()) if kind in mc.MODELS
677
+ else (lambda: mc.SklearnRUL(kind)))
678
+ for f in sorted(bldg_fold.dropna().unique()):
679
+ static_models[f] = make().fit(pool[(pool_fold != f).values])
680
+ if 'self' in arms:
681
+ static_models['SELF'] = make().fit(pool)
682
+ print(f'static foreign fits: {len(static_models)} on '
683
+ f'{len(pool)} closed pairs', flush=True, file=sys.stderr)
684
+
685
  recs = []
686
  for idx in origins:
687
  c = ctx[idx]
688
  T = c['start_time']
689
  tr = mc.training_pairs(t, T)
690
+ if fit != 'static' and tr['dies42'].sum() < 3:
691
  continue
692
  rows = (t[t['origin_idx'] == idx].set_index('device_id')
693
  .reindex(c['locs']['battery']).dropna(subset=['v_last']))
 
699
  row_fold = rows.index.to_series().map(dev_bldg).map(bldg_fold)
700
 
701
  def _pred(k, arm):
702
+ if fit == 'static' and k == kind:
703
+ if arm == 'self':
704
+ return static_models['SELF'].predict(rows)
705
+ parts = []
706
+ for f in sorted(row_fold.dropna().unique()):
707
+ parts.append(static_models[f].predict(
708
+ rows[(row_fold == f).values]))
709
+ return pd.concat(parts).reindex(rows.index)
710
  if k == 'tau':
711
  # fit-free pseudo-model: the physics timer as a rank source
712
  # (only meaningful inside a value-preserving blend)
 
872
  elif proto == 'screen':
873
  screen()
874
  elif proto == 'all48oof':
875
+ # THE SCORE (user directives 2026-08-22): oof arm, STATIC fit
876
+ # protocol (one fit per fold on the other buildings' full closed
877
+ # history - deployment's shape). `cv all48oof self` adds the self
878
+ # arm (flattery readout); `cv all48oof wf` uses the old per-origin
879
+ # walk-forward refits (whose self arm reproduces panel 1679.2).
880
  arms = ('self', 'oof') if variant == 'self' else ('oof',)
881
+ fitp = 'walkforward' if variant == 'wf' else 'static'
882
+ df = run_all48_oof(arms=arms, fit=fitp)
883
  df.to_csv('/tmp/cv_all48oof.csv', index=False)
884
  oof_report(df)
885
  elif proto == 'oofcand':