La Liga Score Predictor Model Card
Scope
This document describes the public La Liga Score Predictor model.
Included:
- model architecture
- feature families
- inference behavior
- output schema
- evaluation approach
Excluded on purpose:
- other internal model variants
- source-provider specific ingestion details
- private infrastructure
Model Summary
- Model version:
la_liga_score_predictor - Public package version:
2026.04.1 - Model type:
catboost_two_stage - Task: pre-match football score prediction
- Competition scope: Spanish La Liga only
- Primary outputs:
- expected home goals
- expected away goals
- predicted score
- home/draw/away probabilities
- confidence level
- abstain / score-range signal for fragile matches
High-Level Architecture
The La Liga Score Predictor model is a two-stage CatBoost setup.
Stage 1:
- one CatBoost model predicts expected home goals
- one CatBoost model predicts expected away goals
Stage 2:
- one CatBoost model predicts match-outcome probabilities:
home_windrawaway_win
Final score decoding:
- score decode mode:
poisson_argmax - home Poisson scale:
1.10 - away Poisson scale:
1.05
Probability post-processing:
- temperature calibration:
0.93
Low-confidence handling:
- abstain mode enabled
- score-range output enabled for fragile matches
Competition Scope
This public release is intended only for Spanish La Liga fixtures.
It should not be treated as a validated model for other leagues without retraining or separate evaluation.
What the Model Learns From
The model is trained on structured pre-match football features only.
It does not need interactive conversation context, database access, or any auxiliary external signal outside the supported feature schema for public inference.
What This Public Package Does Not Include
This release does not include:
- a full production historical La Liga dataset
- a hosted or live data source
- a promise of reproducing a private/internal prediction environment exactly
The public package includes the model and the wrapper logic.
For predict_match(...), the caller must still supply compatible historical match data.
This public release should be treated as:
- a model-and-inference bundle
- not a bundled football data service
Feature Families
The current model artifact uses 48 numeric features.
1. Recent Scoring and Conceding
- recent average goals scored
- recent average goals conceded
- all-match context
- home-only or away-only context where appropriate
2. Recent Results Shape
- recent win rates
- recent draw rates
- recent goal-difference trends
3. Rest and Scheduling
- home rest days
- away rest days
4. Team Strength
- pre-match Elo values
- Elo difference
5. Team Identity Signals
- home team id
- away team id
6. Player Availability and Usage Aggregates
Aggregated over recent matches:
- minutes
- goals
- assists
- yellow cards
- red cards
- starter counts
- used-player counts
- injured-player counts
- suspended-player counts
7. Tactical and Staff Context
- home tactic id
- away tactic id
- home coach id
- away coach id
- tactic stability over recent matches
- tactic matchup encoding
Exact Feature Columns
The model artifact currently expects these exact feature columns:
home_avg_goals_last5_all
away_avg_goals_last5_all
home_avg_goals_last5_home
away_avg_goals_last5_away
home_avg_conceded_last5_all
away_avg_conceded_last5_all
home_avg_conceded_last5_home
away_avg_conceded_last5_away
home_win_rate_last10_all
away_win_rate_last10_all
home_win_rate_last10_home
away_win_rate_last10_away
home_draw_rate_last10
away_draw_rate_last10
home_goal_diff_last5
away_goal_diff_last5
home_rest_days
away_rest_days
home_elo_pre
away_elo_pre
elo_diff_pre
home_team_id
away_team_id
home_player_minutes_total_prev5
away_player_minutes_total_prev5
home_player_goals_total_prev5
away_player_goals_total_prev5
home_player_assists_total_prev5
away_player_assists_total_prev5
home_player_yellow_cards_total_prev5
away_player_yellow_cards_total_prev5
home_player_red_cards_total_prev5
away_player_red_cards_total_prev5
home_player_starters_count_prev5
away_player_starters_count_prev5
home_player_used_count_prev5
away_player_used_count_prev5
home_player_injured_count_prev5
away_player_injured_count_prev5
home_player_suspended_count_prev5
away_player_suspended_count_prev5
home_tactic_id
away_tactic_id
home_coach_id
away_coach_id
home_tactic_stability_last5
away_tactic_stability_last5
tactic_matchup_code
Inference Flow
Step 1: Validate Input
The predictor checks that every required feature exists and is numeric.
Step 2: Sanitize Identifier-Like Fields
The inference path stabilizes:
- team ids
- coach ids
- tactic ids
This avoids malformed id-like values distorting predictions.
Step 3: Predict Expected Goals
The home-goals and away-goals models produce expected goal values.
Step 4: Predict Outcome Probabilities
The outcome model produces:
- home-win probability
- draw probability
- away-win probability
Step 5: Apply Calibration
The probability distribution is temperature-calibrated.
Step 6: Decode Final Score
The model uses Poisson-based score decoding to choose the final scoreline.
Step 7: Compute Confidence
The response includes:
confidence_levelconfidence_scoreconfidence_margin
Step 8: Optional Abstain Signal
If the match is fragile enough:
abstain_recommended = true- a score range is returned
Reproducibility Note
This public release ships the same champion model artifact used by the public bundle, but exact outputs are still data-dependent.
In practice:
- same model + same feature row -> same prediction
- same model + different historical context -> potentially different prediction
That matters because predict_match(...) builds the feature row from historical input data before the model runs.
Output Schema
Typical output fields:
{
"model_version": "la_liga_score_predictor",
"model_type": "catboost_two_stage",
"expected_home_goals": 1.72,
"expected_away_goals": 0.94,
"predicted_home_goals": 2,
"predicted_away_goals": 1,
"predicted_score": "2-1",
"result_probabilities": {
"home_win": 0.54,
"draw": 0.25,
"away_win": 0.21
},
"confidence_level": "medium",
"confidence_score": 0.54,
"confidence_margin": 0.19,
"abstain_recommended": false
}
If abstain mode is triggered, output can also include:
{
"predicted_score_range": {
"home_min": 1,
"home_max": 3,
"away_min": 0,
"away_max": 2
}
}
Field Glossary
predicted_score- the final exact score chosen after expected-goal estimation, probability calibration, and score decoding
result_probabilities- calibrated
home_win,draw, andaway_winprobabilities
- calibrated
raw_result_probabilities- the outcome probabilities before calibration
expected_home_goals- expected goals estimate for the home team
expected_away_goals- expected goals estimate for the away team
confidence_level- coarse confidence label:
high,medium, orlow
- coarse confidence label:
confidence_score- the highest calibrated outcome probability
confidence_margin- the gap between the top and second-highest calibrated outcome probabilities
abstain_recommended- flag indicating that the match is fragile enough to soften exact-score trust
predicted_score_range- optional score band returned when abstain mode is triggered
top_outcome- the strongest calibrated outcome class in the decoder diagnostics
top_outcome_probability- the probability of that strongest outcome class
second_outcome_probability- the probability of the runner-up outcome class
draw_probability- the calibrated draw probability
xg_deltaexpected_home_goals - expected_away_goals- useful for understanding which side carries the stronger expected scoring edge
close_call_draw_override- indicates a draw-favoring tie-break in a tightly balanced fixture
outcome_enforced- indicates that the outcome model was confident enough to force score direction
specialist_rule_triggered- indicates that an internal score adjustment rule ran
specialist_rule_name- the name of the triggered rule, if any
Confidence Logic
The model exposes confidence for usability, not certainty.
Interpretation:
high: clearer distribution separationmedium: usable signal but not dominantlow: fragile match, higher variance, score-range matters more
This is why public docs should explain:
- prediction is guidance
- not a guarantee
Training and Selection Approach
The model was selected through offline evaluation and score-decoding guardrails.
Key ideas:
- no leakage from post-match information
- recent-window checks matter, not only full-history averages
- decode settings were selected to balance:
- exact score rate
- outcome accuracy
- total-goal error
From the current training report:
- selection method:
decode_sweep_no_retrain_recent_guardrails
Current report snapshot:
- full-history exact:
0.2056 - full-history outcome:
0.6177 - recent-window exact:
0.1535 - recent-window outcome:
0.5307
These numbers are artifact-era selection metrics, not a promise for future live windows.
Public Inference Requirements
For public use, inference needs only:
- the bundled model artifacts
- the three
.cbmfiles referenced by them - Python dependencies for CatBoost inference
- either:
- a compatible historical match CSV for
predict_match(...) - or one complete numeric feature row matching the required schema for
predict_features(...)
- a compatible historical match CSV for
It does not require:
- a live database
- a web server
- a scheduled pipeline
- any source-specific connector
Public Inference Interfaces
The public package exposes four main inference methods.
predict_match(home_team, away_team, match_date)
- builds features from a compatible historical match CSV
- best for normal application use
- returns the full response, including advanced fields and diagnostics
predict_match_simple(home_team, away_team, match_date)
- builds features from a compatible historical match CSV
- best for lighter product integrations
- returns the smaller public response shape
predict_features(features)
- expects the full numeric feature row
- best for advanced users managing engineered features directly
- returns the full response, including advanced fields and diagnostics
predict_features_simple(features)
- expects the full numeric feature row
- best for advanced users who want a smaller public response shape
Public Usage Example
The simplest public interface is:
from la_liga_score_predictor import LaLigaScorePredictor
predictor = LaLigaScorePredictor.from_defaults(
dataset_csv_path="sample_history.csv"
)
prediction = predictor.predict_match(
home_team="Athletic",
away_team="Osasuna",
match_date="2026-04-21",
)
simple_prediction = predictor.predict_match_simple(
home_team="Athletic",
away_team="Osasuna",
match_date="2026-04-21",
)
Where:
predict_match()is the easiest interface when you have a compatible history CSVpredict_match_simple()is the lighter product-facing variantpredict_features()is available for direct numeric feature rowspredict_features_simple()is the lighter direct-feature variant
Limitations
- The model is only as good as the input feature row.
- It is a pre-match model, not a live in-match model.
- It is league and feature-schema sensitive.
- It can miss chaotic or low-signal matches.
- Confidence is a helpful indicator, not certainty.
What We Intentionally Exclude From the Public Technical Story
- source-provider implementation details
- private ingestion and refresh mechanics
- other internal model variants and experiment history
That keeps the public story clear:
- one champion model
- one inference path
- one reproducible public artifact
Suggested Companion Files
This technical note works best alongside:
RELEASE_GUIDE.md- a public
README.md - a small
sample_history.csv - a simple
predict_one.py
Release Cadence Note
The public model artifact is planned to update twice per month.
For each public release, technical notes should be updated only if one of these changes:
- feature schema
- decode settings
- calibration behavior
- output contract
- artifact version