Football Match Result Predictor
A PyTorch MLP classifier that predicts the outcome of international football matches: Away Win, Draw, or Home Win.
Model Details
| Field | Value |
|---|---|
| Author | Venus3009 |
| Framework | PyTorch |
| Task | Multi-class classification (3 classes) |
| Test Accuracy | 55.77% |
| Majority-class baseline | 49.0% |
| Random baseline | 33.3% |
Dataset
International football results 1872β2026
- 49,071 international matches
- Date range: 1872-11-30 β 2026-01-26
- Source: Kaggle (martj42)
Architecture
Input (11) β Linear(256) β BatchNorm β ReLU β Dropout(0.3)
β Linear(128) β BatchNorm β ReLU β Dropout(0.2)
β Linear(64) β ReLU
β Linear(3) β Softmax
- Parameters: 45,187
- Optimizer: Adam (lr=1e-3, weight_decay=1e-4)
- Loss: CrossEntropyLoss
- Scheduler: ReduceLROnPlateau (patience=3)
- Epochs: 30
Features (11 total)
| Feature | Description |
|---|---|
home_enc |
Label-encoded home team name |
away_enc |
Label-encoded away team name |
tour_enc |
Label-encoded tournament name |
neutral_n |
1 if played at a neutral venue, 0 otherwise |
year |
Match year (captures long-term team evolution) |
home_winrate |
Home team win rate over last 20 games |
home_gf |
Home team avg goals scored over last 20 games |
home_ga |
Home team avg goals conceded over last 20 games |
away_winrate |
Away team win rate over last 20 games |
away_gf |
Away team avg goals scored over last 20 games |
away_ga |
Away team avg goals conceded over last 20 games |
All features are normalized with StandardScaler before training.
Output Classes
| Index | Label | Meaning |
|---|---|---|
| 0 | Away Win | Away team wins |
| 1 | Draw | Match ends in a draw |
| 2 | Home Win | Home team wins |
Usage
import torch
import torch.nn as nn
import numpy as np
from sklearn.preprocessing import StandardScaler
class FootballPredictor(nn.Module):
def __init__(self, n_features=11):
super().__init__()
self.net = nn.Sequential(
nn.Linear(n_features, 256), nn.BatchNorm1d(256), nn.ReLU(), nn.Dropout(0.3),
nn.Linear(256, 128), nn.BatchNorm1d(128), nn.ReLU(), nn.Dropout(0.2),
nn.Linear(128, 64), nn.ReLU(),
nn.Linear(64, 3)
)
def forward(self, x):
return self.net(x)
# Load model
model = FootballPredictor()
model.load_state_dict(torch.load('football_predictor.pth', map_location='cpu'))
model.eval()
def predict_match(features_scaled):
"""
features_scaled: numpy array of shape (1, 11), already StandardScaler-transformed.
Returns predicted class and probabilities.
"""
with torch.no_grad():
x = torch.tensor(features_scaled, dtype=torch.float32)
probs = torch.softmax(model(x), dim=1)[0].numpy()
labels = ['Away Win', 'Draw', 'Home Win']
for label, prob in zip(labels, probs):
print(f" {label:<12} {prob*100:.1f}%")
print(f" β Prediction: {labels[probs.argmax()]}")
Training Split
- Method: Temporal (chronological order preserved β no random shuffle)
- Train: first 80% of matches (up to ~2019)
- Test: last 20% of matches (2019β2026)
Temporal splitting is critical here: a random split would leak future matches into training and inflate accuracy.
Limitations
- No player-level data (injuries, suspensions, squad strength)
- No ELO / FIFA ranking features
- Team encodings are static β the same team in 1950 and 2026 is treated identically
- Class imbalance (~49% home wins) is not corrected during training
Inference Providers NEW
This model isn't deployed by any Inference Provider. π Ask for provider support