League of Legends Winrate Prediction Model
By Eldar · Published July 17, 2026
Predicts match outcomes using pre-game features like player skill and champion winrates, achieving 75.2% accuracy and revealing that player skill, not team composition, drives victory.
- league-of-legends
- classification
- predictive-modeling
- sports-analytics
- feature-engineering
Inside this notebook
# League of Legends Winrate Analysis & Winner Prediction Model **Dataset:** Season 15 Ranked Match Data — 6,830 games (EUN server, all ranks Iron–Challenger) **Source:** Kaggle — `jakubkrasuski/league-of-legends-ranked-match-data-season-15` ## Key Findings ### 🏆 Best Model: Logistic Regression - **Accuracy:** 75.2% (beats 51.9% blue-side baseline by +23.3%) - **ROC-AUC:** 81.9% - Uses 33 pre-game features: champion winrates per role, solo tier/rank, mastery points ### 🔬 Critical Insight: Champions ≠ Outcome A model using **only champion picks** (no player skill features) scored **48.5% accuracy** — worse than random. The full model's ~75% accuracy is almost entirely driven by **player skill differentials**, not team composition. This validates what high-elo players know: in a well-patched game, player skill trumps champion selection. ### 📊 Top Predictors | Feature | Importance | |---|---| | `tier_advantage` (blue team avg tier − red team avg tier) | 26.2% | | `wr_diff_avg` (avg champion winrate advantage) | 12.8% | | `teamA_avg_solo_rank` / `teamB_avg_solo_rank` | ~10% each | ### 🟦 Blue Side Advantage Blue side wins **51.9%** of games — a small but consistent edge (~1.9%). ### 📈 Strongest Champions (Season 15 EUN) | Champion | Win Rate | Games | |---|---|---| | Ivern | 62.4% | 93 | | Vex | 59.3% | 177 | | Nunu | 58.0% | 343 | | Kog'Maw | 58.0% | 300 | | Amumu | 56.8% | 570 |
# Setup: imports and data loading
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.metrics import (classification_report, confusion_matrix, roc_auc_score,
roc_curve, accuracy_score, precision_recall_curve, f1_score)
import warnings
warnings.filterwarnings('ignore')
plt.rcParams['figure.dpi'] = 120
plt.rcParams['figure.facecolor'] = 'white'
# Load enriched match data
…Loaded 6,830 matches, 65 columns
Target distribution: {1: 3543, 0: 3287}
Target mean (blue side winrate): 0.519# Download League of Legends Challenger Ranked Games dataset from Kaggle
%pip install kagglehub -q
import kagglehub
import pandas as pd
import os
# Download latest version of the dataset
path = kagglehub.dataset_download("gyejr95/league-of-legends-challenger-ranked-games2020")
print(f"Dataset downloaded to: {path}")
print(f"Files: {os.listdir(path)}")Note: you may need to restart the kernel to use updated packages. Downloading to /root/.cache/kagglehub/datasets/gyejr95/league-of-legends-challenger-ranked-games2020/3.archive... Extracting files... Dataset downloaded to: /root/.cache/kagglehub/datasets/gyejr95/league-of-legends-challenger-ranked-games2020/versions/3 Files: ['Challenger_Ranked_Games.csv', 'GrandMaster_Ranked_Games.csv', 'Master_Ranked_Games.csv']
# Explore the dataset structure
import pandas as pd
import os
base = "/root/.cache/kagglehub/datasets/gyejr95/league-of-legends-challenger-ranked-games2020/versions/3"
for fname in ['Challenger_Ranked_Games.csv', 'GrandMaster_Ranked_Games.csv', 'Master_Ranked_Games.csv']:
path = os.path.join(base, fname)
df = pd.read_csv(path, nrows=1)
print(f"\n{'='*70}")
print(f"FILE: {fname} ({os.path.getsize(path) / 1e6:.1f} MB)")
print(f"COLUMNS ({len(df.columns)}):")
for c in df.columns:
print(f" • {c}")
# Also get row count quickly
import subprocess
result = subprocess.run(['wc', '-l', path], capture_output=True, text=True)
rows = int(result.stdout.strip().split()[0]) - 1 # subtract header
…====================================================================== FILE: Challenger_Ranked_Games.csv (4.5 MB) COLUMNS (50): • gameId • gameDuraton • blueWins • blueFirstBlood • blueFirstTower • blueFirstBaron • blueFirstDragon • blueFirstInhibitor • blueDragonKills • blueBaronKills • blueTowerKills • blueInhibitorKills • blueWardPlaced • blueWardkills • blueKills • blueDeath • blueAssist • blueChampionDamageDealt • blueTotalGold • blueTotalMinionKills…
# Try downloading the season 15 match dataset and the diamond games dataset
%pip install kagglehub -q
import kagglehub
import os
# Check dataset structures first
for ds_name in [
"jakubkrasuski/league-of-legends-ranked-match-data-season-15",
"benfattori/league-of-legends-diamond-games-first-15-minutes",
"jakejoeanderson/league-of-legends-diamond-matches-ff15"
]:
try:
path = kagglehub.dataset_download(ds_name)
files = os.listdir(path)
print(f"\n=== {ds_name} ===")
print(f"Path: {path}")
for f in files:
fpath = os.path.join(path, f)
…Note: you may need to restart the kernel to use updated packages. Downloading to /root/.cache/kagglehub/datasets/jakubkrasuski/league-of-legends-ranked-match-data-season-15/1.archive... Extracting files... === jakubkrasuski/league-of-legends-ranked-match-data-season-15 === Path: /root/.cache/kagglehub/datasets/jakubkrasuski/league-of-legends-ranked-match-data-season-15/versions/1 League of Legends Ranked Match Data Season 15 (EUN).csv (31.1 MB) Downloading to /root/.cache/kagglehub/datasets/…
# Explore columns of all datasets
import pandas as pd
import os
datasets = {
"Season 15 (EUN)": "/root/.cache/kagglehub/datasets/jakubkrasuski/league-of-legends-ranked-match-data-season-15/versions/1/League of Legends Ranked Match Data Season 15 (EUN).csv",
"Diamond First15": "/root/.cache/kagglehub/datasets/benfattori/league-of-legends-diamond-games-first-15-minutes/versions/1/MatchTimelinesFirst15.csv",
"Diamond FF15": "/root/.cache/kagglehub/datasets/jakejoeanderson/league-of-legends-diamond-matches-ff15/versions/4/LoL_15_Diamond.csv",
}
for name, path in datasets.items():
df = pd.read_csv(path, nrows=1)
print(f"\n{'='*70}")
print(f"DATASET: {name}")
print(f"COLUMNS ({len(df.columns)}):")
for c in df.columns:
print(f" • {c}")====================================================================== DATASET: Season 15 (EUN) COLUMNS (69): • game_id • start_utc • duration • queue • platform_id • map_id • game_mode • game_version • participant_id • champion_id • champion_name • position • win • kills • deaths • assists • kda_ratio • kill_participation • gold_earned • gold_spent • gold_per_min • damage_dealt • damage_per_min • damage_to_champ • damage_champ_per_min • damage…
# Load the Season 15 dataset - perfect for team comp prediction!
import pandas as pd
import numpy as np
import os
path = "/root/.cache/kagglehub/datasets/jakubkrasuski/league-of-legends-ranked-match-data-season-15/versions/1/League of Legends Ranked Match Data Season 15 (EUN).csv"
df = pd.read_csv(path)
print(f"Shape: {df.shape}")
print(f"Dtypes:\n{df.dtypes.value_counts()}")
print(f"\nChampions: {df['champion_name'].nunique()}")
print(f"Positions: {df['position'].value_counts().to_dict()}")
print(f"Unique games: {df['game_id'].nunique()}")
print(f"\nWin distribution:\n{df['win'].value_counts()}")
print(f"\nSample rows (first 3):")
df.head(3)This is a preview. Open the live notebook to see all 29 cells with their charts and full outputs, or fork it into your own Clusy workspace.