Spaces:
Sleeping
Sleeping
| import os | |
| import joblib | |
| import pandas as pd | |
| from data_loader import DataLoader | |
| from feature_engineer import FeatureEngineer | |
| from rule_based_model import RuleBasedModel | |
| def get_predictions(model_dir='artifacts'): | |
| loader = DataLoader() | |
| rankings = loader.get_rankings() | |
| form = loader.get_team_form() | |
| teams = loader.get_teams() | |
| matches = loader.get_matches() | |
| try: | |
| manual_features = loader.get_manual_features() | |
| except Exception as e: | |
| print(f"WARNING: Could not load manual features: {e}") | |
| manual_features = None | |
| odds_summary = loader.get_latest_odds_summary() | |
| weather_summary = loader.get_latest_weather_summary() | |
| loader.close() | |
| engineer = FeatureEngineer(rankings, form, teams, manual_features) | |
| # Select upcoming matches | |
| upcoming = matches[matches['status'].isin(['scheduled', 'active'])].copy() | |
| if len(upcoming) == 0: | |
| return {"predictions": [], "skipped": []} | |
| X_pred, _ = engineer.build_dataset(upcoming) | |
| # Load model | |
| model_path = os.path.join(model_dir, 'rule_based_baseline.pkl') | |
| if not os.path.exists(model_path): | |
| raise FileNotFoundError(f"Model not found at {model_path}. Run train.py first.") | |
| clf = joblib.load(model_path) | |
| # Predict probabilities | |
| probs = clf.predict_proba(X_pred) | |
| X_pred['prob_away_win'] = probs[:, 0] | |
| X_pred['prob_draw'] = probs[:, 1] | |
| X_pred['prob_home_win'] = probs[:, 2] | |
| # Merge back to upcoming by match_id | |
| upcoming = upcoming.merge(X_pred[['match_id', 'prob_away_win', 'prob_draw', 'prob_home_win']], left_on='id', right_on='match_id', how='left') | |
| results = [] | |
| skipped = [] | |
| for _, row in upcoming.iterrows(): | |
| if pd.isna(row['prob_home_win']): | |
| # Determine reason | |
| reason = "unknown" | |
| if pd.isna(row['home_team_id']) or pd.isna(row['away_team_id']): | |
| reason = "missing_team_placeholder" | |
| else: | |
| reason = "missing_features" | |
| skipped.append({ | |
| "match_id": row['id'], | |
| "home_team_id": row['home_team_id'] if not pd.isna(row['home_team_id']) else None, | |
| "away_team_id": row['away_team_id'] if not pd.isna(row['away_team_id']) else None, | |
| "reason": reason | |
| }) | |
| continue | |
| # Check if manual features were applied | |
| applied = False | |
| if manual_features is not None and row['id'] in manual_features.index: | |
| applied = True | |
| odds_rows = [] | |
| if odds_summary is not None and not odds_summary.empty: | |
| match_odds = odds_summary[odds_summary['match_id'] == row['id']] | |
| for _, odds in match_odds.iterrows(): | |
| odds_rows.append({ | |
| "bookmaker_key": odds.get("bookmaker_key"), | |
| "bookmaker_title": odds.get("bookmaker_title"), | |
| "market_key": odds.get("market_key"), | |
| "market_title": odds.get("market_title"), | |
| "home_odds": float(odds["home_odds"]) if not pd.isna(odds.get("home_odds")) else None, | |
| "draw_odds": float(odds["draw_odds"]) if not pd.isna(odds.get("draw_odds")) else None, | |
| "away_odds": float(odds["away_odds"]) if not pd.isna(odds.get("away_odds")) else None, | |
| "last_update": str(odds.get("last_update")) if not pd.isna(odds.get("last_update")) else None, | |
| }) | |
| weather = None | |
| if weather_summary is not None and not weather_summary.empty and row['id'] in weather_summary.index: | |
| w = weather_summary.loc[row['id']] | |
| weather = { | |
| "forecast_time": str(w.get("forecast_time")) if not pd.isna(w.get("forecast_time")) else None, | |
| "temperature_c": float(w["temperature_c"]) if not pd.isna(w.get("temperature_c")) else None, | |
| "apparent_temperature_c": float(w["apparent_temperature_c"]) if not pd.isna(w.get("apparent_temperature_c")) else None, | |
| "humidity_pct": float(w["humidity_pct"]) if not pd.isna(w.get("humidity_pct")) else None, | |
| "precipitation_probability_pct": float(w["precipitation_probability_pct"]) if not pd.isna(w.get("precipitation_probability_pct")) else None, | |
| "precipitation_mm": float(w["precipitation_mm"]) if not pd.isna(w.get("precipitation_mm")) else None, | |
| "wind_speed_kmh": float(w["wind_speed_kmh"]) if not pd.isna(w.get("wind_speed_kmh")) else None, | |
| "wind_gusts_kmh": float(w["wind_gusts_kmh"]) if not pd.isna(w.get("wind_gusts_kmh")) else None, | |
| "weather_code": int(w["weather_code"]) if not pd.isna(w.get("weather_code")) else None, | |
| } | |
| results.append({ | |
| "match_id": row['id'], | |
| "home_team_id": row['home_team_id'], | |
| "away_team_id": row['away_team_id'], | |
| "prob_home_win": float(row['prob_home_win']), | |
| "prob_draw": float(row['prob_draw']), | |
| "prob_away_win": float(row['prob_away_win']), | |
| "manual_features_applied": applied, | |
| "odds": odds_rows, | |
| "weather": weather | |
| }) | |
| return { | |
| "predictions": results, | |
| "skipped": skipped | |
| } | |
| def run_predictions(): | |
| data = get_predictions() | |
| print("\nUpcoming Match Predictions:") | |
| for p in data['predictions']: | |
| print(f"Match {p['match_id']} | {p['home_team_id']} vs {p['away_team_id']} " | |
| f"| 1: {p['prob_home_win']:.2f} X: {p['prob_draw']:.2f} 2: {p['prob_away_win']:.2f}") | |
| if __name__ == "__main__": | |
| run_predictions() | |