Spaces:
Runtime error
Runtime error
| """Hiperparâmetros do modelo Copa — config + overrides em data/wc/hyperparams.json.""" | |
| from __future__ import annotations | |
| import json | |
| from dataclasses import asdict, dataclass, replace | |
| from functools import lru_cache | |
| from pathlib import Path | |
| from typing import Any | |
| from config import settings | |
| HYPERPARAMS_PATH = Path("data/wc/hyperparams.json") | |
| _active_override = None | |
| class WcHyperParams: | |
| elo_k: float = 24.0 | |
| elo_home_adv: float = 30.0 | |
| elo_initial: float = 1500.0 | |
| home_adv_goals: float = 0.12 | |
| home_adv_goals_neutral: float = 0.04 | |
| home_adv_corners: float = 0.45 | |
| home_adv_corners_neutral: float = 0.15 | |
| logistic_c: float = 0.85 | |
| logistic_class_weight: str | None = "balanced" | |
| logistic_max_iter: int = 3000 | |
| logistic_calibration_cv: int = 3 | |
| ensemble_weight_steps: int = 80 | |
| kxl_blend_weight: float = 0.20 | |
| rho_min: float = -0.2 | |
| rho_max: float = 0.2 | |
| rho_step: float = 0.01 | |
| draw_prob_floor: float = 0.18 | |
| poisson_season_half_life: float = 10.0 | |
| draw_model_blend: float = 0.55 | |
| knockout_draw_discount: float = 0.82 | |
| def home_advantage_goals(self, is_neutral: bool) -> float: | |
| return self.home_adv_goals_neutral if is_neutral else self.home_adv_goals | |
| def home_advantage_corners(self, is_neutral: bool) -> float: | |
| return self.home_adv_corners_neutral if is_neutral else self.home_adv_corners | |
| def _from_settings_defaults() -> WcHyperParams: | |
| return WcHyperParams( | |
| elo_k=getattr(settings, "wc_elo_k", 32.0), | |
| elo_home_adv=getattr(settings, "wc_elo_home_adv", 30.0), | |
| elo_initial=getattr(settings, "wc_elo_initial", 1500.0), | |
| home_adv_goals=getattr(settings, "wc_home_adv_goals", 0.12), | |
| home_adv_goals_neutral=getattr(settings, "wc_home_adv_goals_neutral", 0.04), | |
| home_adv_corners=getattr(settings, "wc_home_adv_corners", 0.45), | |
| home_adv_corners_neutral=getattr(settings, "wc_home_adv_corners_neutral", 0.15), | |
| logistic_c=getattr(settings, "wc_logistic_c", 0.85), | |
| logistic_class_weight=getattr(settings, "wc_logistic_class_weight", "balanced"), | |
| logistic_max_iter=getattr(settings, "wc_logistic_max_iter", 3000), | |
| logistic_calibration_cv=getattr(settings, "wc_logistic_calibration_cv", 3), | |
| ensemble_weight_steps=getattr(settings, "wc_ensemble_weight_steps", 40), | |
| kxl_blend_weight=getattr(settings, "wc_kxl_blend_weight", 0.20), | |
| rho_min=getattr(settings, "wc_rho_min", -0.20), | |
| rho_max=getattr(settings, "wc_rho_max", 0.20), | |
| rho_step=getattr(settings, "wc_rho_step", 0.01), | |
| draw_prob_floor=getattr(settings, "wc_draw_prob_floor", 0.18), | |
| poisson_season_half_life=getattr(settings, "wc_poisson_season_half_life", 8.0), | |
| draw_model_blend=getattr(settings, "wc_draw_model_blend", 0.55), | |
| knockout_draw_discount=getattr(settings, "wc_knockout_draw_discount", 0.82), | |
| ) | |
| def _merge_dict(base: WcHyperParams, overrides: dict[str, Any]) -> WcHyperParams: | |
| valid = {k: v for k, v in overrides.items() if k in base.__dataclass_fields__} | |
| if valid.get("logistic_class_weight") == "none": | |
| valid["logistic_class_weight"] = None | |
| return replace(base, **valid) if valid else base | |
| def _fast_train_overrides(data: dict) -> dict[str, Any]: | |
| if not data.get("fast_mode"): | |
| return {} | |
| return { | |
| "logistic_calibration_cv": 2, | |
| "logistic_max_iter": min( | |
| int(data.get("hyperparams", {}).get("logistic_max_iter", 3000)), | |
| 1500, | |
| ), | |
| } | |
| def load_hyperparams_file(path: Path | None = None) -> WcHyperParams | None: | |
| p = path or HYPERPARAMS_PATH | |
| if not p.exists(): | |
| return None | |
| data = json.loads(p.read_text(encoding="utf-8")) | |
| block = {**data.get("hyperparams", data), **_fast_train_overrides(data)} | |
| base = _from_settings_defaults() | |
| return _merge_dict(base, block) | |
| def get_wc_hyperparams() -> WcHyperParams: | |
| if _active_override is not None: | |
| return _active_override | |
| tuned = load_hyperparams_file() | |
| if tuned is not None: | |
| return tuned | |
| return _from_settings_defaults() | |
| def set_active_hyperparams(hp: WcHyperParams | None) -> None: | |
| global _active_override | |
| _active_override = hp | |
| def save_hyperparams(hp: WcHyperParams, path: Path | None = None, meta: dict | None = None) -> Path: | |
| p = path or HYPERPARAMS_PATH | |
| p.parent.mkdir(parents=True, exist_ok=True) | |
| payload = { | |
| "hyperparams": asdict(hp), | |
| **(meta or {}), | |
| } | |
| if payload["hyperparams"].get("logistic_class_weight") is None: | |
| payload["hyperparams"]["logistic_class_weight"] = "none" | |
| p.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") | |
| load_hyperparams_file.cache_clear() | |
| return p | |
| def clear_hyperparams_cache() -> None: | |
| load_hyperparams_file.cache_clear() | |