Building end-to-end decision systems for football: from data to actionable insights under real-world constraints.
A production-style football forecasting system combining machine learning match prediction with Monte Carlo tournament simulation to estimate advancement and championship probabilities for international tournaments.
Inspired by forecasting methodologies used by FiveThirtyEight, Opta, and professional sports analytics teams.
This project builds a probabilistic forecasting engine for international football tournaments.
| Metric | Value |
|---|---|
| Historical matches | ~31,000 |
| Model | Multiclass Logistic Regression |
| Simulation scale | 10,000 β 100,000 tournaments |
| Tournament formats | 32 teams / 48 teams |
| Outputs | Advancement & champion probabilities |
| Interface | Interactive Streamlit dashboard |
The system simulates thousands of full tournaments to estimate probability distributions rather than deterministic predictions.
| Metric | Value |
|---|---|
| Model | Multiclass Logistic Regression (benchmark-validated baseline) |
| Dataset Size | ~31,000 international matches (1994β2024) |
| Probability Calibration | Temporal train/test split methodology |
| Simulation Scale | 10,000β100,000 Monte Carlo tournaments |
| Forecast Granularity | Stage-by-stage progression probabilities |
| Example Output | Spain: 88.8% group advance, 23.1% champion |
| Production Ready | End-to-end pipeline, modular architecture, artifacts export |
| Feature | Description |
|---|---|
| End-to-end pipeline | Data β modeling β simulation β reporting |
| Match prediction model | Probabilistic win/draw/loss predictions |
| Monte Carlo simulation | Large-scale tournament simulation |
| Modular architecture | Separate modeling, simulation, reporting |
| Reproducible outputs | Structured simulation artifacts |
| Interactive dashboard | Explore forecast probabilities |
| Research environment | Notebooks for experimentation & analysis |
| Component | Technology |
|---|---|
| Language | Python 3.8+ |
| Data Processing | pandas, numpy, scipy |
| Machine Learning | scikit-learn (Logistic Regression) |
| Simulation Engine | Custom probabilistic Monte Carlo |
| Data Formats | Parquet, CSV, JSON |
| Visualization | Streamlit, matplotlib/plotly, seaborn |
| Configuration | YAML (configs/) |
| Versioning | joblib (model persistence) |
- π Key Results & Performance
- π Tech Stack
- π Quick Start
- π§ Project Objective
- π₯ Demo & Screenshots
- π System Architecture
- β Tournament Simulation Flow
- π§ Component Responsibilities
- π Data Pipeline
- π€ Match Outcome Model
- π Model Evaluation & Validation
- π² Tournament Simulation Engine
- π Monte Carlo Forecasting
- π Example Forecast Output
- π Project Structure
- βΆ Running the Simulation
- π¦ Simulation Outputs
- π Dashboard
- π Docs & Reproducibility
- π₯ Input/Output Specification
- π Notebooks & Analysis
- β FAQ
- β Current Limitations
- π For Recruiters & Data Scientists
- π Future Improvements
- π― Why This Project
- π€ Author
- π License
git clone https://github.com/yourusername/world-cup-2026-forecast.git
cd world-cup-2026-forecastpython -m venv venv
source venv/bin/activate
pip install -r requirements.txtpython -m src.simulation.run_simulation --num-simulations 1000streamlit run app/streamlit_app.pyEstimate the probability that each national team:
| Stage |
|---|
| Advances from the group stage |
| Reaches Round of 16 |
| Reaches Quarterfinals |
| Reaches Semifinals |
| Reaches Final |
| Wins the tournament |
This is achieved by simulating thousands of full tournaments using a trained match prediction model.
Figures generated from simulation analysis notebooks.
flowchart LR
A[Historical Match Data] --> B[Feature Engineering]
B --> C[Team Strength Features]
C --> D[Match Outcome Model]
D --> E[Match Prediction API]
E --> F[Monte Carlo Simulation Engine]
F --> G[Simulated Tournaments]
G --> H[Aggregation Layer]
H --> I[Forecast Outputs]
The system separates data processing, predictive modeling, simulation, and reporting layers.
flowchart TD
A[Load Team Strength Snapshot] --> B[Initialize Tournament]
B --> C[Simulate Group Matches]
C --> D[Generate Group Tables]
D --> E[Select Qualified Teams]
E --> F[Simulate Knockout Bracket]
F --> G[Champion]
G --> H[Store Result]
H --> I{More Simulations?}
I -->|Yes| B
I -->|No| J[Aggregate Statistics]
| Component | Responsibility |
|---|---|
| Data ingestion | Load historical match data |
| Feature engineering | Build team strength features |
| Match outcome model | Predict win/draw/loss probabilities |
| Simulation engine | Simulate tournaments |
| Aggregation layer | Compute advancement probabilities |
| Reporting layer | Export artifacts |
| Dashboard | Interactive exploration of forecasts |
Historical international match data is transformed into team strength features.
Key features include:
| Feature Type | Examples |
|---|---|
| Rating metrics | Dynamic Elo rating system computed from historical matches |
| Performance metrics | Rolling goals scored/conceded |
| Form metrics | Rolling win rate |
Stored snapshot:
data/processed/latest_team_features.parquet
The model predicts probabilities for:
| Outcome |
|---|
| Win |
| Draw |
| Loss |
Baseline model:
Multiclass Logistic Regression
Input features include Elo differences and rolling team performance metrics.
The model was evaluated using a temporal train/test split approach to avoid data leakage and reflect real-world forecasting conditions.
| Metric | Purpose |
|---|---|
| Log Loss | Quality of probability estimates |
| Accuracy | Correct outcome prediction |
| Brier Score | Calibration of probabilities |
- Baseline Model: Multiclass Logistic Regression
- Training Data: ~31,000 historical international matches
- Features: Elo ratings, rolling performance metrics, goal differential
- Output: Probability distributions for win/draw/loss
The logistic regression model serves as a baseline probabilistic predictor for the simulation engine. Model predictions feed directly into Monte Carlo simulations, making calibration quality critical.
Additional experiments evaluated probability calibration using
CalibratedClassifierCV. The calibrated model did not improve log loss
or Brier score compared to the baseline Logistic Regression model,
indicating that the original model already provides well-calibrated
probability estimates for this dataset.
The match prediction model was selected after evaluating multiple candidate approaches using probabilistic forecasting metrics.
See:
experiments/05_match_model_benchmark.ipynb
docs/modeling.md
Simulation logic:
flowchart TD
A["predict_match(team_a, team_b)"] --> B["probability distribution"]
B --> C["sample match outcome"]
C --> D["simulate tournament"]
D --> E["repeat N times"]
Each run produces:
- group standings
- knockout progression
- finalists
- champion
The 2026 World Cup format (48 teams, 12 groups) introduces a non-trivial knockout structure due to the inclusion of best third-placed teams.
This project implements a deterministic and balanced approximation of the official FIFA bracket:
- 8 group winners face the 8 best third-placed teams
- 4 group winners face 4 runners-up
- Remaining runners-up play against each other
- Winner-vs-winner matchups are avoided in the Round of 32
This design ensures:
- Competitive fairness (top teams are not eliminated early)
- Structural consistency across simulations
- Reproducibility of results
Instead of enumerating all possible FIFA combinations (495 scenarios), the system uses a deterministic simplified mapping strategy.
When required, third-placed teams are assigned to knockout slots using a consistent fallback rule based on ranking and group identifiers.
This trade-off prioritizes:
- Simulation stability
- Code simplicity
- Portfolio clarity
over exact replication of FIFAβs full mapping table.
Typical simulations:
10,000 β 100,000 tournaments
Aggregating thousands of simulations produces robust probability estimates.
Example probabilities from simulation results:
| Team | Advance Group | Semifinal | Final | Champion |
|---|---|---|---|---|
| Spain | 88.8% | 33.4% | 23.1% | 23.1% |
| Argentina | 88.5% | 30.7% | 20.8% | 20.8% |
| France | 85.2% | 26.9% | 15.6% | 9.4% |
world-cup-2026-forecast
β
βββ app/ # Streamlit dashboard
βββ configs/ # Tournament configuration files
βββ data/ # Datasets and simulation outputs
βββ docs/ # Technical documentation
βββ experiments/ # Modeling experiments
βββ notebooks/ # Analysis notebooks
βββ src/ # Forecasting pipeline
βββ tests/ # Unit testspy -m src.simulation.run_simulation --groups-path configs/world_cup_groups.json --num-simulations 10000py -m src.simulation.run_simulation --groups-path configs/world_cup_groups_48.json --bracket-config-path configs/world_cup_2026_bracket.json --simulation-format v2 --num-simulations 10000Generated artifacts:
| File | Description |
|---|---|
| team_probabilities.csv | Advancement probabilities |
| champion_distribution.csv | Champion distribution |
| match_logs.parquet | Simulated match logs |
| summary_metadata.json | Simulation metadata |
Saved in:
data/outputs/simulation
Interactive dashboard built with Streamlit.
Run:
streamlit run app/streamlit_app.pyDashboard capabilities:
- Champion probability rankings
- Team advancement probabilities
- Team comparison tools
- Simulation charts
Detailed documentation available in docs/:
| Document | Description |
|---|---|
| architecture.md | System architecture |
| engineering.md | Engineering decisions |
| modeling.md | Modeling methodology |
| project_status.md | Project roadmap |
{
"team": "Spain",
"elo_rating": 2150,
"rolling_goals_scored": 2.4,
"rolling_goals_conceded": 1.1,
"rolling_win_rate": 0.65,
"rolling_points": 2.0
}Source: data/processed/latest_team_features.parquet
teams: ["Spain", "Argentina", "France", ...]
groups:
A: ["Spain", "Germany", "Japan", ...]
B: ["Argentina", "Mexico", "Poland", ...]team,advance_from_group,round_of_16,quarterfinal,semifinal,final,champion
Spain,0.888,0.723,0.534,0.334,0.231,0.231
Argentina,0.885,0.718,0.512,0.307,0.208,0.208Frequency distribution of tournament winners across all simulations.
{
"num_simulations": 10000,
"tournament_format": "48-team",
"model": "logistic_regression",
"timestamp": "2026-03-16T10:30:00Z"
}Explore the analysis without cloning the repository:
| Notebook | Purpose | Contents |
|---|---|---|
| 00_eda_match_dataset.ipynb | Exploratory Data Analysis | Match statistics, historical trends |
| 01_match_model_experiments.ipynb | Model Experimentation | Feature importance, model comparison |
| 02_simulation_analysis.ipynb | Simulation Results Analysis | Probability distributions, team insights |
| 03_world_cup_forecast_story.ipynb | Forecast Narrative | Tournament predictions, storytelling |
| 05_match_model_benchmark.ipynb | Model Benchmarking | Probabilistic model comparison, calibration analysis, baseline evaluation |
Q: Why Logistic Regression instead of XGBoost or Deep Learning? A: Logistic Regression provides:
- Interpretable probability estimates (crucial for calibration)
- Fast inference (enables large-scale simulation)
- Proven baseline for match prediction
- Foundation for future ensemble approaches
Q: How is the model calibrated? A: Using temporal train/test split (chronological data split) with evaluation metrics:
- Log Loss: Measures probability quality
- Brier Score: Assesses prediction accuracy
- Historical backtesting on past tournaments
Q: Can I use my own team features?
A: Yes. Modify src/features/build_latest_team_features.py to:
- Add custom feature calculations
- Update feature engineering pipeline
- Re-run simulations with new features
Q: How long does a simulation take? A: On a standard machine:
- 1,000 tournaments: ~2 seconds
- 10,000 tournaments: ~20 seconds
- 100,000 tournaments: ~3 minutes
Q: What tournament formats are supported? A:
- v1: Classic 32-team format (8 groups, Round of 16)
- v2: World Cup 2026 format (12 groups, Round of 32)
Modify using --simulation-format parameter.
Q: Can I change the number of group matches or knockouts?
A: Yes. Edit src/simulation/tournament.py or configs/simulation.yaml to adjust tournament rules.
Q: What's the historical date range of the data? A: Matches from 1994β2024 (~31,000 international matches).
Q: How do I reproduce exact results? A: Ensure:
- Same Python version (3.8+)
- Same
requirements.txtversions - Set random seed in simulation config
| Area | Limitation |
|---|---|
| Score simulation | No explicit goal model |
| Tie-breakers | Simplified group ranking |
| Knockout resolution | Simplified logic |
| Team strength | Static ratings during tournament |
| Knockout bracket (48 teams) | Uses a deterministic approximation instead of full FIFA mapping (495 combinations) |
- Poisson goal model
- Advanced probability calibration techniques
- Ensemble models
- Full FIFA tie-breaker rules
- Improved bracket modeling
- Enhanced dashboard visualizations
- Scenario comparison tools
- Multiclass classification with probability calibration
- Temporal train/test split and proper validation methodology
- Feature engineering from domain-specific data
- Model baseline establishment and improvement planning
- End-to-end data processing pipeline (ingestion β transformation β modeling)
- Modular architecture with clear separation of concerns
- Structured artifact generation and export
- Reproducible results with seed management and version control
- Monte Carlo simulation engine design and implementation
- Tournament logic modeling (group stage, knockouts, qualification rules)
- Large-scale simulation execution (10kβ100k runs)
- Probability aggregation and uncertainty quantification
- Production-ready code organization
- Configuration management (YAML-based tournament configs)
- Comprehensive documentation
- Modular design enabling experimentation
- International football tournament mechanics
- Team strength metrics (Elo, rolling performance)
- Probabilistic match outcome prediction
- Tournament format handling (32-team classic, 48-team modern)
This project demonstrates the ability to go beyond modeling and build complete forecasting systems that:
- Combine ML predictions with domain logic
- Scale computationally for large simulations
- Produce actionable, interpretable outputs
- Maintain code quality and reproducibility
This project demonstrates skills relevant to sports analytics and forecasting roles:
- machine learning for sports prediction
- probabilistic forecasting
- tournament simulation systems
- scalable data pipelines
- analytical storytelling
Manuel PΓ©rez BaΓ±uls
Data Scientist | Football Analytics Enthusiast | Probabilistic Modeling
Specializing in:
- Sports analytics and forecasting
- Probabilistic simulation systems
- Machine learning for football prediction
- Production-ready data pipelines
Connect & Collaborate:
- π§ Email: manuelpeba@gmail.com
Interested in discussing sports analytics, forecasting systems, or data-driven decision-making? Feel free to reach out!
MIT License


