Source code for penaltyblog.models.football_probability_grid
from typing import Callable, List
import numpy as np
from numpy.typing import NDArray
[docs]
class FootballProbabilityGrid:
"""
Class for calculating probabilities of football outcomes.
"""
[docs]
def __init__(
self,
goal_matrix: NDArray,
home_goal_expectation: float,
away_goal_expectation: float,
):
"""
Calculate probabilities of football outcomes.
Parameters
----------
goal_matrix : List[List[float]] Matrix of probabilities for each goal difference
home_goal_expectation : float Expected number of goals for home
away_goal_expectation : float Expected number of goals for away
"""
self.grid = np.array(goal_matrix)
self.home_goal_expectation = home_goal_expectation
self.away_goal_expectation = away_goal_expectation
def __repr__(self) -> str:
return (
f"Module: Penaltyblog\n\n"
f"Class: FootballProbabilityGrid\n\n"
f"Home Goal Expectation: {self.home_goal_expectation}\n"
f"Away Goal Expectation: {self.away_goal_expectation}\n\n"
f"Home Win: {self.home_win}\n"
f"Draw: {self.draw}\n"
f"Away Win: {self.away_win}\n"
)
def _sum(self, condition: Callable[[int, int], bool]) -> float:
rows, cols = self.grid.shape
return sum(
self.grid[i, j] for i in range(rows) for j in range(cols) if condition(i, j)
)
@property
def home_win(self) -> float:
"""Probability of home win"""
return self._sum(lambda a, b: a > b)
@property
def draw(self) -> float:
"""Probability of draw"""
return self._sum(lambda a, b: a == b)
@property
def away_win(self) -> float:
"""Probability of away win"""
return self._sum(lambda a, b: a < b)
@property
def both_teams_to_score(self) -> float:
"""Probability of both teams scoring"""
return self._sum(lambda a, b: a > 0 and b > 0)
@property
def home_draw_away(self) -> List[float]:
"""1x2 Probabilities"""
return [self.home_win, self.draw, self.away_win]
[docs]
def total_goals(self, over_under: str, strike: float) -> float:
"""
Calculate probabilities for total goals market
Parameters
----------
over_under : str
'over' or 'under'
strike : float
Total goals value
"""
conditions = {
"over": lambda a, b: a + b > strike,
"under": lambda a, b: a + b < strike,
}
if over_under not in conditions:
raise ValueError("over_under must be 'over' or 'under'")
return self._sum(conditions[over_under])
[docs]
def asian_handicap(self, home_away: str, strike: float) -> float:
"""
Calculate probabilities for asian handicap market
Parameters
----------
home_away : str
'home' or 'away'
strike : float
Handicap value
"""
conditions = {
"home": lambda a, b: a - b > strike,
"away": lambda a, b: b - a > strike,
}
if home_away not in conditions:
raise ValueError("home_away must be 'home' or 'away'")
return self._sum(conditions[home_away])