Poisson-ELO Ensemble¶
Overview¶
The Poisson-ELO ensemble combines two complementary modeling approaches — Poisson regression for goal-scoring rates and ELO rating systems for team strength — via a weighted average to produce match predictions. The intuition is that Poisson models capture the stochastic nature of football scoring (goals are rare, independent events fitting a Poisson process), while ELO captures systematic strength differences and form dynamics. Blending them reduces the weaknesses of each approach.
The Poisson model estimates expected goals (λ) for each team, incorporating home advantage and attack/defense strength parameters. The ELO model produces pairwise win probabilities from rating differences. The ensemble combines their 1X2 probability outputs with weights determined by backtesting performance.
Why It Matters¶
The ensemble matters because:
1. Complementarity: Poisson captures goal-scoring mechanics; ELO captures opponent-adjusted strength
2. Reduced overfitting: Each model alone may overfit to specific patterns; blending reduces this
3. Better calibration: Each model's raw probabilities are typically overconfident; ensembling improves calibration
4. Adaptive weighting: The optimal blend weight varies by league — can be tuned per tournament
Architecture¶
Step 1: Poisson layer
- Estimate λ_home and λ_away using historical match data
- Parameters: home attack strength, away defense strength, home advantage term
- Output: P(Home), P(Draw), P(Away) via Poisson score distribution
Step 2: ELO layer
- Maintain team ratings updated after each match
- Compute expected score from rating difference
- Convert to 1X2 probabilities via calibration
- Output: P(Home), P(Draw), P(Away)
Step 3: Weighted ensemble
P_ensemble(Home) = w × P_poisson(Home) + (1−w) × P_elo(Home)
P_ensemble(Draw) = w × P_poisson(Draw) + (1−w) × P_elo(Draw)
P_ensemble(Away) = w × P_poisson(Away) + (1−w) × P_elo(Away)
- Weight w tuned via walk-forward validation (typically 0.4–0.7)
- Normalize outputs to sum to 1.0
Worked Example¶
Man City (ELO1850) vs Arsenal (ELO 1820), home advantage = 65
ELO layer:
E_home = 1 / (1 + 10^(−(1850−1820−65)/400)) = 0.558
P_elo = {home: 0.558, draw: 0.24, away: 0.202}
Poisson layer (λ_home=1.84, λ_away=1.62):
P_poisson = {home: 0.580, draw: 0.240, away: 0.180}
Ensemble (w=0.6):
P = {home: 0.6×0.580 + 0.4×0.558 = 0.571, draw: 0.6×0.240 + 0.4×0.240 = 0.240, away: 0.6×0.180 + 0.4×0.202 = 0.189}
Code Snippet¶
import numpy as np
from scipy.stats import poisson
def poisson_elo_ensemble(home_team, away_team, poisson_probs, elo_probs, weight=0.6):
"""Combine Poisson and ELO probability outputs."""
ensemble = {
"home": weight * poisson_probs["home"] + (1 - weight) * elo_probs["home"],
"draw": weight * poisson_probs["draw"] + (1 - weight) * elo_probs["draw"],
"away": weight * poisson_probs["away"] + (1 - weight) * elo_probs["away"],
}
total = sum(ensemble.values())
for k in ensemble:
ensemble[k] /= total
return ensemble
def optimize_weight(validation_matches, poisson_model, elo_model):
"""Walk-forward weight optimization."""
best_weight, best_score = 0.5, float("inf")
for w in np.arange(0, 1.05, 0.05):
logloss_sum = 0
for home, away, result in validation_matches:
p_poisson = poisson_model.predict(home, away)
p_elo = elo_model.predict(home, away)
p_ensemble = poisson_elo_ensemble(home, away, p_poisson, p_elo, w)
if result == "home": logloss_sum -= np.log(p_ensemble["home"])
elif result == "draw": logloss_sum -= np.log(p_ensemble["draw"])
else: logloss_sum -= np.log(p_ensemble["away"])
if logloss_sum < best_score:
best_score, best_weight = logloss_sum, w
return best_weight
Pitfalls¶
- Weight optimization on small samples: World Cup (64 matches) is too small to reliably optimize ensemble weights. Borrow weights from league-level optimization.
- Both models need calibration: Raw outputs from Poisson and ELO are typically overconfident. Calibrate before ensembling.
- Dixon-Coles enhancement: Apply DC correction to Poisson λ to account for low-scoring draw underestimation.
- Stale ELO: ELO ratings need regular updates. Stale ELO produces worse predictions.
See Also¶
- poisson-distribution — base Poisson model
- elo-rating-system — ELO model
- dixon-coles-correction — DC correction for Poisson
- expected-goals-xg — xG provides better λ estimates for Poisson