Looking at champion.gg data

Data currently comes from 2016-09-14, patch 6.17

In [1]:
import json, pandas, requests, re, os.path, sys
from IPython.core.display import display, HTML
idx = pandas.IndexSlice

import matplotlib.pyplot as plt
%matplotlib inline

import seaborn as sns;
sns.set_palette('deep')

#import mpld3, mpld3.plugins; mpld3.enable_notebook()

Get the champion.gg data

Lazily download a Wayback Machine archive of http://champion.gg/statistics/ and extract the data blob that makes up the table

In [2]:
json_file = 'championgg.json'
def get_json_data(url='https://web.archive.org/web/20160914110810/http://champion.gg/statistics/'):
    "Extract the JSON data from a champion.gg statistics page"

    # The data is one line of Javascript setting the variable matchupData.stats
    parse_re = re.compile(r'^\s+matchupData\.stats = (\[.*\]);')

    r = requests.get(url)
    for l in r.text.split('\n'):
        m = parse_re.match(l)
        if m:
            return m.group(1)
# Download the file if necessary
if not os.path.isfile(json_file):
    with open(json_file, 'w') as fp:
        fp.write(get_json_data())
with open(json_file) as fp:
    data_blob = json.load(fp)

Parse the data into a labelled DataFrame

In [3]:
column_names = [
    'winPercent',
    'playPercent',
    'banRate',
    'experience',
    'kills',
    'deaths',
    'assists',
    'largestKillingSpree',
    'totalDamageDealtToChampions',
    'totalDamageTaken',
    'totalHeal',
    'minionsKilled',   
    'neutralMinionsKilledEnemyJungle',
    'neutralMinionsKilledTeamJungle',
    'goldEarned',
    'overallPosition',
    'overallPositionChange',
]
d = []
for datum in data_blob:
    row = [datum['title'], datum['role']]
    row.extend (datum['general'][n] for n in column_names)
    d.append(row)
df = pandas.DataFrame(d, 
                      columns=['Champion', 'Role'] + column_names)
df = df.set_index(['Champion', 'Role'])
df.insert(7, 'KDA', (df.kills + df.assists) / df.deaths)
df.sort_values('playPercent', ascending=False, inplace=True)
df.head(4)
Out[3]:
winPercent playPercent banRate experience kills deaths assists KDA largestKillingSpree totalDamageDealtToChampions totalDamageTaken totalHeal minionsKilled neutralMinionsKilledEnemyJungle neutralMinionsKilledTeamJungle goldEarned overallPosition overallPositionChange
Champion Role
Lucian ADC 47.61 32.01 1.35 81.81 7.90 6.07 7.14 2.477759 3.65 22412 22035 3489 204.4 2.72 8.99 13514 7 1
Thresh Support 49.39 27.66 1.01 135.63 1.96 6.20 15.26 2.777419 0.70 8202 23933 2583 33.5 0.20 0.19 9617 9 2
Jhin ADC 51.87 21.85 9.01 43.72 8.03 5.92 9.16 2.903716 3.78 24971 18265 3022 186.8 2.12 6.97 13256 1 2
Ezreal ADC 49.10 21.75 0.60 52.86 7.56 5.58 8.63 2.901434 3.61 26676 20019 3266 194.9 2.73 7.98 13315 5 -1

Simple list of champions by role

In [4]:
for role in df.index.levels[1]:
    subset = df.xs(role, level='Role')
    display(HTML('<b>%s</b> %d<br>%s' % (role, len(subset), ' • '.join(subset.index))))
ADC 17
Lucian • Jhin • Ezreal • Jinx • Vayne • Caitlyn • Ashe • Tristana • Miss Fortune • Sivir • Draven • Twitch • Kog'Maw • Varus • Corki • Kalista • Quinn
Jungle 53
Lee Sin • Kha'Zix • Zac • Graves • Vi • Nidalee • Elise • Amumu • Hecarim • Rengar • Gragas • Master Yi • Shaco • Evelynn • Nocturne • Sejuani • Rek'Sai • Skarner • Xin Zhao • Fiddlesticks • Jax • Volibear • Jarvan IV • Wukong • Shyvana • Warwick • Rammus • Udyr • Diana • Kog'Maw • Ekko • Olaf • Kindred • Fizz • Twitch • Pantheon • Malphite • Trundle • Nautilus • Rumble • Kayle • Nunu • Poppy • Tryndamere • Maokai • Quinn • Cho'Gath • Sion • Aurelion Sol • Kled • Aatrox • Dr. Mundo • Mordekaiser
Middle 46
Ahri • Lux • LeBlanc • Zed • Syndra • Annie • Katarina • Yasuo • Twisted Fate • Orianna • Viktor • Fizz • Anivia • Cassiopeia • Veigar • Ekko • Lissandra • Vel'Koz • Brand • Malzahar • Kassadin • Xerath • Ryze • Diana • Vladimir • Morgana • Karma • Taliyah • Ziggs • Gangplank • Kennen • Akali • Azir • Aurelion Sol • Talon • Jayce • Zilean • Varus • Swain • Karthus • Kayle • Cho'Gath • Galio • Heimerdinger • Zyra • Corki
Support 25
Thresh • Janna • Braum • Soraka • Morgana • Blitzcrank • Bard • Leona • Nami • Sona • Karma • Alistar • Lulu • Taric • Zyra • Brand • Tahm Kench • Nautilus • Zilean • Vel'Koz • Lux • Trundle • Annie • Sion • Poppy
Top 53
Riven • Yorick • Darius • Gnar • Irelia • Yasuo • Gangplank • Fiora • Malphite • Renekton • Ekko • Jax • Shen • Illaoi • Teemo • Pantheon • Kennen • Tryndamere • Jayce • Nasus • Garen • Wukong • Trundle • Olaf • Kled • Rumble • Vladimir • Singed • Sion • Kayle • Poppy • Maokai • Jarvan IV • Ryze • Cho'Gath • Akali • Graves • Swain • Lissandra • Quinn • Dr. Mundo • Nautilus • Rengar • Tahm Kench • Volibear • Mordekaiser • Heimerdinger • Aatrox • Xin Zhao • Urgot • Rammus • Karthus • Galio

Summary statistics by role

In [5]:
combine = df.mean(level=1).applymap(lambda n: "%.2f" % n) + df.std(level=1).applymap(lambda m: " ±%.2f" % m)
combine.transpose()
Out[5]:
Role ADC Jungle Middle Support Top
winPercent 50.23 ±2.63 49.88 ±2.61 49.86 ±2.86 50.38 ±2.44 50.47 ±2.65
playPercent 11.15 ±9.07 3.66 ±4.00 4.05 ±2.97 7.40 ±6.46 3.52 ±3.17
banRate 2.09 ±3.65 3.39 ±6.06 5.40 ±11.80 2.09 ±3.92 5.89 ±12.43
experience 58.49 ±32.08 63.47 ±35.29 61.55 ±28.11 72.85 ±29.44 72.09 ±39.98
kills 7.82 ±0.84 6.83 ±1.44 7.36 ±1.30 2.47 ±1.17 6.21 ±1.29
deaths 6.48 ±0.54 6.02 ±0.71 6.34 ±0.67 6.08 ±0.83 6.35 ±0.61
assists 7.92 ±0.92 9.17 ±1.84 8.04 ±1.30 13.91 ±1.55 7.29 ±1.53
KDA 2.44 ±0.24 2.70 ±0.38 2.46 ±0.32 2.75 ±0.43 2.14 ±0.31
largestKillingSpree 3.49 ±0.31 3.16 ±0.53 3.36 ±0.50 0.95 ±0.52 2.84 ±0.51
totalDamageDealtToChampions 24001.29 ±1958.12 18245.55 ±2817.39 24174.17 ±2620.93 11686.64 ±5461.44 21551.15 ±2977.23
totalDamageTaken 20806.76 ±1560.57 32467.96 ±5658.15 22259.70 ±4057.10 22030.32 ±5193.91 29376.30 ±5325.45
totalHeal 3185.76 ±330.65 9938.47 ±5251.30 4126.65 ±3741.26 5914.96 ±5552.63 5656.53 ±4206.22
minionsKilled 197.07 ±10.76 56.32 ±16.75 177.79 ±14.50 38.46 ±14.16 188.60 ±15.66
neutralMinionsKilledEnemyJungle 2.96 ±0.40 9.78 ±2.52 2.37 ±0.78 0.48 ±0.32 2.60 ±1.27
neutralMinionsKilledTeamJungle 9.13 ±1.29 63.21 ±8.15 7.64 ±2.35 0.77 ±0.68 4.63 ±1.98
goldEarned 13525.82 ±323.33 12528.70 ±604.85 12717.80 ±469.16 10329.68 ±658.84 12675.81 ±552.01
overallPosition 9.00 ±5.05 27.00 ±15.44 23.50 ±13.42 13.00 ±7.36 27.00 ±15.44
overallPositionChange 0.00 ±1.77 0.00 ±5.67 0.00 ±7.18 0.00 ±2.35 0.00 ±7.37

Pick Rate vs Win Rate

In [6]:
sns.jointplot(x='winPercent', y='playPercent', data=df, size=6, ylim=(0,35), xlim=(40,60), kind="scatter")

if 'mpld3' in sys.modules:
    labels = list("%s: %s<br>Win: %.2f%%<br>Play: %.2f%%<br>" % (x[0], x[1], df['winPercent'][x], df['playPercent'][x]) for x in df.index)
    tooltip = mpld3.plugins.PointHTMLTooltip(points, labels, css=".mpld3-tooltip { background-color: #fff }")
    mpld3.plugins.connect(plt.gcf(), tooltip)

Win rates as a function of experience

In [7]:
sns.jointplot(x='experience', y='winPercent', data=df, size=6, kind="scatter")
Out[7]:
<seaborn.axisgrid.JointGrid at 0x7fb962f7ab70>

Histograms of stats

In [8]:
fig, axs = plt.subplots(figsize=(10,6), ncols=4, nrows=4)
for i, c in enumerate(['KDA',] + column_names[:-2]):
    row, col = int(i/4), i%4
    g = sns.distplot(df[c], ax=axs[row, col])
    g.set(yticklabels=[], xticklabels=[])
fig.tight_layout(pad=0)

Comparison of Experience, Win Percent, KDA, Gold Earned, Total Damage Dealt

In [9]:
subset = df.filter(('experience', 'winPercent', 'KDA', 'goldEarned', 'totalDamageDealtToChampions'))
sns.pairplot(subset)
Out[9]:
<seaborn.axisgrid.PairGrid at 0x7fb962f66dd8>

Add a role value column back to the DataFrame, from the index.

In [10]:
df['role'] = df.index.get_level_values(level=1)

Distributions of some variables by role

In [11]:
variables = ('playPercent', 'winPercent', 'experience', 'KDA', 'goldEarned', 'totalDamageDealtToChampions')
fig, axs = plt.subplots(figsize=(7, len(variables)*4), ncols=1, nrows=len(variables))
for i, c in enumerate(variables):
    sns.violinplot(y=c, x='role', data=df, inner=None, ax=axs[i]).set(xlabel="", ylabel="", title=c)
    sns.swarmplot(y=c, x='role', data=df, color="w", linewidth=0, size=2.5, ax=axs[i]).set(xlabel="", ylabel="", title=c)
fig.tight_layout(pad=0, h_pad=1)