amarorn / models /baseline.py
beAnalytic's picture
feat: sync main with feature/superbet-live-inplay
16c19b8 verified
Raw
History Blame Contribute Delete
3.21 kB
import math
from schemas.models import BolaoFeature, BolaoLabel
HOME_ADVANTAGE = 0.15
LABELS: tuple[BolaoLabel, ...] = ("1", "X", "2")
def _baseline_score(features: BolaoFeature) -> float:
score_home = HOME_ADVANTAGE
reasons: list[str] = []
if features.home_position and features.away_position:
pos_diff = features.away_position - features.home_position
score_home += pos_diff * 0.02
if pos_diff > 3:
reasons.append(f"{features.home_team} {features.home_position}º vs {features.away_team} {features.away_position}º")
elif pos_diff < -3:
reasons.append(f"{features.away_team} melhor na tabela ({features.away_position}º vs {features.home_position}º)")
if features.home_points is not None and features.away_points is not None:
pts_diff = features.home_points - features.away_points
score_home += pts_diff * 0.008
if features.home_form and features.away_form and features.home_form != "N/A":
home_wins = features.home_form.count("V")
away_wins = features.away_form.count("V")
score_home += (home_wins - away_wins) * 0.05
if features.h2h_home_wins is not None and features.h2h_away_wins is not None:
h2h_diff = features.h2h_home_wins - features.h2h_away_wins
score_home += h2h_diff * 0.06
if features.sentiment_home is not None and features.sentiment_away is not None:
sent_diff = features.sentiment_home - features.sentiment_away
score_home += sent_diff * 0.2
if abs(sent_diff) > 0.2:
reasons.append("sentimento das notícias")
if features.injury_mentions_home > features.injury_mentions_away + 1:
score_home -= 0.1
reasons.append(f"desfalques {features.home_team}")
elif features.injury_mentions_away > features.injury_mentions_home + 1:
score_home += 0.1
reasons.append(f"desfalques {features.away_team}")
if features.news_count_home + features.news_count_away > 0:
news_ratio = features.news_count_home / max(features.news_count_home + features.news_count_away, 1)
score_home += (news_ratio - 0.5) * 0.1
return score_home, reasons
def predict_baseline_probs(features: BolaoFeature) -> dict[BolaoLabel, float]:
"""Distribui 1/X/2 a partir do score heurístico (para Brier/log-loss)."""
score_home, _ = _baseline_score(features)
scale = 4.0
raw = {
"1": math.exp(score_home * scale),
"X": math.exp(-abs(score_home) * scale * 0.5),
"2": math.exp(-score_home * scale),
}
total = sum(raw.values())
return {k: v / total for k, v in raw.items()}
def predict_baseline(features: BolaoFeature) -> tuple[BolaoLabel, float, str]:
"""
Previsão heurística combinando estatísticas + sentimento + notícias.
Retorna (palpite, confiança 0-1, motivo).
"""
score_home, reasons = _baseline_score(features)
probs = predict_baseline_probs(features)
prediction = max(probs, key=probs.get) # type: ignore[arg-type]
confidence = min(abs(score_home) + 0.3, 0.85)
reason = "; ".join(reasons) if reasons else "equilíbrio entre os times"
return prediction, confidence, reason