File size: 3,511 Bytes
c7db54a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
"""
Prediction model wrapper — loads Random Forest trained in the lab
"""
import os
import joblib
import pandas as pd
from pathlib import Path

MODELS_DIR = Path(os.path.dirname(os.path.dirname(__file__))) / "models"


class MatchPredictor:
    def __init__(self):
        self.model = None
        self.team_stats = None
        self.feature_cols = None
        self._loaded = False

    def load(self):
        if self._loaded:
            return True
        try:
            model_path = MODELS_DIR / "match_predictor.pkl"
            data_path = MODELS_DIR / "team_data.pkl"

            if not model_path.exists() or not data_path.exists():
                raise FileNotFoundError(f"Model files not found in {MODELS_DIR}")

            self.model = joblib.load(model_path)
            data = joblib.load(data_path)
            self.team_stats = data["team_stats"]
            self.feature_cols = data["feature_cols"]
            self._loaded = True
            return True
        except Exception as e:
            print(f"Model load error: {e}")
            return False

    def predict(self, team_a: str, team_b: str, is_neutral: bool = True,
                is_major_tournament: bool = True) -> dict:
        if not self._loaded:
            raise RuntimeError("Model not loaded")

        if team_a not in self.team_stats:
            raise ValueError(f"Unknown team: {team_a}")
        if team_b not in self.team_stats:
            raise ValueError(f"Unknown team: {team_b}")
        if team_a == team_b:
            raise ValueError("Teams must be different")

        a = self.team_stats[team_a]
        b = self.team_stats[team_b]

        row = pd.DataFrame([{
            "team_a_winrate": a["winrate"],
            "team_b_winrate": b["winrate"],
            "team_a_goal_avg": a["goal_avg"],
            "team_b_goal_avg": b["goal_avg"],
            "team_a_recent_form": a["recent_form"],
            "team_b_recent_form": b["recent_form"],
            "is_neutral": int(is_neutral),
            "is_major_tournament": int(is_major_tournament),
        }])[self.feature_cols]

        proba = self.model.predict_proba(row)[0]

        return {
            "team_a": team_a,
            "team_b": team_b,
            "team_a_win_prob": round(float(proba[0]), 4),
            "draw_prob": round(float(proba[1]), 4),
            "team_b_win_prob": round(float(proba[2]), 4),
            "is_neutral": is_neutral,
            "is_major_tournament": is_major_tournament,
            "stats_a": {
                "winrate": round(a["winrate"], 4),
                "goal_avg": round(a["goal_avg"], 4),
                "recent_form": round(a["recent_form"], 4),
                "matches_played": a["matches_played"],
            },
            "stats_b": {
                "winrate": round(b["winrate"], 4),
                "goal_avg": round(b["goal_avg"], 4),
                "recent_form": round(b["recent_form"], 4),
                "matches_played": b["matches_played"],
            },
        }

    def get_team_names(self) -> list:
        if not self._loaded:
            return []
        return sorted(self.team_stats.keys())

    def get_feature_importances(self) -> list:
        if not self._loaded:
            return []
        names = self.feature_cols
        imps = self.model.feature_importances_
        return [{"name": n, "importance": round(float(i), 4)}
                for n, i in sorted(zip(names, imps), key=lambda x: -x[1])]


# Singleton
predictor = MatchPredictor()