first (part 2: other directories)
Deploy Iddaai Backend / build-and-deploy (push) Failing after 18s

This commit is contained in:
2026-04-16 15:11:25 +03:00
parent 7814e0bc6b
commit 2f0b85a0c7
203 changed files with 59989 additions and 0 deletions
+371
View File
@@ -0,0 +1,371 @@
"""
Poisson Engine - Matematiksel Gol Modeli
V9 Model için Poisson dağılımı ile gol olasılıkları hesaplar.
Özellikler:
1. Exact score olasılıkları (0-0, 1-0, 1-1, 2-1, vb.)
2. Over/Under olasılıkları (matematiksel)
3. BTTS (Karşılıklı Gol) olasılıkları
4. Expected Goals (xG) tahmini
"""
import math
from typing import Dict, Tuple, Optional
from dataclasses import dataclass, field
def poisson_prob(lam: float, k: int) -> float:
"""
Poisson olasılık formülü.
P(X = k) = (λ^k * e^(-λ)) / k!
"""
if lam <= 0:
return 1.0 if k == 0 else 0.0
return (math.pow(lam, k) * math.exp(-lam)) / math.factorial(k)
@dataclass
class PoissonPrediction:
"""Poisson tahmin sonuçları"""
home_xg: float = 0.0 # Ev sahibi beklenen gol
away_xg: float = 0.0 # Deplasman beklenen gol
total_xg: float = 0.0 # Toplam beklenen gol
# Maç sonucu olasılıkları
home_win_prob: float = 0.0
draw_prob: float = 0.0
away_win_prob: float = 0.0
# Alt/Üst olasılıkları
over_15_prob: float = 0.0
over_25_prob: float = 0.0
over_35_prob: float = 0.0
under_15_prob: float = 0.0
under_25_prob: float = 0.0
under_35_prob: float = 0.0
# BTTS
btts_yes_prob: float = 0.0
btts_no_prob: float = 0.0
# En olası skorlar
most_likely_scores: list = field(default_factory=list)
class PoissonEngine:
"""
Poisson dağılımı ile gol olasılıkları hesaplar.
İstatistiksel bir yaklaşım - machine learning'den bağımsız.
"""
# Lig bazlı ortalama gol verileri (varsayılan değerler)
DEFAULT_HOME_XG = 1.45
DEFAULT_AWAY_XG = 1.15
DEFAULT_LEAGUE_AVG = 2.60
def __init__(self):
self.max_goals = 7 # Hesaplama için maksimum gol sayısı
def calculate_xg(
self,
home_goals_avg: float,
home_conceded_avg: float,
away_goals_avg: float,
away_conceded_avg: float,
league_home_avg: float = None,
league_away_avg: float = None,
league_total_avg: float = None
) -> Tuple[float, float]:
"""
Beklenen gol (xG) hesapla.
Attack strength * Defense weakness * League average
"""
# Varsayılan lig ortalamaları
if league_home_avg is None:
league_home_avg = self.DEFAULT_HOME_XG
if league_away_avg is None:
league_away_avg = self.DEFAULT_AWAY_XG
if league_total_avg is None:
league_total_avg = self.DEFAULT_LEAGUE_AVG
# Güç hesaplamaları
# Ev sahibi saldırı gücü = Ev gol ortalaması / Lig ev gol ortalaması
home_attack = home_goals_avg / league_home_avg if league_home_avg > 0 else 1.0
# Deplasman savunma zayıflığı = Deplasman yenilen gol / Lig deplasman yenilen
away_defense = away_conceded_avg / league_away_avg if league_away_avg > 0 else 1.0
# Deplasman saldırı gücü
away_attack = away_goals_avg / league_away_avg if league_away_avg > 0 else 1.0
# Ev sahibi savunma zayıflığı
home_defense = home_conceded_avg / league_home_avg if league_home_avg > 0 else 1.0
# Expected Goals
home_xg = home_attack * away_defense * league_home_avg
away_xg = away_attack * home_defense * league_away_avg
# Aşırı değerleri sınırla
home_xg = max(0.3, min(home_xg, 4.0))
away_xg = max(0.2, min(away_xg, 3.5))
return home_xg, away_xg
def calculate_score_matrix(
self,
home_xg: float,
away_xg: float
) -> Dict[Tuple[int, int], float]:
"""
Tüm skor kombinasyonlarının olasılıklarını hesapla.
Returns:
Dict[(home_goals, away_goals)] = probability
"""
matrix = {}
for home_goals in range(self.max_goals + 1):
for away_goals in range(self.max_goals + 1):
prob = poisson_prob(home_xg, home_goals) * poisson_prob(away_xg, away_goals)
matrix[(home_goals, away_goals)] = prob
return matrix
def calculate_match_odds(
self,
home_xg: float,
away_xg: float
) -> Tuple[float, float, float]:
"""
1X2 olasılıklarını hesapla.
Returns:
(home_win, draw, away_win) probabilities
"""
matrix = self.calculate_score_matrix(home_xg, away_xg)
home_win = 0.0
draw = 0.0
away_win = 0.0
for (h, a), prob in matrix.items():
if h > a:
home_win += prob
elif h == a:
draw += prob
else:
away_win += prob
# Normalize (toplam 1 olmalı)
total = home_win + draw + away_win
if total > 0:
home_win /= total
draw /= total
away_win /= total
return home_win, draw, away_win
def calculate_over_under(
self,
home_xg: float,
away_xg: float
) -> Dict[str, float]:
"""
Alt/Üst olasılıklarını hesapla.
"""
matrix = self.calculate_score_matrix(home_xg, away_xg)
over_15 = 0.0
over_25 = 0.0
over_35 = 0.0
for (h, a), prob in matrix.items():
total = h + a
if total > 1.5:
over_15 += prob
if total > 2.5:
over_25 += prob
if total > 3.5:
over_35 += prob
return {
"over_15": over_15,
"over_25": over_25,
"over_35": over_35,
"under_15": 1 - over_15,
"under_25": 1 - over_25,
"under_35": 1 - over_35,
}
def calculate_btts(
self,
home_xg: float,
away_xg: float
) -> Tuple[float, float]:
"""
Karşılıklı Gol (Both Teams To Score) olasılığı.
"""
# P(Home scores at least 1) = 1 - P(Home scores 0)
home_scores = 1 - poisson_prob(home_xg, 0)
# P(Away scores at least 1) = 1 - P(Away scores 0)
away_scores = 1 - poisson_prob(away_xg, 0)
# P(BTTS) = P(Home scores) * P(Away scores)
btts_yes = home_scores * away_scores
btts_no = 1 - btts_yes
return btts_yes, btts_no
def get_most_likely_scores(
self,
home_xg: float,
away_xg: float,
top_n: int = 5
) -> list:
"""
En olası skorları getir.
"""
matrix = self.calculate_score_matrix(home_xg, away_xg)
# Olasılığa göre sırala
sorted_scores = sorted(matrix.items(), key=lambda x: x[1], reverse=True)
return [
{"score": f"{h}-{a}", "probability": round(prob * 100, 1)}
for (h, a), prob in sorted_scores[:top_n]
]
def predict(
self,
home_goals_avg: float,
home_conceded_avg: float,
away_goals_avg: float,
away_conceded_avg: float,
league_home_avg: float = None,
league_away_avg: float = None,
league_total_avg: float = None
) -> PoissonPrediction:
"""
Tam Poisson tahmini.
"""
prediction = PoissonPrediction()
# 1. xG hesapla
home_xg, away_xg = self.calculate_xg(
home_goals_avg, home_conceded_avg,
away_goals_avg, away_conceded_avg,
league_home_avg, league_away_avg, league_total_avg
)
prediction.home_xg = round(home_xg, 2)
prediction.away_xg = round(away_xg, 2)
prediction.total_xg = round(home_xg + away_xg, 2)
# 2. Maç sonucu
hw, d, aw = self.calculate_match_odds(home_xg, away_xg)
prediction.home_win_prob = round(hw, 3)
prediction.draw_prob = round(d, 3)
prediction.away_win_prob = round(aw, 3)
# 3. Alt/Üst
ou = self.calculate_over_under(home_xg, away_xg)
prediction.over_15_prob = round(ou["over_15"], 3)
prediction.over_25_prob = round(ou["over_25"], 3)
prediction.over_35_prob = round(ou["over_35"], 3)
prediction.under_15_prob = round(ou["under_15"], 3)
prediction.under_25_prob = round(ou["under_25"], 3)
prediction.under_35_prob = round(ou["under_35"], 3)
# 4. BTTS
btts_yes, btts_no = self.calculate_btts(home_xg, away_xg)
prediction.btts_yes_prob = round(btts_yes, 3)
prediction.btts_no_prob = round(btts_no, 3)
# 5. En olası skorlar
prediction.most_likely_scores = self.get_most_likely_scores(home_xg, away_xg)
return prediction
def get_features(
self,
home_goals_avg: float,
home_conceded_avg: float,
away_goals_avg: float,
away_conceded_avg: float,
league_home_avg: float = None,
league_away_avg: float = None,
league_total_avg: float = None
) -> Dict[str, float]:
"""
Model için feature dict.
"""
pred = self.predict(
home_goals_avg, home_conceded_avg,
away_goals_avg, away_conceded_avg,
league_home_avg, league_away_avg, league_total_avg
)
return {
"poisson_home_xg": pred.home_xg,
"poisson_away_xg": pred.away_xg,
"poisson_total_xg": pred.total_xg,
"poisson_home_win": pred.home_win_prob,
"poisson_draw": pred.draw_prob,
"poisson_away_win": pred.away_win_prob,
"poisson_over_15": pred.over_15_prob,
"poisson_over_25": pred.over_25_prob,
"poisson_over_35": pred.over_35_prob,
"poisson_btts_yes": pred.btts_yes_prob,
}
# Singleton
_engine_instance = None
def get_poisson_engine() -> PoissonEngine:
"""Singleton pattern"""
global _engine_instance
if _engine_instance is None:
_engine_instance = PoissonEngine()
return _engine_instance
# Test
if __name__ == "__main__":
engine = get_poisson_engine()
# Örnek: Güçlü ev sahibi vs zayıf deplasman
print("=" * 60)
print("POISSON ENGINE TEST")
print("Galatasaray (ev) vs Antalyaspor (deplasman)")
print("=" * 60)
pred = engine.predict(
home_goals_avg=2.1, # GS ev ortalaması
home_conceded_avg=0.8, # GS ev yenilen
away_goals_avg=0.9, # Antalya deplasman gol
away_conceded_avg=1.8, # Antalya deplasman yenilen
league_home_avg=1.5,
league_away_avg=1.1
)
print(f"\n📊 Expected Goals:")
print(f" Ev Sahibi xG: {pred.home_xg}")
print(f" Deplasman xG: {pred.away_xg}")
print(f" Toplam xG: {pred.total_xg}")
print(f"\n🎯 Maç Sonucu:")
print(f" 1 (Ev): {pred.home_win_prob*100:.1f}%")
print(f" X (Beraberlik): {pred.draw_prob*100:.1f}%")
print(f" 2 (Deplasman): {pred.away_win_prob*100:.1f}%")
print(f"\n⚽ Alt/Üst:")
print(f" 2.5 Üst: {pred.over_25_prob*100:.1f}%")
print(f" 2.5 Alt: {pred.under_25_prob*100:.1f}%")
print(f"\n🤝 Karşılıklı Gol:")
print(f" KG Var: {pred.btts_yes_prob*100:.1f}%")
print(f" KG Yok: {pred.btts_no_prob*100:.1f}%")
print(f"\n📈 En Olası Skorlar:")
for score_data in pred.most_likely_scores:
print(f" {score_data['score']}: {score_data['probability']}%")