Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Data
data/results.csv

# Models
models/*.pkl

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db
57 changes: 57 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# International Football Match Result Prediction

This project uses machine learning to predict the results of international football matches based on historical data from 1872 to 2017.

## Dataset
Source: [International Football Results (1872-2017)](https://www.kaggle.com/datasets/martj42/international-football-results-from-1872-to-2017)

## Project Structure
```
├── data/
│ └── results.csv # Kaggle dataset
├── models/
│ └── football_model.pkl # Trained model
├── src/
│ ├── data_processor.py # Data loading and preprocessing
│ ├── feature_engineer.py # Feature engineering
│ ├── model_trainer.py # Model training and evaluation
│ └── predictor.py # Make predictions
├── main.py # Main execution script
├── requirements.txt # Python dependencies
└── README.md # This file
```

## Installation

1. Clone the repository
2. Install dependencies:
```bash
pip install -r requirements.txt
```

3. Download the dataset from Kaggle and place `results.csv` in the `data/` folder

## Usage

### Train the Model
```bash
python main.py --train
```

### Make Predictions
```bash
python main.py --predict
```

## Model Details

- **Algorithm**: XGBoost Classifier
- **Features**: Team strength metrics, historical win rates, home/away advantage
- **Target**: Match outcome (Home Win, Draw, Away Win)

## Performance

The model achieves competitive accuracy on international match predictions by learning from over 140 years of football history.

## Author
Created by: ashigup14
112 changes: 112 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/usr/bin/env python
"""Main script for training and running football match predictions."""

import argparse
import os
from src.data_processor import DataProcessor
from src.feature_engineer import FeatureEngineer
from src.model_trainer import ModelTrainer
from src.predictor import FootballPredictor


def train_model():
"""Train the football prediction model."""
print("\n=== Starting Training Pipeline ===")

# Load and process data
print("\n1. Loading and processing data...")
processor = DataProcessor('data/results.csv')
processor.process_data()
train_df, test_df = processor.get_train_test_split(test_size=0.2)

# Engineer features
print("\n2. Engineering features...")
engineer = FeatureEngineer(train_df, test_df)
X_train, y_train, X_test, y_test = engineer.engineer_features()

# Train model
print("\n3. Training model...")
trainer = ModelTrainer()
trainer.train(X_train, y_train)

# Evaluate model
print("\n4. Evaluating model...")
trainer.evaluate(X_test, y_test)

# Feature importance
print("\n5. Feature importance...")
feature_names = engineer.get_feature_names()
trainer.get_feature_importance(feature_names)

# Save model
print("\n6. Saving model...")
trainer.save_model()

print("\n=== Training Complete ===")


def make_predictions():
"""Make predictions using trained model."""
print("\n=== Making Predictions ===")

# Check if model exists
if not os.path.exists('models/football_model.pkl'):
print("Error: Trained model not found. Please train the model first using --train")
return

# Load predictor
predictor = FootballPredictor()

# Example predictions
print("\nExample match predictions:")
print("-" * 50)

# Create sample feature vectors (in practice, these would come from new matches)
# Features: [home_strength, away_strength, home_form, away_form, h2h_hw, h2h_aw, h2h_draws, neutral]
sample_matches = [
([0.55, 0.48, 0.50, 0.45, 3, 2, 1, 0], 'Team A', 'Team B'),
([0.60, 0.50, 0.60, 0.40, 2, 3, 2, 0], 'Team C', 'Team D'),
([0.50, 0.50, 0.50, 0.50, 1, 1, 2, 1], 'Team E', 'Team F'),
]

for features, home_team, away_team in sample_matches:
import numpy as np
result = predictor.predict_with_teams(home_team, away_team, np.array(features))
print(f"\n{home_team} vs {away_team}")
print(f" Prediction: {result['prediction']}")
print(f" Confidence: {result['confidence']:.2%}")
print(f" Probabilities:")
print(f" - Home Win: {result['probabilities']['home_win']:.2%}")
print(f" - Draw: {result['probabilities']['draw']:.2%}")
print(f" - Away Win: {result['probabilities']['away_win']:.2%}")

print("\n=== Predictions Complete ===")


def main():
"""Main entry point."""
parser = argparse.ArgumentParser(description='Football Match Prediction Model')
parser.add_argument('--train', action='store_true', help='Train the model')
parser.add_argument('--predict', action='store_true', help='Make predictions')

args = parser.parse_args()

if args.train:
train_model()
elif args.predict:
make_predictions()
else:
print("Football Match Prediction Model")
print("\nUsage:")
print(" python main.py --train Train the model")
print(" python main.py --predict Make predictions")
print("\nSetup:")
print(" 1. pip install -r requirements.txt")
print(" 2. Download results.csv from Kaggle")
print(" 3. Place in data/ folder")
print(" 4. python main.py --train")
print(" 5. python main.py --predict")


if __name__ == '__main__':
main()
7 changes: 7 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pandas==1.5.3
numpy==1.24.3
scikit-learn==1.2.2
xgboost==1.7.5
matplotlib==3.7.1
seaborn==0.12.2
joblib==1.2.0
1 change: 1 addition & 0 deletions src/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Football Match Prediction Package"""
151 changes: 151 additions & 0 deletions src/data_processor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
"""Data loading and preprocessing module for football match data."""

import pandas as pd
import numpy as np
from typing import Tuple, Dict
import os


class DataProcessor:
"""Handle loading and preprocessing of football match data."""

def __init__(self, data_path: str = 'data/results.csv'):
"""Initialize DataProcessor with data path.

Args:
data_path: Path to the results.csv file from Kaggle
"""
self.data_path = data_path
self.df = None
self.processed_df = None

def load_data(self) -> pd.DataFrame:
"""Load football match data from CSV.

Returns:
DataFrame with match data
"""
if not os.path.exists(self.data_path):
raise FileNotFoundError(f"Data file not found at {self.data_path}")

self.df = pd.read_csv(self.data_path)
print(f"Loaded {len(self.df)} matches")
print(f"Columns: {list(self.df.columns)}")
return self.df

def create_match_outcome(self) -> pd.DataFrame:
"""Create target variable for match outcome.

Target classes:
- 0: Home team wins
- 1: Draw
- 2: Away team wins
"""
def determine_outcome(home_goals, away_goals):
if home_goals > away_goals:
return 0 # Home win
elif home_goals == away_goals:
return 1 # Draw
else:
return 2 # Away win

self.df['outcome'] = self.df.apply(
lambda row: determine_outcome(row['home_score'], row['away_score']),
axis=1
)
return self.df

def handle_missing_values(self) -> pd.DataFrame:
"""Handle missing values in the dataset."""
# Drop rows with missing critical values
self.df = self.df.dropna(subset=['home_team', 'away_team', 'home_score', 'away_score'])

# Fill neutral venue with False if missing
self.df['neutral'] = self.df['neutral'].fillna(False)

print(f"Data shape after handling missing values: {self.df.shape}")
return self.df

def convert_date_column(self) -> pd.DataFrame:
"""Convert date column to datetime."""
self.df['date'] = pd.to_datetime(self.df['date'])
return self.df

def process_data(self) -> pd.DataFrame:
"""Execute full preprocessing pipeline.

Returns:
Processed DataFrame
"""
self.load_data()
self.convert_date_column()
self.handle_missing_values()
self.create_match_outcome()
self.processed_df = self.df.copy()
return self.processed_df

def get_train_test_split(self, test_size: float = 0.2) -> Tuple[pd.DataFrame, pd.DataFrame]:
"""Split data into train and test sets based on time.

Args:
test_size: Proportion of data for testing

Returns:
Tuple of (train_df, test_df)
"""
if self.processed_df is None:
self.process_data()

# Sort by date
df_sorted = self.processed_df.sort_values('date').reset_index(drop=True)

# Time-based split
split_point = int(len(df_sorted) * (1 - test_size))
train_df = df_sorted[:split_point]
test_df = df_sorted[split_point:]

print(f"Train set: {len(train_df)} matches")
print(f"Test set: {len(test_df)} matches")

return train_df, test_df

def get_team_stats(self, df: pd.DataFrame, team: str) -> Dict:
"""Calculate team statistics.

Args:
df: DataFrame to calculate stats from
team: Team name

Returns:
Dictionary with team statistics
"""
home_matches = df[df['home_team'] == team]
away_matches = df[df['away_team'] == team]

# Home stats
home_wins = len(home_matches[home_matches['outcome'] == 0])
home_draws = len(home_matches[home_matches['outcome'] == 1])
home_losses = len(home_matches[home_matches['outcome'] == 2])
home_gf = home_matches['home_score'].sum()
home_ga = home_matches['away_score'].sum()

# Away stats
away_wins = len(away_matches[away_matches['outcome'] == 2])
away_draws = len(away_matches[away_matches['outcome'] == 1])
away_losses = len(away_matches[away_matches['outcome'] == 0])
away_gf = away_matches['away_score'].sum()
away_ga = away_matches['home_score'].sum()

total_matches = home_matches.shape[0] + away_matches.shape[0]

return {
'team': team,
'total_matches': total_matches,
'home_wins': home_wins,
'away_wins': away_wins,
'draws': home_draws + away_draws,
'total_wins': home_wins + away_wins,
'goals_for': home_gf + away_gf,
'goals_against': home_ga + away_ga,
'goal_difference': (home_gf + away_gf) - (home_ga + away_ga)
}
Loading