AI in Video Games: Improving Decision Making in League of Legends using Real Match Statistics and Personal Preferences
Part 1: Initial Exploratory Analysis and First Markov Decision Process Model
Motivations and Objectives
League of Legends is a team oriented video game where on two team teams (with 5 players in each) compete for objectives and kills. Gaining an advantage enables the players to become stronger (obtain better items and level up faster) than their opponents and, as their advantage increases, the likelihood of winning the game also increases. We therefore have a sequence of events dependent on previous events that lead to one team destroying the other’s base and winning the game.
Sequences like this being modelled statistically is nothing new; for years now researchers have considered how this is applied in sports, such as basketball (https://arxiv.org/pdf/1507.01816.pdf), where a sequence of passing, dribbling and foul plays lead to a team obtaining or losing points. The aim of research such as this one mentioned is to provide more detailed insight beyond a simple box score (number of points or kill gained by player in basketball or video games respectively) and consider how teams perform when modelled as a sequence of events connected in time.
Modelling the events in this way is even more important in games such as League of Legends as taking objectives and kills lead towards both an item and level advantage. For example, a player obtaining the first kill of the game nets them gold that can be used to purchase more powerful items. With this item they are then strong enough to obtain more kills and so on until they can lead their team to a win. Facilitating a lead like this is often referred to as ‘snowballing’ as the players cumulatively gain advantages but often games are not this one sided and objects and team plays are more important.
The aim of this is project is simple; can we calculate the next best event given what has occurred previously in the game so that the likelihood of eventually leading to a win increases based on real match statistics?
However, there are many factors that lead to a player’s decision making in a game that cannot be easily measured. No how matter how much data collected, the amount of information a player can capture is beyond any that a computer can detect (at least for now!). For example, players may be over or underperforming in this game or may simply have a preference for the way they play (often defined by the types of characters they play). Some players will naturally be more aggressive and look for kills while others will play passively and push for objectives instead. Therefore, we further develop our model to allow the player to adjust the recommended play on their preferences.
Import Packages and Data
In [1]:
import pandas as pd import numpy as np import datetime import matplotlib.pyplot as plt import seaborn as sns from IPython.display import Image import math from scipy.stats import kendalltau import timeit import warnings warnings.filterwarnings('ignore')
In [2]:
#kills = pd.read_csv('C:\\Users\\Phil\\Documents\\LoL Model\\kills.csv') #matchinfo = pd.read_csv('C:\\Users\\Phil\\Documents\\LoL Model\\matchinfo.csv') #monsters = pd.read_csv('C:\\Users\\Phil\\Documents\\LoL Model\\monsters.csv') #structures = pd.read_csv('C:\\Users\\Phil\\Documents\\LoL Model\\structures.csv') kills = pd.read_csv('../input/kills.csv') matchinfo = pd.read_csv('../input/matchinfo.csv') monsters = pd.read_csv('../input/monsters.csv') structures = pd.read_csv('../input/structures.csv')
Pre-Processing and Exploratory Analysis
In [3]:
matchinfo.head()
Out[3]:
League | Year | Season | Type | blueTeamTag | bResult | rResult | redTeamTag | gamelength | blueTop | blueTopChamp | blueJungle | blueJungleChamp | blueMiddle | blueMiddleChamp | blueADC | blueADCChamp | blueSupport | blueSupportChamp | redTop | redTopChamp | redJungle | redJungleChamp | redMiddle | redMiddleChamp | redADC | redADCChamp | redSupport | redSupportChamp | Address | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NALCS | 2015 | Spring | Season | TSM | 1 | 0 | C9 | 40 | Dyrus | Irelia | Santorin | RekSai | Bjergsen | Ahri | WildTurtle | Jinx | Lustboy | Janna | Balls | Gnar | Meteos | Elise | Hai | Fizz | Sneaky | Sivir | LemonNation | Thresh | http://matchhistory.na.leagueoflegends.com/en/... |
1 | NALCS | 2015 | Spring | Season | CST | 0 | 1 | DIG | 38 | Cris | Gnar | Impaler | Rengar | Jesiz | Ahri | Mash | Caitlyn | Sheep | Leona | Gamsu | Irelia | Crumbzz | JarvanIV | Shiphtur | Azir | CoreJJ | Corki | KiWiKiD | Annie | http://matchhistory.na.leagueoflegends.com/en/... |
2 | NALCS | 2015 | Spring | Season | WFX | 1 | 0 | GV | 40 | Flaresz | Renekton | ShorterACE | Rengar | Pobelter | Fizz | Altec | Sivir | Gleeb | Annie | Hauntzer | Sion | Saintvicious | LeeSin | Keane | Azir | Cop | Corki | BunnyFuFuu | Janna | http://matchhistory.na.leagueoflegends.com/en/... |
3 | NALCS | 2015 | Spring | Season | TIP | 0 | 1 | TL | 41 | Rhux | Irelia | Rush | JarvanIV | XiaoWeiXiao | Leblanc | Apollo | Sivir | Adrian | Thresh | Quas | Gnar | IWDominate | Nunu | Fenix | Lulu | KEITH | KogMaw | Xpecial | Janna | http://matchhistory.na.leagueoflegends.com/en/... |
4 | NALCS | 2015 | Spring | Season | CLG | 1 | 0 | T8 | 35 | Benny | Gnar | Xmithie | JarvanIV | Link | Lissandra | Doublelift | Tristana | aphromoo | Janna | CaliTrlolz8 | Sion | Porpoise8 | RekSai | Slooshi8 | Lulu | Maplestreet8 | Corki | Dodo8 | Annie | http://matchhistory.na.leagueoflegends.com/en/... |
In [4]:
# Add ID column based on last 16 digits in match address for simpler matching matchinfo['id'] = matchinfo['Address'].astype(str).str[-16:] kills['id'] = kills['Address'].astype(str).str[-16:] monsters['id'] = monsters['Address'].astype(str).str[-16:] structures['id'] = structures['Address'].astype(str).str[-16:] matchinfo.head()
Out[4]:
League | Year | Season | Type | blueTeamTag | bResult | rResult | redTeamTag | gamelength | blueTop | blueTopChamp | blueJungle | blueJungleChamp | blueMiddle | blueMiddleChamp | blueADC | blueADCChamp | blueSupport | blueSupportChamp | redTop | redTopChamp | redJungle | redJungleChamp | redMiddle | redMiddleChamp | redADC | redADCChamp | redSupport | redSupportChamp | Address | id | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NALCS | 2015 | Spring | Season | TSM | 1 | 0 | C9 | 40 | Dyrus | Irelia | Santorin | RekSai | Bjergsen | Ahri | WildTurtle | Jinx | Lustboy | Janna | Balls | Gnar | Meteos | Elise | Hai | Fizz | Sneaky | Sivir | LemonNation | Thresh | http://matchhistory.na.leagueoflegends.com/en/... | fbb300951ad8327c |
1 | NALCS | 2015 | Spring | Season | CST | 0 | 1 | DIG | 38 | Cris | Gnar | Impaler | Rengar | Jesiz | Ahri | Mash | Caitlyn | Sheep | Leona | Gamsu | Irelia | Crumbzz | JarvanIV | Shiphtur | Azir | CoreJJ | Corki | KiWiKiD | Annie | http://matchhistory.na.leagueoflegends.com/en/... | 055b17da8456fdc8 |
2 | NALCS | 2015 | Spring | Season | WFX | 1 | 0 | GV | 40 | Flaresz | Renekton | ShorterACE | Rengar | Pobelter | Fizz | Altec | Sivir | Gleeb | Annie | Hauntzer | Sion | Saintvicious | LeeSin | Keane | Azir | Cop | Corki | BunnyFuFuu | Janna | http://matchhistory.na.leagueoflegends.com/en/... | 8e8a9b58df366e2d |
3 | NALCS | 2015 | Spring | Season | TIP | 0 | 1 | TL | 41 | Rhux | Irelia | Rush | JarvanIV | XiaoWeiXiao | Leblanc | Apollo | Sivir | Adrian | Thresh | Quas | Gnar | IWDominate | Nunu | Fenix | Lulu | KEITH | KogMaw | Xpecial | Janna | http://matchhistory.na.leagueoflegends.com/en/... | 0ed1cd0e0e57329c |
4 | NALCS | 2015 | Spring | Season | CLG | 1 | 0 | T8 | 35 | Benny | Gnar | Xmithie | JarvanIV | Link | Lissandra | Doublelift | Tristana | aphromoo | Janna | CaliTrlolz8 | Sion | Porpoise8 | RekSai | Slooshi8 | Lulu | Maplestreet8 | Corki | Dodo8 | Annie | http://matchhistory.na.leagueoflegends.com/en/... | f932becf86175f38 |
In [5]:
# Dragon became multiple types in patch v6.9 (http://leagueoflegends.wikia.com/wiki/V6.9) # so we remove and games before this change occured and only use games with the new dragon system monsters['Type'].unique()
Out[5]:
array(['DRAGON', 'EARTH_DRAGON', 'WATER_DRAGON', 'AIR_DRAGON', 'FIRE_DRAGON', 'ELDER_DRAGON', 'BARON_NASHOR', 'RIFT_HERALD'], dtype=object)
In [6]:
old_dragon_id = monsters[ monsters['Type']=="DRAGON"]['id'].unique() old_dragon_id
Out[6]:
array(['fbb300951ad8327c', '055b17da8456fdc8', '8e8a9b58df366e2d', ..., 'd2eaf13bcbb3c021', '035394afd3bfc218', '94537494cdbc8b4c'], dtype=object)
In [7]:
monsters = monsters[ ~monsters['id'].isin(old_dragon_id)] monsters[monsters['Type']=="DRAGON"]
Out[7]:
In [8]:
# Again remove old games, we have some missing values (probably for other events) so remove this # Create a column for the minute in which the kill took place # Reassign the team column to a simpler Red/Blue accordingly for matching with other tables kills = kills[ ~kills['id'].isin(old_dragon_id)] kills = kills[ kills['Time']>0] kills['Minute'] = kills['Time'].astype(int) kills['Team'] = np.where( kills['Team']=="rKills","Red","Blue") kills.head()
Out[8]:
Address | Team | Time | Victim | Killer | Assist_1 | Assist_2 | Assist_3 | Assist_4 | x_pos | y_pos | id | Minute | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
4462 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 6.032 | CLG Huhi | TSM Svenskeren | TSM Bjergsen | NaN | NaN | NaN | 7825 | 8666 | 55109b5a7a91ae87 | 6 |
4463 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 9.428 | CLG Huhi | TSM Biofrost | TSM Bjergsen | TSM Doublelift | NaN | NaN | 8728 | 8751 | 55109b5a7a91ae87 | 9 |
4464 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 9.780 | CLG Xmithie | TSM Bjergsen | TSM Hauntzer | TSM Svenskeren | NaN | NaN | 8655 | 1172 | 55109b5a7a91ae87 | 9 |
4465 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 10.252 | CLG Stixxay | TSM Doublelift | TSM Biofrost | NaN | NaN | NaN | 3621 | 11607 | 55109b5a7a91ae87 | 10 |
4466 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 12.993 | CLG Darshan | TSM Doublelift | TSM Biofrost | NaN | NaN | NaN | 5674 | 12903 | 55109b5a7a91ae87 | 12 |
In [9]:
# For the Kills table, we need decided to group by the minute in which the kills took place and averaged # the time of the kills which we use later for the order of events f = {'Time':['mean','count']} killsGrouped = kills.groupby( ['id','Team','Minute'] ).agg(f).reset_index() killsGrouped.columns = ['id','Team','Minute','Time Avg','Count'] killsGrouped = killsGrouped.sort_values(by=['id','Minute']) killsGrouped.head(13)
Out[9]:
id | Team | Minute | Time Avg | Count | |
---|---|---|---|---|---|
4 | 0001f4374a03c133 | Red | 4 | 4.6350 | 1 |
5 | 0001f4374a03c133 | Red | 6 | 6.0640 | 1 |
0 | 0001f4374a03c133 | Blue | 8 | 8.1940 | 1 |
6 | 0001f4374a03c133 | Red | 10 | 10.4780 | 1 |
7 | 0001f4374a03c133 | Red | 17 | 17.3870 | 2 |
1 | 0001f4374a03c133 | Blue | 18 | 18.0980 | 1 |
8 | 0001f4374a03c133 | Red | 18 | 18.0670 | 2 |
9 | 0001f4374a03c133 | Red | 21 | 21.7900 | 1 |
2 | 0001f4374a03c133 | Blue | 22 | 22.5125 | 2 |
10 | 0001f4374a03c133 | Red | 22 | 22.4578 | 5 |
3 | 0001f4374a03c133 | Blue | 31 | 31.1685 | 2 |
11 | 0001f4374a03c133 | Red | 31 | 31.3880 | 1 |
12 | 0001f4374a03c133 | Red | 32 | 32.7634 | 5 |
In [10]:
# Repeat similar steps for the structures table structures = structures[ ~structures['id'].isin(old_dragon_id)] structures = structures[ structures['Time']>0] structures['Minute'] = structures['Time'].astype(int) structures['Team'] = np.where(structures['Team']=="bTowers","Blue", np.where(structures['Team']=="binhibs","Blue","Red")) structures2 = structures.sort_values(by=['id','Minute']) structures2.head(13)
Out[10]:
Address | Team | Time | Lane | Type | id | Minute | |
---|---|---|---|---|---|---|---|
6740 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 11.182 | TOP_LANE | OUTER_TURRET | 0001f4374a03c133 | 11 |
57600 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 11.006 | BOT_LANE | OUTER_TURRET | 0001f4374a03c133 | 11 |
6741 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 16.556 | BOT_LANE | OUTER_TURRET | 0001f4374a03c133 | 16 |
57601 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 16.145 | TOP_LANE | OUTER_TURRET | 0001f4374a03c133 | 16 |
57598 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 18.378 | MID_LANE | OUTER_TURRET | 0001f4374a03c133 | 18 |
57602 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 24.943 | MID_LANE | INNER_TURRET | 0001f4374a03c133 | 24 |
57599 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 25.463 | TOP_LANE | INNER_TURRET | 0001f4374a03c133 | 25 |
57597 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 26.330 | BOT_LANE | INNER_TURRET | 0001f4374a03c133 | 26 |
57594 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 33.153 | MID_LANE | BASE_TURRET | 0001f4374a03c133 | 33 |
57595 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 33.326 | MID_LANE | NEXUS_TURRET | 0001f4374a03c133 | 33 |
57596 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 33.408 | MID_LANE | NEXUS_TURRET | 0001f4374a03c133 | 33 |
111295 | http://matchhistory.na.leagueoflegends.com/en/... | Red | 33.222 | MID_LANE | INHIBITOR | 0001f4374a03c133 | 33 |
35900 | http://matchhistory.oce.leagueoflegends.com/en... | Blue | 12.603 | BOT_LANE | OUTER_TURRET | 0016710a48fdd46d | 12 |
In [11]:
# Merge the two together kills_structures = killsGrouped.merge(structures2[['id','Minute','Team','Time','Lane','Type']], on=['id','Minute','Team'],how='outer') kills_structures.head(20)
Out[11]:
id | Team | Minute | Time Avg | Count | Time | Lane | Type | |
---|---|---|---|---|---|---|---|---|
0 | 0001f4374a03c133 | Red | 4 | 4.6350 | 1.0 | NaN | NaN | NaN |
1 | 0001f4374a03c133 | Red | 6 | 6.0640 | 1.0 | NaN | NaN | NaN |
2 | 0001f4374a03c133 | Blue | 8 | 8.1940 | 1.0 | NaN | NaN | NaN |
3 | 0001f4374a03c133 | Red | 10 | 10.4780 | 1.0 | NaN | NaN | NaN |
4 | 0001f4374a03c133 | Red | 17 | 17.3870 | 2.0 | NaN | NaN | NaN |
5 | 0001f4374a03c133 | Blue | 18 | 18.0980 | 1.0 | NaN | NaN | NaN |
6 | 0001f4374a03c133 | Red | 18 | 18.0670 | 2.0 | 18.378 | MID_LANE | OUTER_TURRET |
7 | 0001f4374a03c133 | Red | 21 | 21.7900 | 1.0 | NaN | NaN | NaN |
8 | 0001f4374a03c133 | Blue | 22 | 22.5125 | 2.0 | NaN | NaN | NaN |
9 | 0001f4374a03c133 | Red | 22 | 22.4578 | 5.0 | NaN | NaN | NaN |
10 | 0001f4374a03c133 | Blue | 31 | 31.1685 | 2.0 | NaN | NaN | NaN |
11 | 0001f4374a03c133 | Red | 31 | 31.3880 | 1.0 | NaN | NaN | NaN |
12 | 0001f4374a03c133 | Red | 32 | 32.7634 | 5.0 | NaN | NaN | NaN |
13 | 0016710a48fdd46d | Blue | 5 | 5.9710 | 1.0 | NaN | NaN | NaN |
14 | 0016710a48fdd46d | Red | 8 | 8.3750 | 1.0 | NaN | NaN | NaN |
15 | 0016710a48fdd46d | Blue | 11 | 11.9720 | 1.0 | NaN | NaN | NaN |
16 | 0016710a48fdd46d | Red | 11 | 11.9130 | 1.0 | NaN | NaN | NaN |
17 | 0016710a48fdd46d | Red | 13 | 13.1030 | 1.0 | NaN | NaN | NaN |
18 | 0016710a48fdd46d | Blue | 17 | 17.2070 | 1.0 | NaN | NaN | NaN |
19 | 0016710a48fdd46d | Red | 17 | 17.9140 | 1.0 | NaN | NaN | NaN |
In [12]:
# Again repeat same steps, we also map the types of dragon to a simpler 'Dragon' label monsters = monsters[ ~monsters['id'].isin(old_dragon_id)] monsters['Type2'] = np.where( monsters['Type']=="FIRE_DRAGON", "DRAGON", np.where( monsters['Type']=="EARTH_DRAGON","DRAGON", np.where( monsters['Type']=="WATER_DRAGON","DRAGON", np.where( monsters['Type']=="AIR_DRAGON","DRAGON", monsters['Type'])))) monsters = monsters[ monsters['Time']>0] monsters['Minute'] = monsters['Time'].astype(int) monsters['Team'] = np.where( monsters['Team']=="bDragons","Blue", np.where( monsters['Team']=="bHeralds","Blue", np.where( monsters['Team']=="bBarons", "Blue", "Red"))) monsters.head()
Out[12]:
Address | Team | Time | Type | id | Type2 | Minute | |
---|---|---|---|---|---|---|---|
696 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 23.444 | EARTH_DRAGON | 55109b5a7a91ae87 | DRAGON | 23 |
697 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 31.069 | WATER_DRAGON | 55109b5a7a91ae87 | DRAGON | 31 |
698 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 16.419 | AIR_DRAGON | 55109b5a7a91ae87 | DRAGON | 16 |
699 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 32.022 | EARTH_DRAGON | e147296c928da5b4 | DRAGON | 32 |
700 | http://matchhistory.na.leagueoflegends.com/en/... | Blue | 25.304 | WATER_DRAGON | e147296c928da5b4 | DRAGON | 25 |
In [13]:
# Merge the monsters to our previously merged table # This provides us with a table that has each event seperated by columns depending on what type of event it was kills_structures_monsters = kills_structures.merge(monsters[['id','Minute','Team','Time','Type2']], on=['id','Minute'],how='outer') kills_structures_monsters = kills_structures_monsters.sort_values(by=['id','Minute']) kills_structures_monsters.head(5)
Out[13]:
id | Team_x | Minute | Time Avg | Count | Time_x | Lane | Type | Team_y | Time_y | Type2 | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0001f4374a03c133 | Red | 4 | 4.635 | 1.0 | NaN | NaN | NaN | NaN | NaN | NaN |
1 | 0001f4374a03c133 | Red | 6 | 6.064 | 1.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2 | 0001f4374a03c133 | Blue | 8 | 8.194 | 1.0 | NaN | NaN | NaN | NaN | NaN | NaN |
3 | 0001f4374a03c133 | Red | 10 | 10.478 | 1.0 | NaN | NaN | NaN | NaN | NaN | NaN |
94502 | 0001f4374a03c133 | Blue | 11 | NaN | NaN | 11.182 | TOP_LANE | OUTER_TURRET | Red | 11.261 | DRAGON |
In [14]:
# Although this is a good start, information is repeated on the rows if multiple # events occured in the same minute. # # Therefore, I decided to let each event have its own row by stacking the tables # on top of one another. We then add a more detailed time column and sort by this # so we know exactly which event came first (allowing for some errors with kill time # being averaged). stackedData = killsGrouped.append(structures2) stackedData = stackedData.append(monsters[['id','Address','Team','Minute','Time','Type2']]) stackedData['Time2'] = stackedData['Time'].fillna(stackedData['Time Avg']) stackedData = stackedData.sort_values(by=['id','Time2']) stackedData['EventNum'] = stackedData.groupby('id').cumcount()+1 stackedData = stackedData[['id','EventNum','Team','Minute','Time2','Count','Type','Lane','Type2']] stackedData.columns = ['id','EventNum','Team','Minute','Time','KillCount','StructType','StructLane','Monster'] stackedData.head(5)
Out[14]:
id | EventNum | Team | Minute | Time | KillCount | StructType | StructLane | Monster | |
---|---|---|---|---|---|---|---|---|---|
4 | 0001f4374a03c133 | 1 | Red | 4 | 4.635 | 1.0 | NaN | NaN | NaN |
5 | 0001f4374a03c133 | 2 | Red | 6 | 6.064 | 1.0 | NaN | NaN | NaN |
0 | 0001f4374a03c133 | 3 | Blue | 8 | 8.194 | 1.0 | NaN | NaN | NaN |
6 | 0001f4374a03c133 | 4 | Red | 10 | 10.478 | 1.0 | NaN | NaN | NaN |
57600 | 0001f4374a03c133 | 5 | Red | 11 | 11.006 | NaN | OUTER_TURRET | BOT_LANE | NaN |
In [15]:
# We then add an 'Event' column to merge the columns into one, where kills are now # simple labelled as 'KILLS' stackedData['Event'] = np.where(stackedData['KillCount']>0,"KILLS",None) stackedData['Event'] = stackedData['Event'].fillna(stackedData['StructType']) stackedData['Event'] = stackedData['Event'].fillna(stackedData['Monster']) stackedData.head(10)
Out[15]:
id | EventNum | Team | Minute | Time | KillCount | StructType | StructLane | Monster | Event | |
---|---|---|---|---|---|---|---|---|---|---|
4 | 0001f4374a03c133 | 1 | Red | 4 | 4.635 | 1.0 | NaN | NaN | NaN | KILLS |
5 | 0001f4374a03c133 | 2 | Red | 6 | 6.064 | 1.0 | NaN | NaN | NaN | KILLS |
0 | 0001f4374a03c133 | 3 | Blue | 8 | 8.194 | 1.0 | NaN | NaN | NaN | KILLS |
6 | 0001f4374a03c133 | 4 | Red | 10 | 10.478 | 1.0 | NaN | NaN | NaN | KILLS |
57600 | 0001f4374a03c133 | 5 | Red | 11 | 11.006 | NaN | OUTER_TURRET | BOT_LANE | NaN | OUTER_TURRET |
6740 | 0001f4374a03c133 | 6 | Blue | 11 | 11.182 | NaN | OUTER_TURRET | TOP_LANE | NaN | OUTER_TURRET |
24027 | 0001f4374a03c133 | 7 | Red | 11 | 11.261 | NaN | NaN | NaN | DRAGON | DRAGON |
42565 | 0001f4374a03c133 | 8 | Red | 15 | 15.777 | NaN | NaN | NaN | RIFT_HERALD | RIFT_HERALD |
57601 | 0001f4374a03c133 | 9 | Red | 16 | 16.145 | NaN | OUTER_TURRET | TOP_LANE | NaN | OUTER_TURRET |
6741 | 0001f4374a03c133 | 10 | Blue | 16 | 16.556 | NaN | OUTER_TURRET | BOT_LANE | NaN | OUTER_TURRET |
In [16]:
stackedData['Event'].unique()
Out[16]:
array(['KILLS', 'OUTER_TURRET', 'DRAGON', 'RIFT_HERALD', 'BARON_NASHOR', 'INNER_TURRET', 'BASE_TURRET', 'INHIBITOR', 'NEXUS_TURRET', 'ELDER_DRAGON'], dtype=object)
In [17]:
NumEventAnalysis = stackedData[['id','EventNum']].groupby('id').max().reset_index() NumEventAnalysis2 = NumEventAnalysis.groupby('EventNum').count().reset_index() NumEventAnalysis2.head()
Out[17]:
EventNum | id | |
---|---|---|
0 | 14 | 1 |
1 | 16 | 3 |
2 | 17 | 4 |
3 | 18 | 7 |
4 | 19 | 12 |
In [18]:
plt.bar(NumEventAnalysis2['EventNum'],NumEventAnalysis2['id'] ,alpha=0.3) plt.plot(NumEventAnalysis2['EventNum'],NumEventAnalysis2['id']) plt.title('Distribution of Number of Events in Each Match (EXACT)') plt.xlim(0,100) plt.xlabel("Number of Events") plt.ylabel("Number of Matches") plt.show()
In [19]:
sns.distplot(NumEventAnalysis['EventNum'],bins=65) plt.title('Distribution of Number of Events in Each Match (NORMAL DIST)') plt.xlim(0,100) plt.xlabel("Number of Events") plt.ylabel("Number of Matches") plt.show()
In [20]:
print("The max number of events for any team in a single game is:",NumEventAnalysis['EventNum'].max()) print("The min number of events for any team in a single game is:",NumEventAnalysis['EventNum'].min())
The max number of events for any team in a single game is: 79 The min number of events for any team in a single game is: 14
In [21]:
# We then create a table with just the unique match ids that we will use to merge our tables to shortly matchevents = pd.DataFrame(stackedData['id'].unique()) matchevents.columns = ['id'] matchevents.head()
Out[21]:
id | |
---|---|
0 | 0001f4374a03c133 |
1 | 0016710a48fdd46d |
2 | 0016c9df37278448 |
3 | 0021b45647424cd5 |
4 | 00405293fb859241 |
In [22]:
# WARNING: Takes a while to run # This cell has a lot of steps but the idea is to: # 1) Seperate the the events into each team (Red/Blue) # 2) For each, go through each match and transpose the list of events into a single row # 3) Stack a table that has the events for both team of the matches bluerows = pd.DataFrame() stackedData_blue = stackedData stackedData_blue['EventBlue'] = np.where( stackedData_blue['Team']!="Red",stackedData_blue['Event'],np.nan) redrows = pd.DataFrame() stackedData_red = stackedData stackedData_red['EventRed'] = np.where( stackedData_red['Team']=="Red",stackedData_red['Event'],np.nan) for i in range(0,len(matchevents)): #Red Team Output stackedData_match_red = stackedData_red[stackedData_red['id'] == matchevents.iloc[i,0] ] redextract = stackedData_match_red.iloc[:,[1,11]] redextract.iloc[:,0] = redextract.iloc[:,0]-1 redextract = redextract.set_index('EventNum') redrow = pd.DataFrame(redextract.transpose()) redrow['id'] = (stackedData_match_red['id'].unique()) redrows = redrows.append((redrow)) redrows = redrows.reset_index(drop=True) #Blue Team Output stackedData_match_blue = stackedData_blue[stackedData_blue['id'] == matchevents.iloc[i,0] ] blueextract = stackedData_match_blue.iloc[:,[1,10]] blueextract.iloc[:,0] = blueextract.iloc[:,0]-1 blueextract = blueextract.set_index('EventNum') bluerow = pd.DataFrame(blueextract.transpose()) bluerow['id'] = (stackedData_match_blue['id'].unique()) bluerows = bluerows.append((bluerow)) bluerows = bluerows.reset_index(drop=True)
In [23]:
redrows = redrows.sort_values('id') redrows.head(5)
Out[23]:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | id | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | KILLS | KILLS | NaN | KILLS | OUTER_TURRET | NaN | DRAGON | RIFT_HERALD | OUTER_TURRET | NaN | KILLS | DRAGON | KILLS | NaN | OUTER_TURRET | KILLS | KILLS | NaN | BARON_NASHOR | DRAGON | INNER_TURRET | INNER_TURRET | INNER_TURRET | DRAGON | NaN | KILLS | KILLS | BASE_TURRET | INHIBITOR | NEXUS_TURRET | NEXUS_TURRET | 0001f4374a03c133 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | NaN | KILLS | DRAGON | KILLS | NaN | NaN | KILLS | NaN | NaN | KILLS | KILLS | NaN | OUTER_TURRET | NaN | NaN | NaN | KILLS | NaN | KILLS | OUTER_TURRET | NaN | KILLS | OUTER_TURRET | NaN | KILLS | NaN | KILLS | NaN | KILLS | BARON_NASHOR | KILLS | 0016710a48fdd46d | INNER_TURRET | INNER_TURRET | INNER_TURRET | NaN | KILLS | BASE_TURRET | NaN | INHIBITOR | KILLS | NaN | KILLS | NEXUS_TURRET | NEXUS_TURRET | NaN | NaN | NaN | KILLS | INHIBITOR | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 | NaN | NaN | NaN | NaN | NaN | NaN | KILLS | NaN | NaN | OUTER_TURRET | NaN | NaN | KILLS | NaN | NaN | NaN | KILLS | BARON_NASHOR | OUTER_TURRET | DRAGON | KILLS | OUTER_TURRET | INNER_TURRET | INNER_TURRET | BASE_TURRET | INHIBITOR | INNER_TURRET | BASE_TURRET | BASE_TURRET | INHIBITOR | NEXUS_TURRET | 0016c9df37278448 | NEXUS_TURRET | NaN | KILLS | INHIBITOR | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
3 | NaN | KILLS | KILLS | KILLS | NaN | DRAGON | RIFT_HERALD | NaN | OUTER_TURRET | NaN | OUTER_TURRET | NaN | DRAGON | KILLS | KILLS | OUTER_TURRET | NaN | KILLS | BARON_NASHOR | NaN | DRAGON | INNER_TURRET | KILLS | INNER_TURRET | BASE_TURRET | INHIBITOR | NaN | KILLS | NEXUS_TURRET | BARON_NASHOR | INNER_TURRET | 0021b45647424cd5 | NaN | DRAGON | INHIBITOR | BASE_TURRET | INHIBITOR | NaN | NaN | KILLS | NaN | KILLS | NEXUS_TURRET | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
4 | KILLS | NaN | NaN | NaN | NaN | OUTER_TURRET | NaN | NaN | NaN | NaN | NaN | NaN | NaN | KILLS | NaN | NaN | OUTER_TURRET | KILLS | KILLS | NaN | OUTER_TURRET | DRAGON | BARON_NASHOR | KILLS | INNER_TURRET | BASE_TURRET | INHIBITOR | KILLS | INNER_TURRET | KILLS | BASE_TURRET | 00405293fb859241 | INHIBITOR | NaN | KILLS | INNER_TURRET | NEXUS_TURRET | NEXUS_TURRET | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
In [24]:
bluerows = bluerows.sort_values('id') bluerows.head(5)
Out[24]:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | id | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | NaN | KILLS | NaN | NaN | OUTER_TURRET | NaN | NaN | NaN | OUTER_TURRET | NaN | NaN | NaN | KILLS | NaN | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | 0001f4374a03c133 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | KILLS | NaN | NaN | NaN | KILLS | OUTER_TURRET | NaN | DRAGON | KILLS | NaN | NaN | KILLS | NaN | OUTER_TURRET | DRAGON | KILLS | NaN | OUTER_TURRET | NaN | NaN | KILLS | NaN | NaN | KILLS | NaN | KILLS | NaN | DRAGON | NaN | NaN | NaN | 0016710a48fdd46d | NaN | NaN | NaN | KILLS | NaN | NaN | KILLS | NaN | NaN | KILLS | NaN | NaN | NaN | KILLS | KILLS | DRAGON | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 | KILLS | KILLS | KILLS | OUTER_TURRET | DRAGON | KILLS | NaN | KILLS | RIFT_HERALD | NaN | OUTER_TURRET | DRAGON | NaN | DRAGON | KILLS | OUTER_TURRET | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0016c9df37278448 | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
3 | KILLS | NaN | NaN | NaN | KILLS | NaN | NaN | KILLS | NaN | KILLS | NaN | KILLS | NaN | NaN | NaN | NaN | OUTER_TURRET | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | 0021b45647424cd5 | KILLS | NaN | NaN | NaN | NaN | KILLS | BARON_NASHOR | NaN | KILLS | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
4 | NaN | KILLS | KILLS | KILLS | OUTER_TURRET | NaN | DRAGON | KILLS | OUTER_TURRET | KILLS | KILLS | DRAGON | OUTER_TURRET | NaN | KILLS | DRAGON | NaN | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 00405293fb859241 | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
In [25]:
# We can now merge these two tables for each team's events in the match to # our table with just the match ids. We also add a column for the result of # the red team for the match and change column names according to which team # made the event. matchevents2 = matchevents.merge(redrows,how='left',on='id') matchevents3 = matchevents2.merge(bluerows,how='left',on='id') matchevents4 = matchevents3.merge(matchinfo[['id','rResult','gamelength']], on='id',how='left') matchevents4.columns = ['id', 'RedEvent1','RedEvent2','RedEvent3', 'RedEvent4','RedEvent5','RedEvent6','RedEvent7', 'RedEvent8','RedEvent9','RedEvent10','RedEvent11', 'RedEvent12','RedEvent13','RedEvent14','RedEvent15', 'RedEvent16','RedEvent17','RedEvent18','RedEvent19', 'RedEvent20','RedEvent21','RedEvent22','RedEvent23', 'RedEvent24','RedEvent25','RedEvent26','RedEvent27', 'RedEvent28','RedEvent29','RedEvent30','RedEvent31', 'RedEvent32','RedEvent33','RedEvent34','RedEvent35', 'RedEvent36','RedEvent37','RedEvent38','RedEvent39', 'RedEvent40','RedEvent41','RedEvent42','RedEvent43', 'RedEvent44','RedEvent45','RedEvent46','RedEvent47', 'RedEvent48','RedEvent49','RedEvent50','RedEvent51', 'RedEvent52','RedEvent53','RedEvent54','RedEvent55', 'RedEvent56','RedEvent57','RedEvent58','RedEvent59', 'RedEvent60','RedEvent61','RedEvent62','RedEvent63', 'RedEvent64','RedEvent65','RedEvent66','RedEvent67', 'RedEvent68','RedEvent69','RedEvent70','RedEvent71', 'RedEvent72','RedEvent73','RedEvent74','RedEvent75', 'RedEvent76','RedEvent77','RedEvent78','RedEvent79', 'BlueEvent1','BlueEvent2','BlueEvent3','BlueEvent4', 'BlueEvent5','BlueEvent6','BlueEvent7','BlueEvent8', 'BlueEvent9','BlueEvent10','BlueEvent11','BlueEvent12', 'BlueEvent13','BlueEvent14','BlueEvent15','BlueEvent16', 'BlueEvent17','BlueEvent18','BlueEvent19','BlueEvent20', 'BlueEvent21','BlueEvent22','BlueEvent23','BlueEvent24', 'BlueEvent25','BlueEvent26','BlueEvent27','BlueEvent28', 'BlueEvent29','BlueEvent30','BlueEvent31','BlueEvent32', 'BlueEvent33','BlueEvent34','BlueEvent35','BlueEvent36', 'BlueEvent37','BlueEvent38','BlueEvent39','BlueEvent40', 'BlueEvent41','BlueEvent42','BlueEvent43','BlueEvent44', 'BlueEvent45','BlueEvent46','BlueEvent47','BlueEvent48', 'BlueEvent49','BlueEvent50','BlueEvent51','BlueEvent52', 'BlueEvent53','BlueEvent54','BlueEvent55','BlueEvent56', 'BlueEvent57','BlueEvent58','BlueEvent59','BlueEvent60', 'BlueEvent61','BlueEvent62','BlueEvent63', 'BlueEvent64','BlueEvent65','BlueEvent66','BlueEvent67', 'BlueEvent68','BlueEvent69','BlueEvent70','BlueEvent71', 'BlueEvent72','BlueEvent73','BlueEvent74','BlueEvent75', 'BlueEvent76','BlueEvent77','BlueEvent78','BlueEvent79', 'rResult','gamelength'] matchevents4.head(20)
Out[25]:
id | RedEvent1 | RedEvent2 | RedEvent3 | RedEvent4 | RedEvent5 | RedEvent6 | RedEvent7 | RedEvent8 | RedEvent9 | RedEvent10 | RedEvent11 | RedEvent12 | RedEvent13 | RedEvent14 | RedEvent15 | RedEvent16 | RedEvent17 | RedEvent18 | RedEvent19 | RedEvent20 | RedEvent21 | RedEvent22 | RedEvent23 | RedEvent24 | RedEvent25 | RedEvent26 | RedEvent27 | RedEvent28 | RedEvent29 | RedEvent30 | RedEvent31 | RedEvent32 | RedEvent33 | RedEvent34 | RedEvent35 | RedEvent36 | RedEvent37 | RedEvent38 | RedEvent39 | ... | BlueEvent42 | BlueEvent43 | BlueEvent44 | BlueEvent45 | BlueEvent46 | BlueEvent47 | BlueEvent48 | BlueEvent49 | BlueEvent50 | BlueEvent51 | BlueEvent52 | BlueEvent53 | BlueEvent54 | BlueEvent55 | BlueEvent56 | BlueEvent57 | BlueEvent58 | BlueEvent59 | BlueEvent60 | BlueEvent61 | BlueEvent62 | BlueEvent63 | BlueEvent64 | BlueEvent65 | BlueEvent66 | BlueEvent67 | BlueEvent68 | BlueEvent69 | BlueEvent70 | BlueEvent71 | BlueEvent72 | BlueEvent73 | BlueEvent74 | BlueEvent75 | BlueEvent76 | BlueEvent77 | BlueEvent78 | BlueEvent79 | rResult | gamelength | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0001f4374a03c133 | KILLS | KILLS | NaN | KILLS | OUTER_TURRET | NaN | DRAGON | RIFT_HERALD | OUTER_TURRET | NaN | KILLS | DRAGON | KILLS | NaN | OUTER_TURRET | KILLS | KILLS | NaN | BARON_NASHOR | DRAGON | INNER_TURRET | INNER_TURRET | INNER_TURRET | DRAGON | NaN | KILLS | KILLS | BASE_TURRET | INHIBITOR | NEXUS_TURRET | NEXUS_TURRET | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 34 |
1 | 0016710a48fdd46d | NaN | KILLS | DRAGON | KILLS | NaN | NaN | KILLS | NaN | NaN | KILLS | KILLS | NaN | OUTER_TURRET | NaN | NaN | NaN | KILLS | NaN | KILLS | OUTER_TURRET | NaN | KILLS | OUTER_TURRET | NaN | KILLS | NaN | KILLS | NaN | KILLS | BARON_NASHOR | KILLS | INNER_TURRET | INNER_TURRET | INNER_TURRET | NaN | KILLS | BASE_TURRET | NaN | INHIBITOR | ... | NaN | NaN | NaN | KILLS | KILLS | DRAGON | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 40 |
2 | 0016c9df37278448 | NaN | NaN | NaN | NaN | NaN | NaN | KILLS | NaN | NaN | OUTER_TURRET | NaN | NaN | KILLS | NaN | NaN | NaN | KILLS | BARON_NASHOR | OUTER_TURRET | DRAGON | KILLS | OUTER_TURRET | INNER_TURRET | INNER_TURRET | BASE_TURRET | INHIBITOR | INNER_TURRET | BASE_TURRET | BASE_TURRET | INHIBITOR | NEXUS_TURRET | NEXUS_TURRET | NaN | KILLS | INHIBITOR | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 40 |
3 | 0021b45647424cd5 | NaN | KILLS | KILLS | KILLS | NaN | DRAGON | RIFT_HERALD | NaN | OUTER_TURRET | NaN | OUTER_TURRET | NaN | DRAGON | KILLS | KILLS | OUTER_TURRET | NaN | KILLS | BARON_NASHOR | NaN | DRAGON | INNER_TURRET | KILLS | INNER_TURRET | BASE_TURRET | INHIBITOR | NaN | KILLS | NEXUS_TURRET | BARON_NASHOR | INNER_TURRET | NaN | DRAGON | INHIBITOR | BASE_TURRET | INHIBITOR | NaN | NaN | KILLS | ... | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 42 |
4 | 00405293fb859241 | KILLS | NaN | NaN | NaN | NaN | OUTER_TURRET | NaN | NaN | NaN | NaN | NaN | NaN | NaN | KILLS | NaN | NaN | OUTER_TURRET | KILLS | KILLS | NaN | OUTER_TURRET | DRAGON | BARON_NASHOR | KILLS | INNER_TURRET | BASE_TURRET | INHIBITOR | KILLS | INNER_TURRET | KILLS | BASE_TURRET | INHIBITOR | NaN | KILLS | INNER_TURRET | NEXUS_TURRET | NEXUS_TURRET | KILLS | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 39 |
5 | 00416ed438e29f14 | NaN | KILLS | NaN | NaN | NaN | OUTER_TURRET | NaN | KILLS | KILLS | DRAGON | NaN | NaN | OUTER_TURRET | KILLS | KILLS | BARON_NASHOR | NaN | OUTER_TURRET | NaN | INNER_TURRET | INNER_TURRET | NaN | BARON_NASHOR | KILLS | BASE_TURRET | NaN | NaN | NaN | INHIBITOR | KILLS | INNER_TURRET | BASE_TURRET | BASE_TURRET | INHIBITOR | NaN | KILLS | NaN | NEXUS_TURRET | NEXUS_TURRET | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 41 |
6 | 007802c051352561 | NaN | KILLS | DRAGON | KILLS | KILLS | RIFT_HERALD | NaN | NaN | OUTER_TURRET | OUTER_TURRET | INNER_TURRET | NaN | NaN | NaN | OUTER_TURRET | NaN | KILLS | DRAGON | INNER_TURRET | DRAGON | NaN | NaN | KILLS | BARON_NASHOR | NaN | KILLS | KILLS | ELDER_DRAGON | INNER_TURRET | BASE_TURRET | INHIBITOR | BARON_NASHOR | BASE_TURRET | NaN | KILLS | INHIBITOR | KILLS | NEXUS_TURRET | NEXUS_TURRET | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 44 |
7 | 0091705b03924485 | NaN | NaN | NaN | NaN | NaN | NaN | DRAGON | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | INHIBITOR | INHIBITOR | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0 | 27 |
8 | 00986b51908a63c3 | NaN | KILLS | KILLS | KILLS | KILLS | KILLS | NaN | OUTER_TURRET | DRAGON | OUTER_TURRET | NaN | INNER_TURRET | KILLS | OUTER_TURRET | INNER_TURRET | DRAGON | KILLS | NaN | NaN | DRAGON | NaN | NaN | KILLS | INNER_TURRET | BASE_TURRET | INHIBITOR | NaN | NaN | NaN | KILLS | BASE_TURRET | NaN | NaN | INHIBITOR | NaN | NaN | KILLS | INHIBITOR | BASE_TURRET | ... | NaN | NaN | NaN | KILLS | INNER_TURRET | NaN | NaN | NaN | KILLS | NaN | BARON_NASHOR | KILLS | KILLS | ELDER_DRAGON | BASE_TURRET | NaN | NaN | NaN | KILLS | KILLS | NEXUS_TURRET | NEXUS_TURRET | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0 | 69 |
9 | 00b13dbf1bd7aff0 | NaN | KILLS | OUTER_TURRET | NaN | DRAGON | NaN | DRAGON | OUTER_TURRET | NaN | OUTER_TURRET | NaN | KILLS | NaN | NaN | KILLS | BARON_NASHOR | NaN | NaN | NaN | NaN | DRAGON | NaN | KILLS | INHIBITOR | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0 | 36 |
10 | 00b2492ce66406e9 | KILLS | KILLS | KILLS | NaN | NaN | NaN | NaN | KILLS | KILLS | KILLS | KILLS | KILLS | OUTER_TURRET | OUTER_TURRET | DRAGON | RIFT_HERALD | OUTER_TURRET | BARON_NASHOR | INNER_TURRET | NaN | INNER_TURRET | KILLS | INNER_TURRET | DRAGON | KILLS | BASE_TURRET | BASE_TURRET | BASE_TURRET | INHIBITOR | KILLS | NEXUS_TURRET | INHIBITOR | NEXUS_TURRET | INHIBITOR | NaN | KILLS | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 29 |
11 | 00df84280ed2625b | KILLS | NaN | NaN | DRAGON | NaN | KILLS | NaN | KILLS | KILLS | OUTER_TURRET | OUTER_TURRET | KILLS | NaN | BARON_NASHOR | NaN | KILLS | OUTER_TURRET | DRAGON | INNER_TURRET | NaN | KILLS | KILLS | KILLS | BARON_NASHOR | DRAGON | INNER_TURRET | KILLS | NaN | BASE_TURRET | INHIBITOR | NEXUS_TURRET | KILLS | INNER_TURRET | BASE_TURRET | KILLS | NEXUS_TURRET | NaN | KILLS | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 39 |
12 | 00e4eb2c47c14065 | NaN | OUTER_TURRET | NaN | OUTER_TURRET | NaN | DRAGON | RIFT_HERALD | NaN | NaN | NaN | KILLS | OUTER_TURRET | NaN | NaN | BARON_NASHOR | INNER_TURRET | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | INHIBITOR | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0 | 31 |
13 | 00ecc69a0f024ada | NaN | NaN | NaN | NaN | NaN | NaN | OUTER_TURRET | NaN | NaN | OUTER_TURRET | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | INHIBITOR | NaN | NaN | NaN | INHIBITOR | NaN | NaN | NaN | INHIBITOR | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0 | 34 |
14 | 00fc8c3957193d35 | KILLS | KILLS | OUTER_TURRET | NaN | INNER_TURRET | NaN | DRAGON | NaN | KILLS | NaN | OUTER_TURRET | OUTER_TURRET | DRAGON | NaN | KILLS | NaN | NaN | NaN | DRAGON | KILLS | BARON_NASHOR | NaN | KILLS | INNER_TURRET | NaN | KILLS | BASE_TURRET | INHIBITOR | KILLS | INNER_TURRET | KILLS | NaN | DRAGON | NaN | KILLS | NaN | KILLS | NEXUS_TURRET | NEXUS_TURRET | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 32 |
15 | 0122e715a37611f0 | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | DRAGON | KILLS | KILLS | OUTER_TURRET | KILLS | NaN | NaN | NaN | NaN | OUTER_TURRET | NaN | NaN | NaN | KILLS | NaN | NaN | KILLS | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | NaN | INHIBITOR | NaN | INHIBITOR | NaN | INHIBITOR | NaN | ... | NEXUS_TURRET | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0 | 36 |
16 | 01321351be01672f | OUTER_TURRET | NaN | NaN | OUTER_TURRET | NaN | DRAGON | NaN | NaN | NaN | OUTER_TURRET | NaN | KILLS | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | INHIBITOR | NaN | KILLS | NaN | NaN | KILLS | NaN | INHIBITOR | NaN | KILLS | NaN | INHIBITOR | NaN | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0 | 34 |
17 | 01360c9cdc07e173 | NaN | KILLS | KILLS | NaN | NaN | KILLS | NaN | DRAGON | NaN | NaN | NaN | OUTER_TURRET | NaN | KILLS | NaN | BARON_NASHOR | NaN | DRAGON | OUTER_TURRET | OUTER_TURRET | NaN | INNER_TURRET | KILLS | NaN | BASE_TURRET | INNER_TURRET | NaN | INHIBITOR | KILLS | NaN | DRAGON | NaN | NEXUS_TURRET | NaN | INNER_TURRET | NaN | BASE_TURRET | DRAGON | INHIBITOR | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1 | 44 |
18 | 01368b5ce8fcef87 | NaN | KILLS | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | KILLS | DRAGON | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | INHIBITOR | NaN | INHIBITOR | NaN | NaN | NaN | INHIBITOR | NaN | KILLS | NaN | NaN | NaN | KILLS | INHIBITOR | KILLS | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0 | 34 |
19 | 01417eebd0d9ccb3 | NaN | NaN | KILLS | NaN | KILLS | NaN | KILLS | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | NaN | NaN | KILLS | NaN | NaN | NaN | NaN | INHIBITOR | NaN | NaN | INHIBITOR | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0 | 31 |
In [26]:
# We now decided, for the purpose of calculating probabilities, to consider one team's perseperctive. # Therefore, we make all events either positive or negative for red team but keep their label otherwise. matchevents5=matchevents4 for j in range(1,len(list(redrows))): matchevents5['RedEvent'+str(j)] = '+'+ matchevents5['RedEvent'+str(j)].astype(str) matchevents5['BlueEvent'+str(j)] = '-'+ matchevents5['BlueEvent'+str(j)].astype(str) matchevents5 = matchevents5.replace('+nan',np.nan) matchevents5['RedEvent'+str(j)] = matchevents5['RedEvent'+str(j)].fillna( (matchevents5['BlueEvent'+str(j)]).astype(str)) matchevents5.head()
Out[26]:
id | RedEvent1 | RedEvent2 | RedEvent3 | RedEvent4 | RedEvent5 | RedEvent6 | RedEvent7 | RedEvent8 | RedEvent9 | RedEvent10 | RedEvent11 | RedEvent12 | RedEvent13 | RedEvent14 | RedEvent15 | RedEvent16 | RedEvent17 | RedEvent18 | RedEvent19 | RedEvent20 | RedEvent21 | RedEvent22 | RedEvent23 | RedEvent24 | RedEvent25 | RedEvent26 | RedEvent27 | RedEvent28 | RedEvent29 | RedEvent30 | RedEvent31 | RedEvent32 | RedEvent33 | RedEvent34 | RedEvent35 | RedEvent36 | RedEvent37 | RedEvent38 | RedEvent39 | ... | BlueEvent42 | BlueEvent43 | BlueEvent44 | BlueEvent45 | BlueEvent46 | BlueEvent47 | BlueEvent48 | BlueEvent49 | BlueEvent50 | BlueEvent51 | BlueEvent52 | BlueEvent53 | BlueEvent54 | BlueEvent55 | BlueEvent56 | BlueEvent57 | BlueEvent58 | BlueEvent59 | BlueEvent60 | BlueEvent61 | BlueEvent62 | BlueEvent63 | BlueEvent64 | BlueEvent65 | BlueEvent66 | BlueEvent67 | BlueEvent68 | BlueEvent69 | BlueEvent70 | BlueEvent71 | BlueEvent72 | BlueEvent73 | BlueEvent74 | BlueEvent75 | BlueEvent76 | BlueEvent77 | BlueEvent78 | BlueEvent79 | rResult | gamelength | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0001f4374a03c133 | +KILLS | +KILLS | -KILLS | +KILLS | +OUTER_TURRET | -OUTER_TURRET | +DRAGON | +RIFT_HERALD | +OUTER_TURRET | -OUTER_TURRET | +KILLS | +DRAGON | +KILLS | -KILLS | +OUTER_TURRET | +KILLS | +KILLS | -KILLS | +BARON_NASHOR | +DRAGON | +INNER_TURRET | +INNER_TURRET | +INNER_TURRET | +DRAGON | -KILLS | +KILLS | +KILLS | +BASE_TURRET | +INHIBITOR | +NEXUS_TURRET | +NEXUS_TURRET | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 34 |
1 | 0016710a48fdd46d | -KILLS | +KILLS | +DRAGON | +KILLS | -KILLS | -OUTER_TURRET | +KILLS | -DRAGON | -KILLS | +KILLS | +KILLS | -KILLS | +OUTER_TURRET | -OUTER_TURRET | -DRAGON | -KILLS | +KILLS | -OUTER_TURRET | +KILLS | +OUTER_TURRET | -KILLS | +KILLS | +OUTER_TURRET | -KILLS | +KILLS | -KILLS | +KILLS | -DRAGON | +KILLS | +BARON_NASHOR | +KILLS | +INNER_TURRET | +INNER_TURRET | +INNER_TURRET | -KILLS | +KILLS | +BASE_TURRET | -KILLS | +INHIBITOR | ... | -nan | -nan | -nan | -KILLS | -KILLS | -DRAGON | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 40 |
2 | 0016c9df37278448 | -KILLS | -KILLS | -KILLS | -OUTER_TURRET | -DRAGON | -KILLS | +KILLS | -KILLS | -RIFT_HERALD | +OUTER_TURRET | -OUTER_TURRET | -DRAGON | +KILLS | -DRAGON | -KILLS | -OUTER_TURRET | +KILLS | +BARON_NASHOR | +OUTER_TURRET | +DRAGON | +KILLS | +OUTER_TURRET | +INNER_TURRET | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | +INNER_TURRET | +BASE_TURRET | +BASE_TURRET | +INHIBITOR | +NEXUS_TURRET | +NEXUS_TURRET | -KILLS | +KILLS | +INHIBITOR | -nan | -nan | -nan | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 40 |
3 | 0021b45647424cd5 | -KILLS | +KILLS | +KILLS | +KILLS | -KILLS | +DRAGON | +RIFT_HERALD | -KILLS | +OUTER_TURRET | -KILLS | +OUTER_TURRET | -KILLS | +DRAGON | +KILLS | +KILLS | +OUTER_TURRET | -OUTER_TURRET | +KILLS | +BARON_NASHOR | -KILLS | +DRAGON | +INNER_TURRET | +KILLS | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | -KILLS | +KILLS | +NEXUS_TURRET | +BARON_NASHOR | +INNER_TURRET | -KILLS | +DRAGON | +INHIBITOR | +BASE_TURRET | +INHIBITOR | -KILLS | -BARON_NASHOR | +KILLS | ... | -nan | -KILLS | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 42 |
4 | 00405293fb859241 | +KILLS | -KILLS | -KILLS | -KILLS | -OUTER_TURRET | +OUTER_TURRET | -DRAGON | -KILLS | -OUTER_TURRET | -KILLS | -KILLS | -DRAGON | -OUTER_TURRET | +KILLS | -KILLS | -DRAGON | +OUTER_TURRET | +KILLS | +KILLS | -KILLS | +OUTER_TURRET | +DRAGON | +BARON_NASHOR | +KILLS | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | +KILLS | +INNER_TURRET | +KILLS | +BASE_TURRET | +INHIBITOR | -KILLS | +KILLS | +INNER_TURRET | +NEXUS_TURRET | +NEXUS_TURRET | +KILLS | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 39 |
In [27]:
# We take on the red event columns now and re-add the end result of the game for red team (1=win, 0=loss) RedMatchEvents = matchevents5.iloc[:,0:80] RedMatchEvents['RedResult'] = matchevents5['rResult'] RedMatchEvents['MatchLength'] = matchevents5['gamelength'] RedMatchEvents.iloc[0:10]
Out[27]:
id | RedEvent1 | RedEvent2 | RedEvent3 | RedEvent4 | RedEvent5 | RedEvent6 | RedEvent7 | RedEvent8 | RedEvent9 | RedEvent10 | RedEvent11 | RedEvent12 | RedEvent13 | RedEvent14 | RedEvent15 | RedEvent16 | RedEvent17 | RedEvent18 | RedEvent19 | RedEvent20 | RedEvent21 | RedEvent22 | RedEvent23 | RedEvent24 | RedEvent25 | RedEvent26 | RedEvent27 | RedEvent28 | RedEvent29 | RedEvent30 | RedEvent31 | RedEvent32 | RedEvent33 | RedEvent34 | RedEvent35 | RedEvent36 | RedEvent37 | RedEvent38 | RedEvent39 | ... | RedEvent42 | RedEvent43 | RedEvent44 | RedEvent45 | RedEvent46 | RedEvent47 | RedEvent48 | RedEvent49 | RedEvent50 | RedEvent51 | RedEvent52 | RedEvent53 | RedEvent54 | RedEvent55 | RedEvent56 | RedEvent57 | RedEvent58 | RedEvent59 | RedEvent60 | RedEvent61 | RedEvent62 | RedEvent63 | RedEvent64 | RedEvent65 | RedEvent66 | RedEvent67 | RedEvent68 | RedEvent69 | RedEvent70 | RedEvent71 | RedEvent72 | RedEvent73 | RedEvent74 | RedEvent75 | RedEvent76 | RedEvent77 | RedEvent78 | RedEvent79 | RedResult | MatchLength | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0001f4374a03c133 | +KILLS | +KILLS | -KILLS | +KILLS | +OUTER_TURRET | -OUTER_TURRET | +DRAGON | +RIFT_HERALD | +OUTER_TURRET | -OUTER_TURRET | +KILLS | +DRAGON | +KILLS | -KILLS | +OUTER_TURRET | +KILLS | +KILLS | -KILLS | +BARON_NASHOR | +DRAGON | +INNER_TURRET | +INNER_TURRET | +INNER_TURRET | +DRAGON | -KILLS | +KILLS | +KILLS | +BASE_TURRET | +INHIBITOR | +NEXUS_TURRET | +NEXUS_TURRET | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 34 |
1 | 0016710a48fdd46d | -KILLS | +KILLS | +DRAGON | +KILLS | -KILLS | -OUTER_TURRET | +KILLS | -DRAGON | -KILLS | +KILLS | +KILLS | -KILLS | +OUTER_TURRET | -OUTER_TURRET | -DRAGON | -KILLS | +KILLS | -OUTER_TURRET | +KILLS | +OUTER_TURRET | -KILLS | +KILLS | +OUTER_TURRET | -KILLS | +KILLS | -KILLS | +KILLS | -DRAGON | +KILLS | +BARON_NASHOR | +KILLS | +INNER_TURRET | +INNER_TURRET | +INNER_TURRET | -KILLS | +KILLS | +BASE_TURRET | -KILLS | +INHIBITOR | ... | +KILLS | +NEXUS_TURRET | +NEXUS_TURRET | -KILLS | -KILLS | -DRAGON | +KILLS | +INHIBITOR | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 40 |
2 | 0016c9df37278448 | -KILLS | -KILLS | -KILLS | -OUTER_TURRET | -DRAGON | -KILLS | +KILLS | -KILLS | -RIFT_HERALD | +OUTER_TURRET | -OUTER_TURRET | -DRAGON | +KILLS | -DRAGON | -KILLS | -OUTER_TURRET | +KILLS | +BARON_NASHOR | +OUTER_TURRET | +DRAGON | +KILLS | +OUTER_TURRET | +INNER_TURRET | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | +INNER_TURRET | +BASE_TURRET | +BASE_TURRET | +INHIBITOR | +NEXUS_TURRET | +NEXUS_TURRET | -KILLS | +KILLS | +INHIBITOR | -nan | -nan | -nan | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 40 |
3 | 0021b45647424cd5 | -KILLS | +KILLS | +KILLS | +KILLS | -KILLS | +DRAGON | +RIFT_HERALD | -KILLS | +OUTER_TURRET | -KILLS | +OUTER_TURRET | -KILLS | +DRAGON | +KILLS | +KILLS | +OUTER_TURRET | -OUTER_TURRET | +KILLS | +BARON_NASHOR | -KILLS | +DRAGON | +INNER_TURRET | +KILLS | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | -KILLS | +KILLS | +NEXUS_TURRET | +BARON_NASHOR | +INNER_TURRET | -KILLS | +DRAGON | +INHIBITOR | +BASE_TURRET | +INHIBITOR | -KILLS | -BARON_NASHOR | +KILLS | ... | +NEXUS_TURRET | -KILLS | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 42 |
4 | 00405293fb859241 | +KILLS | -KILLS | -KILLS | -KILLS | -OUTER_TURRET | +OUTER_TURRET | -DRAGON | -KILLS | -OUTER_TURRET | -KILLS | -KILLS | -DRAGON | -OUTER_TURRET | +KILLS | -KILLS | -DRAGON | +OUTER_TURRET | +KILLS | +KILLS | -KILLS | +OUTER_TURRET | +DRAGON | +BARON_NASHOR | +KILLS | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | +KILLS | +INNER_TURRET | +KILLS | +BASE_TURRET | +INHIBITOR | -KILLS | +KILLS | +INNER_TURRET | +NEXUS_TURRET | +NEXUS_TURRET | +KILLS | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 39 |
5 | 00416ed438e29f14 | -KILLS | +KILLS | -KILLS | -DRAGON | -KILLS | +OUTER_TURRET | -KILLS | +KILLS | +KILLS | +DRAGON | -OUTER_TURRET | -OUTER_TURRET | +OUTER_TURRET | +KILLS | +KILLS | +BARON_NASHOR | -DRAGON | +OUTER_TURRET | -KILLS | +INNER_TURRET | +INNER_TURRET | -DRAGON | +BARON_NASHOR | +KILLS | +BASE_TURRET | -KILLS | -KILLS | -INNER_TURRET | +INHIBITOR | +KILLS | +INNER_TURRET | +BASE_TURRET | +BASE_TURRET | +INHIBITOR | -KILLS | +KILLS | -ELDER_DRAGON | +NEXUS_TURRET | +NEXUS_TURRET | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 41 |
6 | 007802c051352561 | -KILLS | +KILLS | +DRAGON | +KILLS | +KILLS | +RIFT_HERALD | -OUTER_TURRET | -OUTER_TURRET | +OUTER_TURRET | +OUTER_TURRET | +INNER_TURRET | -INNER_TURRET | -KILLS | -DRAGON | +OUTER_TURRET | -KILLS | +KILLS | +DRAGON | +INNER_TURRET | +DRAGON | -KILLS | -OUTER_TURRET | +KILLS | +BARON_NASHOR | -KILLS | +KILLS | +KILLS | +ELDER_DRAGON | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | +BARON_NASHOR | +BASE_TURRET | -KILLS | +KILLS | +INHIBITOR | +KILLS | +NEXUS_TURRET | +NEXUS_TURRET | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 44 |
7 | 0091705b03924485 | -KILLS | -KILLS | -OUTER_TURRET | -KILLS | -KILLS | -OUTER_TURRET | +DRAGON | -RIFT_HERALD | -OUTER_TURRET | -KILLS | -INNER_TURRET | -DRAGON | -KILLS | -INNER_TURRET | -BARON_NASHOR | -KILLS | -BASE_TURRET | -BASE_TURRET | +INHIBITOR | +INHIBITOR | -KILLS | -NEXUS_TURRET | -NEXUS_TURRET | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 0 | 27 |
8 | 00986b51908a63c3 | -KILLS | +KILLS | +KILLS | +KILLS | +KILLS | +KILLS | -OUTER_TURRET | +OUTER_TURRET | +DRAGON | +OUTER_TURRET | -OUTER_TURRET | +INNER_TURRET | +KILLS | +OUTER_TURRET | +INNER_TURRET | +DRAGON | +KILLS | -KILLS | -OUTER_TURRET | +DRAGON | -KILLS | -BARON_NASHOR | +KILLS | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | -KILLS | -KILLS | -ELDER_DRAGON | +KILLS | +BASE_TURRET | -KILLS | -KILLS | +INHIBITOR | -BARON_NASHOR | -INNER_TURRET | +KILLS | +INHIBITOR | +BASE_TURRET | ... | +INHIBITOR | +ELDER_DRAGON | +KILLS | -KILLS | -INNER_TURRET | +KILLS | +INHIBITOR | +KILLS | -KILLS | +NEXUS_TURRET | -BARON_NASHOR | -KILLS | -KILLS | -ELDER_DRAGON | -BASE_TURRET | +INHIBITOR | +INHIBITOR | +NEXUS_TURRET | -KILLS | -KILLS | -NEXUS_TURRET | -NEXUS_TURRET | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 0 | 69 |
9 | 00b13dbf1bd7aff0 | -KILLS | +KILLS | +OUTER_TURRET | -OUTER_TURRET | +DRAGON | -KILLS | +DRAGON | +OUTER_TURRET | -OUTER_TURRET | +OUTER_TURRET | -KILLS | +KILLS | -KILLS | -DRAGON | +KILLS | +BARON_NASHOR | -KILLS | -OUTER_TURRET | -INNER_TURRET | -BASE_TURRET | +DRAGON | -KILLS | +KILLS | +INHIBITOR | -NEXUS_TURRET | -KILLS | -NEXUS_TURRET | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 0 | 36 |
In [28]:
RedMatchEvents[['RedEvent1','id']].groupby('RedEvent1').count()
Out[28]:
id | |
---|---|
RedEvent1 | |
+DRAGON | 158 |
+KILLS | 1931 |
+OUTER_TURRET | 263 |
+RIFT_HERALD | 7 |
-DRAGON | 108 |
-KILLS | 2136 |
-OUTER_TURRET | 302 |
-RIFT_HERALD | 10 |
In [29]:
RedMatchEvents[['RedEvent1','MatchLength']].groupby('RedEvent1').mean()
Out[29]:
MatchLength | |
---|---|
RedEvent1 | |
+DRAGON | 38.278481 |
+KILLS | 36.599689 |
+OUTER_TURRET | 37.680608 |
+RIFT_HERALD | 39.428571 |
-DRAGON | 37.750000 |
-KILLS | 36.265918 |
-OUTER_TURRET | 38.049669 |
-RIFT_HERALD | 41.500000 |
In [30]:
sns.boxplot(RedMatchEvents['RedEvent1'],RedMatchEvents['MatchLength'],RedMatchEvents['RedResult'], boxprops=dict(alpha=.7) ) plt.xticks(rotation=45) plt.title('Distribution of Match Length by First Event and Match Result (Win = 1, Loss = 0)') plt.ylim(0,100) plt.xlabel('Event 1') plt.plot([1.5, 1.5], [0, 100],'k', linewidth=2,alpha=0.8 ) plt.plot([3.5, 3.5], [0, 100],'k', linewidth=2,alpha=0.8 ) plt.plot([5.5, 5.5], [0, 100],'k', linewidth=2,alpha=0.8 ) plt.show()
In [31]:
# We can now use this to calculate some conditional probabilities as shown TestData = RedMatchEvents PwinGivenFirstBloodWon = ( (len(TestData[(TestData['RedEvent1']=="+KILLS")&(TestData['RedResult']==1)])/len(TestData))/ (len( TestData[TestData['RedEvent1']=="+KILLS"])/len(TestData)) ) PwinGivenFirstBloodLost = ( (len(TestData[(TestData['RedEvent1']=="-KILLS")&(TestData['RedResult']==1)])/len(TestData))/ (len( TestData[TestData['RedEvent1']=="-KILLS"])/len(TestData)) ) PwinGivenFirstTowerWon = ( (len(TestData[(TestData['RedEvent1']=="+OUTER_TURRET")&(TestData['RedResult']==1)])/len(TestData))/ (len( TestData[TestData['RedEvent1']=="+OUTER_TURRET"])/len(TestData)) ) PwinGivenFirstTowerLost = ( (len(TestData[(TestData['RedEvent1']=="-OUTER_TURRET")&(TestData['RedResult']==1)])/len(TestData))/ (len( TestData[TestData['RedEvent1']=="-OUTER_TURRET"])/len(TestData)) ) PwinGivenFirstDragonWon = ( (len(TestData[(TestData['RedEvent1']=="+DRAGON")&(TestData['RedResult']==1)])/len(TestData))/ (len( TestData[TestData['RedEvent1']=="+DRAGON"])/len(TestData)) ) PwinGivenFirstDragonLost = ( (len(TestData[(TestData['RedEvent1']=="-DRAGON")&(TestData['RedResult']==1)])/len(TestData))/ (len( TestData[TestData['RedEvent1']=="-DRAGON"])/len(TestData)) ) PwinGivenFirstRiftHeraldWon = ( (len(TestData[(TestData['RedEvent1']=="+RIFT_HERALD")&(TestData['RedResult']==1)])/len(TestData))/ (len( TestData[TestData['RedEvent1']=="+RIFT_HERALD"])/len(TestData)) ) PwinGivenFirstRiftHeraldLost = ( (len(TestData[(TestData['RedEvent1']=="-RIFT_HERALD")&(TestData['RedResult']==1)])/len(TestData))/ (len( TestData[TestData['RedEvent1']=="-RIFT_HERALD"])/len(TestData)) ) print("-------FIRST BLOOD--------------------------------") print("P(Won | First Blood Taken):",PwinGivenFirstBloodWon) print("P(Won | First Blood Lost):",PwinGivenFirstBloodLost) print("") print("-------FIRST TURRET-------------------------------") print("P(Won | First Tower Won):",PwinGivenFirstTowerWon) print("P(Won | First Tower Lost):",PwinGivenFirstTowerLost) print("") print("-------FIRST DRAGON-------------------------------") print("P(Won | First Dragon Won):",PwinGivenFirstDragonWon) print("P(Won | First Dragon Lost):",PwinGivenFirstDragonLost) print("") print("-------FIRST RIFT HERALD (NOTE: ONLY 17 GAMES)----") print("P(Won | First Rift Herald Won):",PwinGivenFirstRiftHeraldWon) print("P(Won | First Rift Herald Lost):",PwinGivenFirstRiftHeraldLost)
-------FIRST BLOOD-------------------------------- P(Won | First Blood Taken): 0.5535991714137752 P(Won | First Blood Lost): 0.3647003745318352 -------FIRST TURRET------------------------------- P(Won | First Tower Won): 0.4790874524714828 P(Won | First Tower Lost): 0.4470198675496689 -------FIRST DRAGON------------------------------- P(Won | First Dragon Won): 0.5189873417721519 P(Won | First Dragon Lost): 0.4351851851851851 -------FIRST RIFT HERALD (NOTE: ONLY 17 GAMES)---- P(Won | First Rift Herald Won): 0.5714285714285714 P(Won | First Rift Herald Lost): 0.1
In [32]:
aggs = {'id':'count','MatchLength':'mean'} RedMatchTWOEvents = (RedMatchEvents[['RedEvent1','RedEvent2','RedResult','id','MatchLength']].groupby( ['RedEvent1','RedEvent2','RedResult']).agg(aggs).reset_index()) RedMatchTWOEvents = RedMatchTWOEvents.sort_values(['RedEvent1','RedEvent2','RedResult']) RedMatchTWOEventsWINS = RedMatchTWOEvents[RedMatchTWOEvents['RedResult']==1] RedMatchTWOEventsLOSS = RedMatchTWOEvents[RedMatchTWOEvents['RedResult']==0]
In [33]:
# First merge the RedWin and RedLoss data tables # Then remove events which only resulted in a win then calculate the total number of games that has these two events # Use this total to calculate the prob of win and loss respectively RedMatchTWOEventsMERGED = RedMatchTWOEventsWINS.merge(RedMatchTWOEventsLOSS, how='left',on=['RedEvent1','RedEvent2']) RedMatchTWOEventsMERGED = RedMatchTWOEventsMERGED[RedMatchTWOEventsMERGED['id_y']>0] RedMatchTWOEventsMERGED['Total'] = RedMatchTWOEventsMERGED['id_x']+RedMatchTWOEventsMERGED['id_y'] RedMatchTWOEventsMERGED['ProbWIN'] = RedMatchTWOEventsMERGED['id_x']/RedMatchTWOEventsMERGED['Total'].sum() RedMatchTWOEventsMERGED['ProbLOSS'] = RedMatchTWOEventsMERGED['id_y']/RedMatchTWOEventsMERGED['Total'].sum() RedMatchTWOEventsMERGED['ProbE1ANDE2'] = RedMatchTWOEventsMERGED['Total']/(RedMatchTWOEventsMERGED['Total'].sum()) RedMatchTWOEventsMERGED['ProbWINgivenE1ANDE2'] = RedMatchTWOEventsMERGED['ProbWIN']/RedMatchTWOEventsMERGED['ProbE1ANDE2'] RedMatchTWOEventsMERGED['ProbLOSSgivenE1ANDE2'] = RedMatchTWOEventsMERGED['ProbLOSS']/RedMatchTWOEventsMERGED['ProbE1ANDE2'] # Create column to single binary digit for whether the first event is positive or negative RedMatchTWOEventsMERGED['RedEvent1Gain'] = np.where( (RedMatchTWOEventsMERGED['RedEvent1']=="+KILLS") | (RedMatchTWOEventsMERGED['RedEvent1']=="+OUTER_TURRET") | (RedMatchTWOEventsMERGED['RedEvent1']=="+DRAGON") | (RedMatchTWOEventsMERGED['RedEvent1']=="+RIFT_HERALD") ,1,0 ) # Repeat for second event RedMatchTWOEventsMERGED['RedEvent2Gain'] = np.where( (RedMatchTWOEventsMERGED['RedEvent2']=="+KILLS") | (RedMatchTWOEventsMERGED['RedEvent2']=="+OUTER_TURRET") | (RedMatchTWOEventsMERGED['RedEvent2']=="+DRAGON") | (RedMatchTWOEventsMERGED['RedEvent2']=="+RIFT_HERALD") ,1,0 ) # Create another column for combination of first and second event outcomes classification RedMatchTWOEventsMERGED['Event1AND2Outcome'] = np.where( (RedMatchTWOEventsMERGED['RedEvent1Gain']==1)&(RedMatchTWOEventsMERGED['RedEvent2Gain']==1),"Both Positive", np.where( (((RedMatchTWOEventsMERGED['RedEvent1Gain']==1)&(RedMatchTWOEventsMERGED['RedEvent2Gain']==0))| ((RedMatchTWOEventsMERGED['RedEvent1Gain']==0)&(RedMatchTWOEventsMERGED['RedEvent2Gain']==1))),"One Positive", np.where( (RedMatchTWOEventsMERGED['RedEvent1Gain']==0)&(RedMatchTWOEventsMERGED['RedEvent2Gain']==0),"Neither Positive", "MISSING",))) # Sort by highest probability of win to lowest RedMatchTWOEventsMERGED = RedMatchTWOEventsMERGED.sort_values('ProbWINgivenE1ANDE2',ascending=False) # Remove event combination with less than x number of games to remove possible outliers RedMatchTWOEventsMERGED = RedMatchTWOEventsMERGED[RedMatchTWOEventsMERGED['Total']>=0] RedMatchTWOEventsMERGED.head(5)
Out[33]:
RedEvent1 | RedEvent2 | RedResult_x | id_x | MatchLength_x | RedResult_y | id_y | MatchLength_y | Total | ProbWIN | ProbLOSS | ProbE1ANDE2 | ProbWINgivenE1ANDE2 | ProbLOSSgivenE1ANDE2 | RedEvent1Gain | RedEvent2Gain | Event1AND2Outcome | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
16 | +OUTER_TURRET | +KILLS | 1 | 11 | 38.181818 | 0.0 | 2.0 | 34.50 | 13.0 | 0.002248 | 0.000409 | 0.002656 | 0.846154 | 0.153846 | 1 | 1 | Both Positive |
9 | +KILLS | +RIFT_HERALD | 1 | 4 | 31.750000 | 0.0 | 1.0 | 33.00 | 5.0 | 0.000817 | 0.000204 | 0.001022 | 0.800000 | 0.200000 | 1 | 1 | Both Positive |
1 | +DRAGON | +OUTER_TURRET | 1 | 11 | 37.636364 | 0.0 | 4.0 | 41.75 | 15.0 | 0.002248 | 0.000817 | 0.003065 | 0.733333 | 0.266667 | 1 | 1 | Both Positive |
21 | +RIFT_HERALD | -DRAGON | 1 | 2 | 36.500000 | 0.0 | 1.0 | 32.00 | 3.0 | 0.000409 | 0.000204 | 0.000613 | 0.666667 | 0.333333 | 1 | 0 | One Positive |
20 | +RIFT_HERALD | +KILLS | 1 | 2 | 36.000000 | 0.0 | 1.0 | 33.00 | 3.0 | 0.000409 | 0.000204 | 0.000613 | 0.666667 | 0.333333 | 1 | 1 | Both Positive |
In [34]:
sns.pairplot(data = RedMatchTWOEventsMERGED, x_vars='ProbWINgivenE1ANDE2',y_vars='MatchLength_x', hue= 'Event1AND2Outcome', size=8) plt.title('Probability of Winning Given the First Two Events against Average Game Duration, \n Coloured by Event 1 and 2 Outcomes') plt.xlabel('Probability of Win GIVEN First Two Events') plt.ylabel('Average Game Length') plt.xlim([0,1]) plt.xticks(np.arange(0,1.1,0.1)) #plt.ylim([20,50]) plt.show()
Markov Decision Process (MDP)
We could calculate the conditional probabilities for more events but, as had already become a challenge, the calculation process would be increasingly complicated. Therefore, instead of this, we can model our data as an MDP where we create pairwise probabilities between the events. Each event stage is a state and we calculate the probability of going to the next state given we are in the current one at that event stage.
In [35]:
RedMatchEvents.head()
Out[35]:
id | RedEvent1 | RedEvent2 | RedEvent3 | RedEvent4 | RedEvent5 | RedEvent6 | RedEvent7 | RedEvent8 | RedEvent9 | RedEvent10 | RedEvent11 | RedEvent12 | RedEvent13 | RedEvent14 | RedEvent15 | RedEvent16 | RedEvent17 | RedEvent18 | RedEvent19 | RedEvent20 | RedEvent21 | RedEvent22 | RedEvent23 | RedEvent24 | RedEvent25 | RedEvent26 | RedEvent27 | RedEvent28 | RedEvent29 | RedEvent30 | RedEvent31 | RedEvent32 | RedEvent33 | RedEvent34 | RedEvent35 | RedEvent36 | RedEvent37 | RedEvent38 | RedEvent39 | ... | RedEvent42 | RedEvent43 | RedEvent44 | RedEvent45 | RedEvent46 | RedEvent47 | RedEvent48 | RedEvent49 | RedEvent50 | RedEvent51 | RedEvent52 | RedEvent53 | RedEvent54 | RedEvent55 | RedEvent56 | RedEvent57 | RedEvent58 | RedEvent59 | RedEvent60 | RedEvent61 | RedEvent62 | RedEvent63 | RedEvent64 | RedEvent65 | RedEvent66 | RedEvent67 | RedEvent68 | RedEvent69 | RedEvent70 | RedEvent71 | RedEvent72 | RedEvent73 | RedEvent74 | RedEvent75 | RedEvent76 | RedEvent77 | RedEvent78 | RedEvent79 | RedResult | MatchLength | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0001f4374a03c133 | +KILLS | +KILLS | -KILLS | +KILLS | +OUTER_TURRET | -OUTER_TURRET | +DRAGON | +RIFT_HERALD | +OUTER_TURRET | -OUTER_TURRET | +KILLS | +DRAGON | +KILLS | -KILLS | +OUTER_TURRET | +KILLS | +KILLS | -KILLS | +BARON_NASHOR | +DRAGON | +INNER_TURRET | +INNER_TURRET | +INNER_TURRET | +DRAGON | -KILLS | +KILLS | +KILLS | +BASE_TURRET | +INHIBITOR | +NEXUS_TURRET | +NEXUS_TURRET | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 34 |
1 | 0016710a48fdd46d | -KILLS | +KILLS | +DRAGON | +KILLS | -KILLS | -OUTER_TURRET | +KILLS | -DRAGON | -KILLS | +KILLS | +KILLS | -KILLS | +OUTER_TURRET | -OUTER_TURRET | -DRAGON | -KILLS | +KILLS | -OUTER_TURRET | +KILLS | +OUTER_TURRET | -KILLS | +KILLS | +OUTER_TURRET | -KILLS | +KILLS | -KILLS | +KILLS | -DRAGON | +KILLS | +BARON_NASHOR | +KILLS | +INNER_TURRET | +INNER_TURRET | +INNER_TURRET | -KILLS | +KILLS | +BASE_TURRET | -KILLS | +INHIBITOR | ... | +KILLS | +NEXUS_TURRET | +NEXUS_TURRET | -KILLS | -KILLS | -DRAGON | +KILLS | +INHIBITOR | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 40 |
2 | 0016c9df37278448 | -KILLS | -KILLS | -KILLS | -OUTER_TURRET | -DRAGON | -KILLS | +KILLS | -KILLS | -RIFT_HERALD | +OUTER_TURRET | -OUTER_TURRET | -DRAGON | +KILLS | -DRAGON | -KILLS | -OUTER_TURRET | +KILLS | +BARON_NASHOR | +OUTER_TURRET | +DRAGON | +KILLS | +OUTER_TURRET | +INNER_TURRET | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | +INNER_TURRET | +BASE_TURRET | +BASE_TURRET | +INHIBITOR | +NEXUS_TURRET | +NEXUS_TURRET | -KILLS | +KILLS | +INHIBITOR | -nan | -nan | -nan | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 40 |
3 | 0021b45647424cd5 | -KILLS | +KILLS | +KILLS | +KILLS | -KILLS | +DRAGON | +RIFT_HERALD | -KILLS | +OUTER_TURRET | -KILLS | +OUTER_TURRET | -KILLS | +DRAGON | +KILLS | +KILLS | +OUTER_TURRET | -OUTER_TURRET | +KILLS | +BARON_NASHOR | -KILLS | +DRAGON | +INNER_TURRET | +KILLS | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | -KILLS | +KILLS | +NEXUS_TURRET | +BARON_NASHOR | +INNER_TURRET | -KILLS | +DRAGON | +INHIBITOR | +BASE_TURRET | +INHIBITOR | -KILLS | -BARON_NASHOR | +KILLS | ... | +NEXUS_TURRET | -KILLS | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 42 |
4 | 00405293fb859241 | +KILLS | -KILLS | -KILLS | -KILLS | -OUTER_TURRET | +OUTER_TURRET | -DRAGON | -KILLS | -OUTER_TURRET | -KILLS | -KILLS | -DRAGON | -OUTER_TURRET | +KILLS | -KILLS | -DRAGON | +OUTER_TURRET | +KILLS | +KILLS | -KILLS | +OUTER_TURRET | +DRAGON | +BARON_NASHOR | +KILLS | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | +KILLS | +INNER_TURRET | +KILLS | +BASE_TURRET | +INHIBITOR | -KILLS | +KILLS | +INNER_TURRET | +NEXUS_TURRET | +NEXUS_TURRET | +KILLS | -nan | ... | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | -nan | 1 | 39 |
In [36]:
# WARNING: Takes a while to run # Replace all N/As with the match outcome so that our final state is either a Win or Loss for i in range(1,80): RedMatchEvents['RedEvent'+str(i)] = RedMatchEvents['RedEvent'+str(i)].replace('-nan',RedMatchEvents['RedResult'].astype(str)) RedMatchEvents['RedEvent'+str(i)] = RedMatchEvents['RedEvent'+str(i)].replace('+nan',RedMatchEvents['RedResult'].astype(str)) #Print i for progress tracking #print(i) RedMatchEvents.head()
Out[36]:
id | RedEvent1 | RedEvent2 | RedEvent3 | RedEvent4 | RedEvent5 | RedEvent6 | RedEvent7 | RedEvent8 | RedEvent9 | RedEvent10 | RedEvent11 | RedEvent12 | RedEvent13 | RedEvent14 | RedEvent15 | RedEvent16 | RedEvent17 | RedEvent18 | RedEvent19 | RedEvent20 | RedEvent21 | RedEvent22 | RedEvent23 | RedEvent24 | RedEvent25 | RedEvent26 | RedEvent27 | RedEvent28 | RedEvent29 | RedEvent30 | RedEvent31 | RedEvent32 | RedEvent33 | RedEvent34 | RedEvent35 | RedEvent36 | RedEvent37 | RedEvent38 | RedEvent39 | ... | RedEvent42 | RedEvent43 | RedEvent44 | RedEvent45 | RedEvent46 | RedEvent47 | RedEvent48 | RedEvent49 | RedEvent50 | RedEvent51 | RedEvent52 | RedEvent53 | RedEvent54 | RedEvent55 | RedEvent56 | RedEvent57 | RedEvent58 | RedEvent59 | RedEvent60 | RedEvent61 | RedEvent62 | RedEvent63 | RedEvent64 | RedEvent65 | RedEvent66 | RedEvent67 | RedEvent68 | RedEvent69 | RedEvent70 | RedEvent71 | RedEvent72 | RedEvent73 | RedEvent74 | RedEvent75 | RedEvent76 | RedEvent77 | RedEvent78 | RedEvent79 | RedResult | MatchLength | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0001f4374a03c133 | +KILLS | +KILLS | -KILLS | +KILLS | +OUTER_TURRET | -OUTER_TURRET | +DRAGON | +RIFT_HERALD | +OUTER_TURRET | -OUTER_TURRET | +KILLS | +DRAGON | +KILLS | -KILLS | +OUTER_TURRET | +KILLS | +KILLS | -KILLS | +BARON_NASHOR | +DRAGON | +INNER_TURRET | +INNER_TURRET | +INNER_TURRET | +DRAGON | -KILLS | +KILLS | +KILLS | +BASE_TURRET | +INHIBITOR | +NEXUS_TURRET | +NEXUS_TURRET | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 34 |
1 | 0016710a48fdd46d | -KILLS | +KILLS | +DRAGON | +KILLS | -KILLS | -OUTER_TURRET | +KILLS | -DRAGON | -KILLS | +KILLS | +KILLS | -KILLS | +OUTER_TURRET | -OUTER_TURRET | -DRAGON | -KILLS | +KILLS | -OUTER_TURRET | +KILLS | +OUTER_TURRET | -KILLS | +KILLS | +OUTER_TURRET | -KILLS | +KILLS | -KILLS | +KILLS | -DRAGON | +KILLS | +BARON_NASHOR | +KILLS | +INNER_TURRET | +INNER_TURRET | +INNER_TURRET | -KILLS | +KILLS | +BASE_TURRET | -KILLS | +INHIBITOR | ... | +KILLS | +NEXUS_TURRET | +NEXUS_TURRET | -KILLS | -KILLS | -DRAGON | +KILLS | +INHIBITOR | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 40 |
2 | 0016c9df37278448 | -KILLS | -KILLS | -KILLS | -OUTER_TURRET | -DRAGON | -KILLS | +KILLS | -KILLS | -RIFT_HERALD | +OUTER_TURRET | -OUTER_TURRET | -DRAGON | +KILLS | -DRAGON | -KILLS | -OUTER_TURRET | +KILLS | +BARON_NASHOR | +OUTER_TURRET | +DRAGON | +KILLS | +OUTER_TURRET | +INNER_TURRET | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | +INNER_TURRET | +BASE_TURRET | +BASE_TURRET | +INHIBITOR | +NEXUS_TURRET | +NEXUS_TURRET | -KILLS | +KILLS | +INHIBITOR | 1 | 1 | 1 | 1 | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 40 |
3 | 0021b45647424cd5 | -KILLS | +KILLS | +KILLS | +KILLS | -KILLS | +DRAGON | +RIFT_HERALD | -KILLS | +OUTER_TURRET | -KILLS | +OUTER_TURRET | -KILLS | +DRAGON | +KILLS | +KILLS | +OUTER_TURRET | -OUTER_TURRET | +KILLS | +BARON_NASHOR | -KILLS | +DRAGON | +INNER_TURRET | +KILLS | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | -KILLS | +KILLS | +NEXUS_TURRET | +BARON_NASHOR | +INNER_TURRET | -KILLS | +DRAGON | +INHIBITOR | +BASE_TURRET | +INHIBITOR | -KILLS | -BARON_NASHOR | +KILLS | ... | +NEXUS_TURRET | -KILLS | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 42 |
4 | 00405293fb859241 | +KILLS | -KILLS | -KILLS | -KILLS | -OUTER_TURRET | +OUTER_TURRET | -DRAGON | -KILLS | -OUTER_TURRET | -KILLS | -KILLS | -DRAGON | -OUTER_TURRET | +KILLS | -KILLS | -DRAGON | +OUTER_TURRET | +KILLS | +KILLS | -KILLS | +OUTER_TURRET | +DRAGON | +BARON_NASHOR | +KILLS | +INNER_TURRET | +BASE_TURRET | +INHIBITOR | +KILLS | +INNER_TURRET | +KILLS | +BASE_TURRET | +INHIBITOR | -KILLS | +KILLS | +INNER_TURRET | +NEXUS_TURRET | +NEXUS_TURRET | +KILLS | 1 | ... | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 39 |
In [37]:
RedMatchEvents[['RedEvent60','id']].groupby('RedEvent60').count()
Out[37]:
id | |
---|---|
RedEvent60 | |
+BARON_NASHOR | 4 |
+BASE_TURRET | 2 |
+ELDER_DRAGON | 1 |
+INHIBITOR | 12 |
+INNER_TURRET | 2 |
+KILLS | 7 |
+NEXUS_TURRET | 5 |
-BARON_NASHOR | 1 |
-BASE_TURRET | 3 |
-ELDER_DRAGON | 2 |
-KILLS | 19 |
-NEXUS_TURRET | 12 |
0 | 2629 |
1 | 2216 |
In [38]:
RedMatchEvents2 = RedMatchEvents
In [39]:
# WARNING: Takes a little while to run EventList = [ #Positive Events '+KILLS', '+OUTER_TURRET', '+DRAGON', '+RIFT_HERALD', '+BARON_NASHOR', '+INNER_TURRET', '+BASE_TURRET', '+INHIBITOR', '+NEXUS_TURRET', '+ELDER_DRAGON', #Negative Events '-KILLS', '-OUTER_TURRET', '-DRAGON', '-RIFT_HERALD', '-BARON_NASHOR', '-INNER_TURRET', '-BASE_TURRET', '-INHIBITOR', '-NEXUS_TURRET', '-ELDER_DRAGON', #Game Win or Loss Events '1','0'] RedMatchMDP = pd.DataFrame() for i in range(1,79): Event = i for j1 in range(0,len(EventList)): Event1 = EventList[j1] for j2 in range(0,len(EventList)): Event2 = EventList[j2] if len(RedMatchEvents2[(RedMatchEvents2['RedEvent'+str(Event)]==Event1)])==0: continue #elif len(RedMatchEvents2[(RedMatchEvents2['RedEvent'+str(Event)]==Event1)& # (RedMatchEvents2['RedEvent'+str(Event+1)]==Event2) ])==0: continue else: TransProb = ( len(RedMatchEvents2[(RedMatchEvents2['RedEvent'+str(Event)]==Event1)& (RedMatchEvents2['RedEvent'+str(Event+1)]==Event2) ])/ len(RedMatchEvents2[(RedMatchEvents2['RedEvent'+str(Event)]==Event1)]) ) RedMatchMDP2 = pd.DataFrame({'StartState':Event,'EndState':Event+1,'Event1':Event1,'Event2':Event2,'Probability':TransProb}, index=[0]) RedMatchMDP = RedMatchMDP.append(RedMatchMDP2) #Print i for tracking progress #print(i)
In [40]:
RedMatchMDP = RedMatchMDP[['StartState','EndState','Event1','Event2','Probability']] RedMatchMDP[(RedMatchMDP['StartState']==61)&(RedMatchMDP['Event1']=="+INHIBITOR")]
Out[40]:
StartState | EndState | Event1 | Event2 | Probability | |
---|---|---|---|---|---|
0 | 61 | 62 | +INHIBITOR | +KILLS | 0.076923 |
0 | 61 | 62 | +INHIBITOR | +OUTER_TURRET | 0.000000 |
0 | 61 | 62 | +INHIBITOR | +DRAGON | 0.000000 |
0 | 61 | 62 | +INHIBITOR | +RIFT_HERALD | 0.000000 |
0 | 61 | 62 | +INHIBITOR | +BARON_NASHOR | 0.153846 |
0 | 61 | 62 | +INHIBITOR | +INNER_TURRET | 0.076923 |
0 | 61 | 62 | +INHIBITOR | +BASE_TURRET | 0.000000 |
0 | 61 | 62 | +INHIBITOR | +INHIBITOR | 0.076923 |
0 | 61 | 62 | +INHIBITOR | +NEXUS_TURRET | 0.153846 |
0 | 61 | 62 | +INHIBITOR | +ELDER_DRAGON | 0.000000 |
0 | 61 | 62 | +INHIBITOR | -KILLS | 0.076923 |
0 | 61 | 62 | +INHIBITOR | -OUTER_TURRET | 0.000000 |
0 | 61 | 62 | +INHIBITOR | -DRAGON | 0.000000 |
0 | 61 | 62 | +INHIBITOR | -RIFT_HERALD | 0.000000 |
0 | 61 | 62 | +INHIBITOR | -BARON_NASHOR | 0.153846 |
0 | 61 | 62 | +INHIBITOR | -INNER_TURRET | 0.000000 |
0 | 61 | 62 | +INHIBITOR | -BASE_TURRET | 0.000000 |
0 | 61 | 62 | +INHIBITOR | -INHIBITOR | 0.000000 |
0 | 61 | 62 | +INHIBITOR | -NEXUS_TURRET | 0.230769 |
0 | 61 | 62 | +INHIBITOR | -ELDER_DRAGON | 0.000000 |
0 | 61 | 62 | +INHIBITOR | 1 | 0.000000 |
0 | 61 | 62 | +INHIBITOR | 0 | 0.000000 |
In [41]:
EndCondition = RedMatchMDP[ ((RedMatchMDP['Event1']!="1")&(RedMatchMDP['Event2']=="1") )| ((RedMatchMDP['Event1']!="0")&(RedMatchMDP['Event2']=="0"))] EndCondition = EndCondition.sort_values('Probability',ascending=False) EndConditionGrouped = EndCondition[['StartState','Probability']].groupby('StartState').mean().reset_index() EndConditionGrouped['CumProb'] = EndConditionGrouped['Probability'].cumsum() EndConditionGrouped2 = EndCondition[['StartState','Probability']].groupby('StartState').sum().reset_index() EndConditionGrouped2['CumProb'] = EndConditionGrouped2['Probability'].cumsum() fig, axes = plt.subplots(nrows=2, ncols=2) axes[0,0].bar(EndConditionGrouped['StartState'],EndConditionGrouped['Probability'] ,alpha=0.3) axes[0,0].plot(EndConditionGrouped['StartState'],EndConditionGrouped['Probability']) axes[0,0].set_title('Mean Probability Dist') axes[0,0].set_xlabel("State") axes[0,0].set_ylabel("Probability of Ending") axes[0,0].set_xticks([],[]) axes[0,0].set_xlabel("") axes[0,0].set_xlim([0,80]) axes[0,0].grid(False) axes[0,1].bar(EndConditionGrouped['StartState'],EndConditionGrouped['CumProb'] ,alpha=0.3) axes[0,1].plot(EndConditionGrouped['StartState'],EndConditionGrouped['CumProb']) axes[0,1].set_title('Mean Cumulative Probability Dist') axes[0,1].set_xlabel("State") axes[0,1].set_ylabel("Cumlative Probability of Ending") axes[0,1].set_xticks([]) axes[0,1].set_xlabel("") axes[0,1].set_xlim([0,80]) axes[0,1].grid(False) axes[1,0].bar(EndConditionGrouped2['StartState'],EndConditionGrouped2['Probability'] ,alpha=0.3) axes[1,0].plot(EndConditionGrouped2['StartState'],EndConditionGrouped2['Probability']) axes[1,0].set_title('Sum Probability Dist') axes[1,0].set_xlabel("State") axes[1,0].set_ylabel("Probability of Ending") axes[1,0].set_xlim([0,80]) axes[1,0].grid(False) axes[1,1].bar(EndConditionGrouped2['StartState'],EndConditionGrouped2['CumProb'] ,alpha=0.3) axes[1,1].plot(EndConditionGrouped2['StartState'],EndConditionGrouped2['CumProb']) axes[1,1].set_title('Sum Cumulative Probability Dist') axes[1,1].set_xlabel("State") axes[1,1].set_ylabel("Cumlative Probability of Ending") axes[1,1].set_xlim([0,80]) axes[1,1].grid(False) fig.suptitle("Probability of Game Ending in Each State Averaged and Summed over Varying Start Events") fig.set_figheight(15) fig.set_figwidth(15) plt.show()
In [42]:
RedMatchMDP['Reward'] = 0 RedMatchMDP.head()
Out[42]:
StartState | EndState | Event1 | Event2 | Probability | Reward | |
---|---|---|---|---|---|---|
0 | 1 | 2 | +KILLS | +KILLS | 0.350596 | 0 |
0 | 1 | 2 | +KILLS | +OUTER_TURRET | 0.058519 | 0 |
0 | 1 | 2 | +KILLS | +DRAGON | 0.076126 | 0 |
0 | 1 | 2 | +KILLS | +RIFT_HERALD | 0.002589 | 0 |
0 | 1 | 2 | +KILLS | +BARON_NASHOR | 0.000000 | 0 |
In [43]:
len(RedMatchMDP)
Out[43]:
25564
In [44]:
RedMatchMDP[(RedMatchMDP['StartState']==15)&(RedMatchMDP['Event1']=="+ELDER_DRAGON")]
Out[44]:
StartState | EndState | Event1 | Event2 | Probability | Reward | |
---|---|---|---|---|---|---|
0 | 15 | 16 | +ELDER_DRAGON | +KILLS | 0.5 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | +OUTER_TURRET | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | +DRAGON | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | +RIFT_HERALD | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | +BARON_NASHOR | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | +INNER_TURRET | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | +BASE_TURRET | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | +INHIBITOR | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | +NEXUS_TURRET | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | +ELDER_DRAGON | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -KILLS | 0.5 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -OUTER_TURRET | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -DRAGON | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -RIFT_HERALD | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -BARON_NASHOR | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -INNER_TURRET | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -BASE_TURRET | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -INHIBITOR | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -NEXUS_TURRET | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | -ELDER_DRAGON | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | 1 | 0.0 | 0 |
0 | 15 | 16 | +ELDER_DRAGON | 0 | 0.0 | 0 |
Reinforcement Learning AI Model
Now that we have our data modelled as an MDP, we can apply Reinforcement Learning. In short, this applied a model that simulates thousands of games and learns how good or bad each decision is towards reaching a win given the team’s current position.
What makes this AI is its ability to learn from its own trial and error experience. It starts with zero knowledge about the game but, as it is rewarded for reaching a win and punished for reaching a loss, it begins to recognise and remember which decisions are better than others. Our first models start with no knowledge but I later demonstrate the impact initial information about decisions can be fed into the model to represent a person’s preferences.
So how is the model learning? In short, we use Monte Carlo learning whereby each episode is a simulation of a game based on our MDP probabilities and depending on the outcome for the team, our return will vary (+1 terminal reward for win and -1 terminal reward for loss). The value of each action taken in this episode is then updated accordingly based on whether the outcome was a win or loss.
In Monte Carlo learning, we have a parameter 'gamma' that discounts the rewards and will give a higher value to immediate steps than later one. In our model, this can be understood by the fact that as we reach later stages of the games, the decisions we make will have a much larger impact on the final outcome than those made in the first few minutes. For example, losing a team fight in minute 50 is much more likely to lead to a loss than losing a team fight in the first 5 minutes.
In [45]:
alpha = 0.1 gamma = 0.9 num_episodes = 100 epsilon = 0.1 reward = RedMatchMDP['Reward'] StartState = 1 StartEvent = '+KILLS' StartAction = '+OUTER_TURRET'
In [46]:
def MCModelv1(data, alpha, gamma, epsilon, reward, StartState, StartEvent, StartAction, num_episodes): # Initiatise variables appropiately data['V'] = 0 outcomes = pd.DataFrame() episode_return = pd.DataFrame() actions_output = pd.DataFrame() for e in range(0,num_episodes): action = [] current_state = StartState current_action = StartEvent next_action = StartAction actions = pd.DataFrame() for a in range(0,100): action_table = pd.DataFrame() if (current_action=="1") | (current_action=="0") | (current_state==79): continue else: data_e = data[(data['StartState']==current_state)&(data['Event1']==current_action)] data_e = data_e.sort_values('Probability') data_e['CumProb'] = data_e['Probability'].cumsum() data_e['CumProb'] = np.round(data_e['CumProb'],4) rng = np.round(np.random.random()*data_e['CumProb'].max(),4) action_table = data_e[ data_e['CumProb'] >= rng] action_table = action_table[ action_table['CumProb'] == action_table['CumProb'].min()] action_table = action_table.reset_index() action = action_table['Event2'][0] if action == "1": step_reward = 10*(gamma**a) elif action == "0": step_reward = -10*(gamma**a) else: step_reward = -0.005*(gamma**a) action_table['StepReward'] = step_reward action_table['Episode'] = e action_table['Action'] = a current_action = action current_state = current_state+1 actions = actions.append(action_table) actions_output = actions_output.append(actions) episode_return = actions['StepReward'].sum() actions['Return']= episode_return data = data.merge(actions[['StartState','EndState','Event1','Event2','Return']], how='left',on =['StartState','EndState','Event1','Event2']) data['Return'] = data['Return'].fillna(0) data['V'] = data['V'] + alpha*(data['Return']-data['V']) data = data.drop('Return', 1) if current_action=="1": outcome = "WIN" elif current_action=="0": outcome = "LOSS" else: outcome = "INCOMPLETE" outcome = pd.DataFrame({'Epsiode':[e],'Outcome':[outcome]}) outcomes = outcomes.append(outcome) optimal_policy_table = data[ ( data['StartState']==StartState) & (data['Event1']==StartEvent)&(data['Event2']==StartAction)] for i in range(2,79): optimal_V = data[data['StartState']==i]['V'].max() optimal_policy = data[ ( data['V']==optimal_V) & (data['StartState']==i)] optimal_policy_table = optimal_policy_table.append(optimal_policy) return(outcomes,actions_output,data,optimal_policy_table)
In [47]:
start_time = timeit.default_timer() Mdl = MCModelv1(data=RedMatchMDP, alpha = alpha, gamma=gamma, epsilon = epsilon, reward = reward, StartState=StartState, StartEvent=StartEvent,StartAction=StartAction, num_episodes = num_episodes) elapsed = timeit.default_timer() - start_time print("Time taken to run model:",np.round(elapsed/60,2),"mins")
Time taken to run model: 0.65 mins
In [48]:
Mdl[3].head()
Out[48]:
StartState | EndState | Event1 | Event2 | Probability | Reward | V | |
---|---|---|---|---|---|---|---|
1 | 1 | 2 | +KILLS | +OUTER_TURRET | 0.058519 | 0 | -0.000142 |
286 | 2 | 3 | -KILLS | +KILLS | 0.405299 | 0 | 0.055403 |
406 | 3 | 4 | +KILLS | -KILLS | 0.380066 | 0 | 0.027542 |
748 | 4 | 5 | -KILLS | +KILLS | 0.345982 | 0 | 0.062849 |
861 | 5 | 6 | +KILLS | +RIFT_HERALD | 0.012048 | 0 | 0.038553 |
RL Model V2
This is a good start but our first model requires the first action to be provided. Instead, we now repeat the process but enable it to calculate the optimal first action when none is given.
In [49]:
def MCModelv2(data, alpha, gamma, epsilon, reward, StartState, StartEvent, StartAction, num_episodes): # Initiatise variables appropiately data['V'] = 0 outcomes = pd.DataFrame() episode_return = pd.DataFrame() actions_output = pd.DataFrame() for e in range(0,num_episodes): action = [] current_state = StartState current_action = StartEvent actions = pd.DataFrame() for a in range(0,100): action_table = pd.DataFrame() if (current_action=="1") | (current_action=="0") | (current_state==79): continue else: data_e = data[(data['StartState']==current_state)&(data['Event1']==current_action)] data_e = data_e[data_e['Probability']>0] if (StartAction is None)&(a==0): random_first_action = data_e.sample() action_table = random_first_action action_table = action_table.reset_index() action = action_table['Event2'][0] elif (a==0): action_table = data_e[ data_e['Event2'] ==StartAction] action = StartAction else: data_e = data_e.sort_values('Probability') data_e['CumProb'] = data_e['Probability'].cumsum() data_e['CumProb'] = np.round(data_e['CumProb'],4) rng = np.round(np.random.random()*data_e['CumProb'].max(),4) action_table = data_e[ data_e['CumProb'] >= rng] action_table = action_table[ action_table['CumProb'] == action_table['CumProb'].min()] action_table = action_table.reset_index() action = action_table['Event2'][0] if action == "1": step_reward = 10*(gamma**a) elif action == "0": step_reward = -10*(gamma**a) else: step_reward = -0.005*(gamma**a) action_table['StepReward'] = step_reward action_table['Episode'] = e action_table['Action'] = a current_action = action current_state = current_state+1 actions = actions.append(action_table) actions_output = actions_output.append(actions) episode_return = actions['StepReward'].sum() actions['Return']= episode_return data = data.merge(actions[['StartState','EndState','Event1','Event2','Return']], how='left',on =['StartState','EndState','Event1','Event2']) data['Return'] = data['Return'].fillna(0) data['V'] = data['V'] + alpha*(data['Return']-data['V']) data = data.drop('Return', 1) if current_action=="1": outcome = "WIN" elif current_action=="0": outcome = "LOSS" else: outcome = "INCOMPLETE" outcome = pd.DataFrame({'Epsiode':[e],'Outcome':[outcome]}) outcomes = outcomes.append(outcome) if StartAction is None: optimal_policy_table = pd.DataFrame() for i in range(1,79): optimal_V = data[data['StartState']==i]['V'].max() optimal_policy = data[ ( data['V']==optimal_V) & (data['StartState']==i)] optimal_policy_table = optimal_policy_table.append(optimal_policy) else: optimal_policy_table = data[ ( data['StartState']==StartState) & (data['Event1']==StartEvent)&(data['Event2']==StartAction)] for i in range(2,79): optimal_V = data[data['StartState']==i]['V'].max() optimal_policy = data[ ( data['V']==optimal_V) & (data['StartState']==i)] optimal_policy_table = optimal_policy_table.append(optimal_policy) return(outcomes,actions_output,data,optimal_policy_table)
In [50]:
alpha = 0.1 gamma = 0.9 num_episodes = 100 epsilon = 0.1 reward = RedMatchMDP['Reward'] StartState = 1 StartEvent = '+KILLS' StartAction = None start_time = timeit.default_timer() Mdl2 = MCModelv2(data=RedMatchMDP, alpha = alpha, gamma=gamma, epsilon = epsilon, reward = reward, StartState=StartState, StartEvent=StartEvent,StartAction=None, num_episodes = num_episodes) elapsed = timeit.default_timer() - start_time print("Time taken to run model:",np.round(elapsed/60,2),"mins")
Time taken to run model: 1.24 mins
In [51]:
Mdl2[3].head(30)
Out[51]:
StartState | EndState | Event1 | Event2 | Probability | Reward | V | |
---|---|---|---|---|---|---|---|
11 | 1 | 2 | +KILLS | -OUTER_TURRET | 0.034697 | 0 | 0.059365 |
309 | 2 | 3 | -OUTER_TURRET | +OUTER_TURRET | 0.300847 | 0 | 0.056334 |
430 | 3 | 4 | +OUTER_TURRET | -DRAGON | 0.074447 | 0 | 0.055783 |
793 | 4 | 5 | -DRAGON | +OUTER_TURRET | 0.152104 | 0 | 0.055781 |
891 | 5 | 6 | +OUTER_TURRET | -OUTER_TURRET | 0.261941 | 0 | 0.055770 |
1288 | 6 | 7 | -OUTER_TURRET | -DRAGON | 0.110092 | 0 | 0.055765 |
1606 | 7 | 8 | -DRAGON | +KILLS | 0.265672 | 0 | 0.056417 |
1720 | 8 | 9 | +KILLS | +BARON_NASHOR | 0.005859 | 0 | 0.055783 |
2144 | 9 | 10 | +BARON_NASHOR | -KILLS | 0.312500 | 0 | 0.055783 |
2398 | 10 | 11 | +OUTER_TURRET | +KILLS | 0.185980 | 0 | 0.059142 |
2706 | 11 | 12 | +KILLS | +KILLS | 0.118577 | 0 | 0.058965 |
3244 | 12 | 13 | -OUTER_TURRET | -KILLS | 0.227920 | 0 | 0.055783 |
3596 | 13 | 14 | -KILLS | -KILLS | 0.121409 | 0 | 0.054589 |
3975 | 14 | 15 | -KILLS | -INNER_TURRET | 0.138376 | 0 | 0.074098 |
4168 | 15 | 16 | +KILLS | -KILLS | 0.297481 | 0 | 0.056211 |
4877 | 16 | 17 | -DRAGON | -INNER_TURRET | 0.158576 | 0 | 0.055783 |
5356 | 17 | 18 | -INNER_TURRET | -KILLS | 0.236324 | 0 | 0.055783 |
5698 | 18 | 19 | -KILLS | +KILLS | 0.266546 | 0 | 0.057560 |
5940 | 19 | 20 | +KILLS | +KILLS | 0.128205 | 0 | 0.058518 |
6414 | 20 | 21 | +KILLS | -DRAGON | 0.037569 | 0 | 0.055783 |
7128 | 21 | 22 | -DRAGON | +KILLS | 0.235741 | 0 | 0.056081 |
7346 | 22 | 23 | +KILLS | 1 | 0.002304 | 0 | 0.056324 |
7795 | 23 | 24 | +KILLS | +INHIBITOR | 0.049818 | 0 | 0.033658 |
8384 | 24 | 25 | +INHIBITOR | +DRAGON | 0.037037 | 0 | 0.035062 |
8717 | 25 | 26 | +DRAGON | +INNER_TURRET | 0.254777 | 0 | 0.035054 |
9196 | 26 | 27 | +INNER_TURRET | +KILLS | 0.230303 | 0 | 0.035203 |
9534 | 27 | 28 | +KILLS | +NEXUS_TURRET | 0.071124 | 0 | 0.035062 |
10162 | 28 | 29 | +NEXUS_TURRET | 1 | 0.280612 | 0 | 0.035062 |
10721 | 29 | 30 | -BASE_TURRET | +INHIBITOR | 0.576923 | 0 | 0.024197 |
10965 | 30 | 31 | +INHIBITOR | +ELDER_DRAGON | 0.016129 | 0 | 0.023902 |
RL Model V3
It quickly became apparent that our model was not following the structure of the game correctly because we had set no limitations on the number of turrets available to destroy on either team.
Therefore, it was taking more objectives than possible and so we now introduce a rule that removes the turrets, rift heralds and inhibitors after so many are taken by one team.
In [52]:
def MCModelv3(data, alpha, gamma, epsilon, reward, StartState, StartEvent, StartAction, num_episodes): # Initiatise variables appropiately data['V'] = 0 data_output = data outcomes = pd.DataFrame() episode_return = pd.DataFrame() actions_output = pd.DataFrame() for e in range(0,num_episodes): action = [] current_state = StartState current_action = StartEvent data_e1 = data actions = pd.DataFrame() for a in range(0,100): action_table = pd.DataFrame() if (current_action=="1") | (current_action=="0") | (current_state==79): continue else: if a==0: data_e1=data_e1 elif (len(individual_actions_count[individual_actions_count['Event2']=="+RIFT_HERALD"])==1): data_e1_e1 = data_e1[(data_e1['Event2']!='+RIFT_HERALD')|(data_e1['Event2']!='-RIFT_HERALD')] elif (len(individual_actions_count[individual_actions_count['Event2']=="-RIFT_HERALD"])==1): data_e1 = data_e1[(data_e1['Event2']!='+RIFT_HERALD')|(data_e1['Event2']!='-RIFT_HERALD')] elif (len(individual_actions_count[individual_actions_count['Event2']=="+OUTER_TURRET"])==3): data_e1 = data_e1[data_e1['Event2']!='+OUTER_TURRET'] elif (len(individual_actions_count[individual_actions_count['Event2']=="-OUTER_TURRET"])==3): data_e1 = data_e1[data_e1['Event2']!='-OUTER_TURRET'] elif (len(individual_actions_count[individual_actions_count['Event2']=="+INNER_TURRET"])==3): data_e1 = data_e1[data_e1['Event2']!='+INNER_TURRET'] elif (len(individual_actions_count[individual_actions_count['Event2']=="-INNER_TURRET"])==3): data_e1 = data_e1[data_e1['Event2']!='-INNER_TURRET'] elif (len(individual_actions_count[individual_actions_count['Event2']=="+BASE_TURRET"])==3): data_e1 = data_e1[data_e1['Event2']!='+BASE_TURRET'] elif (len(individual_actions_count[individual_actions_count['Event2']=="-BASE_TURRET"])==3): data_e1 = data_e1[data_e1['Event2']!='-BASE_TURRET'] elif (len(individual_actions_count[individual_actions_count['Event2']=="+INHIBITOR"])==3): data_e1 = data_e1[data_e1['Event2']!='+INHIBITOR'] elif (len(individual_actions_count[individual_actions_count['Event2']=="-INHIBITOR"])==3): data_e1 = data_e1[data_e1['Event2']!='-INHIBITOR'] elif (len(individual_actions_count[individual_actions_count['Event2']=="+NEXUS_TURRET"])==2): data_e1 = data_e1[data_e1['Event2']!='+NEXUS_TURRET'] elif (len(individual_actions_count[individual_actions_count['Event2']=="-NEXUS_TURRET"])==2): data_e1 = data_e1[data_e1['Event2']!='-NEXUS_TURRET'] else: data_e1 = data_e1 data_e = data_e1[(data_e1['StartState']==current_state)&(data_e1['Event1']==current_action)] data_e = data_e[data_e['Probability']>0] if (StartAction is None)&(a==0): random_first_action = data_e.sample() action_table = random_first_action action_table = action_table.reset_index() action = action_table['Event2'][0] elif (a==0): action_table = data_e[ data_e['Event2'] ==StartAction] action = StartAction else: data_e = data_e.sort_values('Probability') data_e['CumProb'] = data_e['Probability'].cumsum() data_e['CumProb'] = np.round(data_e['CumProb'],4) rng = np.round(np.random.random()*data_e['CumProb'].max(),4) action_table = data_e[ data_e['CumProb'] >= rng] action_table = action_table[ action_table['CumProb'] == action_table['CumProb'].min()] action_table = action_table.reset_index() action = action_table['Event2'][0] if action == "1": step_reward = 10*(gamma**a) elif action == "0": step_reward = -10*(gamma**a) else: step_reward = -0.005*(gamma**a) action_table['StepReward'] = step_reward action_table['Episode'] = e action_table['Action'] = a current_action = action current_state = current_state+1 actions = actions.append(action_table) individual_actions_count = actions actions_output = actions_output.append(actions) episode_return = actions['StepReward'].sum() actions['Return']= episode_return data_output = data_output.merge(actions[['StartState','EndState','Event1','Event2','Return']], how='left',on =['StartState','EndState','Event1','Event2']) data_output['Return'] = data_output['Return'].fillna(0) data_output['V'] = data_output['V'] + alpha*(data_output['Return']-data_output['V']) data_output = data_output.drop('Return', 1) if current_action=="1": outcome = "WIN" elif current_action=="0": outcome = "LOSS" else: outcome = "INCOMPLETE" outcome = pd.DataFrame({'Epsiode':[e],'Outcome':[outcome]}) outcomes = outcomes.append(outcome) optimal_policy_table = pd.DataFrame() if (StartAction is None): optimal_policy_table = data_output[ (data_output['StartState']==StartState)&(data_output['Event1']==StartEvent) & (data_output['V']==(data_output[(data_output['StartState']==StartState)&(data_output['Event1']==StartEvent)]['V'].max())) ] for i in range(2,79): optimal_V = data_output[(data_output['StartState']==i)]['V'].max() optimal_policy = data_output[ ( data_output['V']==optimal_V) & (data_output['StartState']==i)] optimal_policy_table = optimal_policy_table.append(optimal_policy) else: optimal_policy_table = data_output[ ( data_output['StartState']==StartState) & (data_output['Event1']==StartEvent)&(data_output['Event2']==StartAction)] for i in range(2,79): optimal_V = data_output[data_output['StartState']==i]['V'].max() optimal_policy = data_output[ ( data_output['V']==optimal_V) & (data_output['StartState']==i)] optimal_policy_table = optimal_policy_table.append(optimal_policy) if (StartAction is None): currentpath_action = StartEvent optimal_path = pd.DataFrame() for i in range(1,79): StartPathState = i nextpath_action = data_output [ (data_output['V'] == data_output[ (data_output['StartState']==StartPathState) & (data_output['Event1']==currentpath_action) ]['V'].max()) & (data_output['StartState']==StartPathState) & (data_output['Event1']==currentpath_action) ] if (nextpath_action['V'].max()==0): break else: nextpath_action = nextpath_action.reset_index(drop=True) currentpath_action = nextpath_action['Event2'][0] optimal_path = optimal_path.append(nextpath_action) else: currentpath_action = StartEvent optimal_path = data_output[(data_output['StartState']==StartPathState) & (data_output['Event1']==currentpath_action) & (data_output['Event2']==StartAction) ] for i in range(2,79): StartPathState = i nextpath_action = data_output [ (data_output['V'] == data_output[ (data_output['StartState']==StartPathState) & (data_output['Event1']==currentpath_action) ]['V'].max()) & (data_output['StartState']==StartPathState) & (data_output['Event1']==currentpath_action) ] if (nextpath_action['V'].max()==0): break else: nextpath_action = nextpath_action.reset_index(drop=True) currentpath_action = nextpath_action['Event2'][0] optimal_path = optimal_path.append(nextpath_action) return(outcomes,actions_output,data_output,optimal_policy_table,optimal_path)
In [53]:
alpha = 0.1 gamma = 0.9 num_episodes = 100 epsilon = 0.1 reward = RedMatchMDP['Reward'] StartState = 1 StartEvent = '+KILLS' StartAction = None start_time = timeit.default_timer() Mdl3 = MCModelv3(data=RedMatchMDP, alpha = alpha, gamma=gamma, epsilon = epsilon, reward = reward, StartState=StartState, StartEvent=StartEvent,StartAction=StartAction, num_episodes = num_episodes) elapsed = timeit.default_timer() - start_time print("Time taken to run model:",np.round(elapsed/60,2),"mins") print("Avg Time taken per episode:", np.round(elapsed/num_episodes,2),"secs")
Time taken to run model: 1.93 mins Avg Time taken per episode: 1.16 secs
In [54]:
Mdl3[3].head()
Out[54]:
StartState | EndState | Event1 | Event2 | Probability | Reward | V | |
---|---|---|---|---|---|---|---|
12 | 1 | 2 | +KILLS | -DRAGON | 0.031590 | 0 | 0.094938 |
341 | 2 | 3 | -DRAGON | -OUTER_TURRET | 0.142857 | 0 | 0.094465 |
529 | 3 | 4 | -OUTER_TURRET | +OUTER_TURRET | 0.368852 | 0 | 0.084538 |
648 | 4 | 5 | +OUTER_TURRET | -KILLS | 0.146843 | 0 | 0.094469 |
978 | 5 | 6 | -KILLS | -KILLS | 0.160743 | 0 | 0.087776 |
In [55]:
Mdl3[4]
Out[55]:
StartState | EndState | Event1 | Event2 | Probability | Reward | V | |
---|---|---|---|---|---|---|---|
0 | 1 | 2 | +KILLS | -DRAGON | 0.031590 | 0 | 0.094938 |
0 | 2 | 3 | -DRAGON | -OUTER_TURRET | 0.142857 | 0 | 0.094465 |
0 | 3 | 4 | -OUTER_TURRET | +OUTER_TURRET | 0.368852 | 0 | 0.084538 |
0 | 4 | 5 | +OUTER_TURRET | -KILLS | 0.146843 | 0 | 0.094469 |
0 | 5 | 6 | -KILLS | -KILLS | 0.160743 | 0 | 0.087776 |
0 | 6 | 7 | -KILLS | -OUTER_TURRET | 0.271478 | 0 | 0.096109 |
0 | 7 | 8 | -OUTER_TURRET | +OUTER_TURRET | 0.186101 | 0 | 0.093135 |
0 | 8 | 9 | +OUTER_TURRET | +KILLS | 0.194960 | 0 | 0.074443 |
0 | 9 | 10 | +KILLS | +OUTER_TURRET | 0.216617 | 0 | 0.072786 |
0 | 10 | 11 | +OUTER_TURRET | +DRAGON | 0.124464 | 0 | 0.082719 |
0 | 11 | 12 | +DRAGON | -KILLS | 0.250000 | 0 | 0.073039 |
0 | 12 | 13 | -KILLS | +KILLS | 0.266995 | 0 | 0.095967 |
0 | 13 | 14 | +KILLS | +DRAGON | 0.072690 | 0 | 0.091666 |
0 | 14 | 15 | +DRAGON | +KILLS | 0.314985 | 0 | 0.094469 |
0 | 15 | 16 | +KILLS | -KILLS | 0.297481 | 0 | 0.073666 |
0 | 16 | 17 | -KILLS | -INNER_TURRET | 0.124319 | 0 | 0.093982 |
0 | 17 | 18 | -INNER_TURRET | +KILLS | 0.181619 | 0 | 0.093859 |
0 | 18 | 19 | +KILLS | +BASE_TURRET | 0.029692 | 0 | 0.094469 |
0 | 19 | 20 | +BASE_TURRET | +DRAGON | 0.055556 | 0 | 0.094469 |
0 | 20 | 21 | +DRAGON | -KILLS | 0.195745 | 0 | 0.095296 |
0 | 21 | 22 | -KILLS | -KILLS | 0.108607 | 0 | 0.107893 |
0 | 22 | 23 | -KILLS | 1 | 0.003209 | 0 | 0.094469 |
Part 1 Conclusion
So we have performed some interesting exploratory analysis, modelled the environment as an MDP and even created a RL model, however, there are still many challenges to overcome.
The biggest issue right now is our output doesn't account for cumulative success or failures.
In other words, our model thinks we are just as likely to take good objectives in later stages irrespective of whether we have lost each one before and would likely be behind.
We can see this emphasised by our output getting us to a win from 20+ minutes by simply taking objective after objective even though we had lost the majority of objectives before it. There is no accountability for being in a losing position in our model.
To fix this, we must re-asses our MDP and consider features that would account for the long term success or failure of taking or losing objectives.
This is a good start, in our next part we will redesign our MDP to account for this and fix some other issues.