My aim in this project was to predict match outcomes in League of Legends by leveraging machine learning models trained on recent match data. By Riot Games' API to gather historical match data and apply KNN to analyze the win ratio with respect to team compositions and match results.
1. Importing Libraries and Configuring API
from riotwatcher import LolWatcher, ApiError
from itertools import permutations
from os import path
import numpy as np
import csv
import json
import requests
import pandas as pd
import time
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
API_TOKEN = '?api_key=' # Insert your API key here
HOST = 'https://tr1.api.riotgames.com/' # Server location, e.g., Turkey region
Required project imports of libraries for API requests, data handling, and machine learning. Pandas and NumPy manage data, while scikit-learn offer models and evaluation metrics for prediction. The API token and host are for enabling access to Riot Games' API to get historical match data.
2. LOLAPI Class - Managing API Interactions
class LOLAPI:
def __init__(self, username, host=HOST, token=API_TOKEN):
self.host = host
self.token = token
self.username = username
def get_encrypted_account_id(self):
url = f"{self.host}/lol/summoner/v4/summoners/by-name/{self.username}{self.token}"
response = requests.get(url).json()
return response['accountId']
def get_matches(self, account_id):
url = f"{self.host}/lol/match/v4/matchlists/by-account/{account_id}{self.token}"
return requests.get(url).json().get('matches', [])
def get_match_info(self, match_id):
url = f"{self.host}/lol/match/v4/matches/{match_id}{self.token}"
return requests.get(url).json()
def get_champions(self):
url = "http://ddragon.leagueoflegends.com/cdn/10.18.1/data/en_US/champion.json"
response = requests.get(url).json()
return {int(data['key']): champ for champ, data in response['data'].items()}
The LOLAPI class manages the interaction with the Riot Games API, providing methods to retrieve account IDs, match lists, individual match details, and champion information. The API calls are modularized to enable easy access and reuse.
3. MatchDataProcessor Class - Processing and Extracting Match Data
class MatchDataProcessor:
def __init__(self, api):
self.api = api
def process_match_data(self, match_data):
results, labels = [], []
matches = {match['gameId']: match['champion'] for match in match_data}
for counter, (match_id, champ_id) in enumerate(matches.items(), 1):
if counter % 10 == 0:
break
match_info = self.api.get_match_info(match_id)
if 'status' in match_info:
break
match_features, match_label = self.extract_match_features(match_info, champ_id)
if match_features:
results.append(match_features)
labels.append(match_label)
return results, labels
def extract_match_features(self, match_info, champion_id):
participant_data = {p['championId']: p for p in match_info['participants']}
team_id = participant_data[champion_id]['teamId']
win = participant_data[champion_id]['stats']['win']
ally_champs = [p['championId'] for p in match_info['participants'] if p['teamId'] == team_id and p['championId'] != champion_id]
enemy_team_id = (team_id % 200) + 100
enemy_champs = [p['championId'] for p in match_info['participants'] if p['teamId'] == enemy_team_id]
if all(champ == enemy_champs[0] for champ in enemy_champs):
enemy_champs = []
if ally_champs and enemy_champs:
features = {
'GameId': match_info['gameId'],
'ChampionId': champion_id,
'Allies': ally_champs,
'Enemies': enemy_champs
}
return features, int(win)
return None, None
The MatchDataProcessor class processes match data by extracting relevant features (champion, allies, and enemies) for each match. It includes error handling for rate limits and custom feature extraction for each match, allowing flexibility and efficient data preparation.
4. CSVHandler Class - Saving and Loading Processed Data
class CSVHandler:
@staticmethod
def save_to_csv(filename, match_data):
filepath = f"./{filename}.csv"
header = ["MatchId", "ChampionId", "Ally1", "Ally2", "Ally3", "Ally4", "Enemy1", "Enemy2", "Enemy3", "Enemy4", "Enemy5"]
with open(filepath, mode="w", newline="") as file:
writer = csv.writer(file)
writer.writerow(header)
for match in match_data:
row = [match['GameId'], match['ChampionId']] + match['Allies'] + match['Enemies'][:5]
writer.writerow(row)
@staticmethod
def load_from_csv(filename):
filepath = f"./{filename}.csv"
if not path.exists(filepath):
return [], []
with open(filepath, mode="r", newline="") as file:
reader = csv.reader(file)
next(reader) # Skip header
matches, labels = [], []
for row in reader:
matches.append({
'GameId': row[0],
'ChampionId': int(row[1]),
'Allies': list(map(int, row[2:6])),
'Enemies': list(map(int, row[6:11]))
})
labels.append(int(row[11]))
return matches, labels
The CSVHandler class provides methods to save processed data to CSV and load it back for analysis. This enables structured storage and quick access to the prepared dataset.
5. Training the Model and Evaluating Accuracy
def train_model(data, labels):
df = pd.DataFrame(data)
X = np.asarray(df[["ChampionId", "Allies", "Enemies"]])
Y = np.asarray(labels)
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, shuffle=True)
model = DecisionTreeClassifier(criterion="entropy", max_depth=5, random_state=4)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2%}")
return model
The train_model function uses a Decision Tree Classifier with entropy criterion to predict match outcomes. After training, it evaluates model accuracy to assess prediction performance.
6. Main Execution
if __name__ == "__main__":
api = LOLAPI("Elroid")
processor = MatchDataProcessor(api)
account_id = api.get_encrypted_account_id()
match_data = api.get_matches(account_id)
processed_data, labels = processor.process_match_data(match_data)
csv_handler = CSVHandler()
csv_handler.save_to_csv("Elroid", processed_data)
model = train_model(processed_data, labels)
The main execution block initiates the API, processes match data, saves it to a CSV file, and trains the model. This organized flow facilitates data collection, processing, and machine learning in a single run.
Comments
Be the first one to comment!