Win/Loss Betting Model


In [1]:
import pandas as pd
import numpy as np
import datetime as dt
from scipy.stats import norm, bernoulli
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
from spcl_case import *
plt.style.use('fivethirtyeight')

Obtain results of teams within the past year


In [2]:
h_matches = pd.read_csv('hltv_csv/matchResults.csv')
h_matches['Date'] = pd.to_datetime(h_matches['Date'])
h_teams = pd.read_csv('hltv_csv/teams_w_ranking.csv')
h_teams = fix_teams(h_teams.set_index('ID'))

In [3]:
MIN_DATE = dt.datetime(2017,1,1)
EVENT_SET = 'eslpl'
FILTER_TEAMS = {'eslpl': ['OpTic', 'SK', 'Cloud9', 'Liquid', 'Luminosity', 'Misfits', 'Renegades', 'Immortals', 
                    'Splyce', 'compLexity', 'Rogue', 'Ghost', 'CLG', 'NRG', 'FaZe', 'North',
                    'BIG', 'LDLC', 'mousesports', 'EnVyUs', 'NiP', 'Virtus.pro', 
                    'Astralis', 'G2', 'GODSENT', 'Heroic', 'fnatic', 'NiP', 'Heroic'],
                'mdleu': ['Virtus.pro', 'FlipSid3', 'eXtatus', 'AGO', 'Fragsters', 'Gambit', 'PRIDE', '1337HUANIA', 
                    'VITALIS', 'Epsilon', 'CHAOS', 'Crowns', 'MK', 'Japaleno', 'Not Academy', 'aAa', 'Space Soldiers',
                    'Singularity', 'Nexus', 'Invictus Aquilas', 'Spirit', 'Kinguin', 'Seed', 'Endpoint', 'iGame.com', 'TEAM5',
                    'ALTERNATE aTTaX'],
                'mdlna': ['Gale Force', 'FRENCH CANADIANS', 'Mythic', 'GX', 'Beacon', 'Torqued', 'Rise Nation', 'Denial', 'subtLe', 
                   'SoaR', 'Muffin Lightning', 'Iceberg', 'ex-Nitrious', 'Adaptation', 'Morior Invictus', 'Naventic', 'CheckSix', 'Good People'
                   , 'LFAO', 'CLG Academy', 'Ambition', 'Mostly Harmless', 'Gorilla Core', 'ex-Nitrious', 'ANTI ECO'],
                'mdlau': ['Grayhound', 'Tainted Minds', 'Kings', 'Chiefs', 'Dark Sided', 'seadoggs', 'Athletico', 'Legacy',
                    'SIN', 'Noxide', 'Control', 'SYF', 'Corvidae', 'Funkd', 'Masterminds', 'Conspiracy', 'AVANT']
               }

h_matches = h_matches[h_matches['Date'] >= MIN_DATE]

In [4]:
maps_played = pd.DataFrame([h_matches.groupby('Team 1 ID')['Map'].count(), h_matches.groupby('Team 2 ID')['Map'].count()]).T.fillna(0).sum(axis=1)
maps_played.hist(bins=30)
h_teams['maps played 2017'] = maps_played
np.mean(maps_played > 200)


Out[4]:
0.033699633699633698

In [5]:
#h_filter_teams = h_teams[h_teams['Name'].isin(FILTER_TEAMS[EVENT_SET])]
#h_filter_teams = h_teams.dropna().sort_values('Ranking').iloc[:250]
h_filter_teams = h_teams[h_teams['maps played 2017']> 10].dropna()
print(len(h_filter_teams))


222

In [6]:
h_matches = h_matches[h_matches['Team 1 ID'].isin(h_filter_teams.index) | h_matches['Team 2 ID'].isin(h_filter_teams.index)]
h_matches['winner'] = h_matches.apply(lambda x: x['Team 1 ID'] if x['Team 1 Score'] > x['Team 2 Score'] else x['Team 2 ID'], axis=1)
h_matches['score_diff'] = h_matches['Team 1 Score'] - h_matches['Team 2 Score']

In [7]:
obs = h_matches[['Date', 'Map', 'Team 1 ID', 'Team 2 ID', 'score_diff', 'winner']]
obs = obs[obs.Map != 'Default']
obs.Date = obs.Date.dt.to_period('M') # date period
obs = obs.sort_values('Date')
obs.head()


Out[7]:
Date Map Team 1 ID Team 2 ID score_diff winner
23834 2017-01 Cobblestone 6134 4674 14 6134
24247 2017-01 Mirage 7568 7557 -9 7557
24245 2017-01 Mirage 7105 6673 -5 6673
24244 2017-01 Mirage 5974 7569 14 5974
24243 2017-01 Overpass 6290 7575 5 6290

In [8]:
teams = np.sort(np.unique(np.concatenate([h_matches['Team 1 ID'], h_matches['Team 2 ID']])))
maps = obs.Map.unique()
periods = obs.Date.unique()
tmap = {v:k for k,v in dict(enumerate(teams)).items()}
mmap = {v:k for k,v in dict(enumerate(maps)).items()}
pmap = {v:k for k,v in dict(enumerate(periods)).items()}
n_teams = len(teams)
n_maps = len(maps)
n_periods = len(periods)
print('Number of Teams: %i ' % n_teams)
print('Number of Plotted Teams: %i' % len(FILTER_TEAMS[EVENT_SET]))
print('Number of Matches: %i ' % len(h_matches))
print('Number of Maps: %i '% n_maps)
print('Number of Periods: %i '% n_periods)


Number of Teams: 936 
Number of Plotted Teams: 29
Number of Matches: 14520 
Number of Maps: 8 
Number of Periods: 11 

Pymc Model

Determining Binary Win Loss: $wl_{m,i,j}$ $$ \omega, \tau, \sim HC(0.5) \\ R_{k} \sim N(0, \omega^2) \\ \tilde{\theta}_{m,k} \sim N(0,1) \\ R_{m,k} = R_{k} + \tau\tilde{\theta} \\ wl_{m,i,j} \sim B(p = \text{Sig}(R_{m,i}-R_{m,j})) \\ $$

and score difference: $sc_{m,i,j}$

$$ \alpha \sim Gamma(10,5) \\ \kappa_{m,i,j} = 32\text{Sig}(\alpha(R_{m,i}-R_{m,j}))-16 \\ \sigma_{m} \sim HC(0.5) \\ sc_{m,i,j} \sim N(\kappa, \sigma_{m}^2) $$

In [11]:
import pymc3 as pm
import theano
import theano.tensor as tt

In [12]:
obs_map = obs['Map'].map(mmap).values
obs_team_1 = obs['Team 1 ID'].map(tmap).values
obs_team_2 = obs['Team 2 ID'].map(tmap).values
obs_period = obs['Date'].map(pmap).values

In [34]:
a = np.arange(1,n_periods)
with pm.Model() as rating_model:
    
    rho = pm.Normal('rho', 0, 1)
    omega = tt.sqrt(pm.InverseGamma('omega', 4, 2))
    sigma = tt.sqrt(pm.HalfNormal('sigma', 1.5))
    tau = pm.HalfCauchy('tau', 0.5)
    theta_tilde = pm.Normal('rate_t', mu=0, sd=1, shape=(n_maps, n_teams))
    
    time_rating = [pm.Normal('rating_0', 0, omega, shape=n_teams)]
    time_rating_map = [pm.Deterministic('rating_0 | map', time_rating[0] + tau * theta_tilde)]
    
    for i in a:
        time_rating.append(pm.Normal('rating_'+str(i), rho*time_rating[i-1], sigma, shape=n_teams))
        time_rating_map.append(pm.Deterministic('rating_'+str(i)+' | map', time_rating[i] + tau * theta_tilde))
    
    diff = [time_rating_map[i][obs_map[obs_period == i], obs_team_1[obs_period == i]] - time_rating_map[i][obs_map[obs_period == i], obs_team_2[obs_period == i]] for i in range(n_periods)]
    diff = tt.concatenate(diff)
    #p = 0.5*pm.math.tanh(diff)+0.5
    kappa = 16.*pm.math.tanh(0.5*diff)
    gamma = pm.HalfNormal('gamma', 10)
    
    sc = pm.Normal('observed score diff', kappa, gamma, observed=obs['score_diff'])
    #wl = pm.Bernoulli('observed wl', p=p, observed=(obs['Team 1 ID'] == obs['winner']).values)

In [ ]:
# help my models too slow and i am bad at coding, pls just approximate :3
with rating_model:
    approx = pm.fit(20000, method='advi')
    ap_trace = approx.sample(500)

In [35]:
with rating_model:
    trace = pm.sample(1000, init='jitter+adapt_diag', n_init=20000, tune=250, nuts_kwargs={'target_accept': 0.9, 'max_treedepth': 25}) # tune=1000, nuts_kwargs={'target_accept': 0.95}


Auto-assigning NUTS sampler...
Initializing NUTS using jitter+adapt_diag...
100%|██████████████████████████████████████████████████████████████████████████████| 1250/1250 [37:38<00:00,  1.81s/it]

In [36]:
team_names = h_teams.loc[teams]
filt = team_names[team_names.Name.isin(FILTER_TEAMS[EVENT_SET])]
sns.set_palette('Paired', n_teams)

f, ax = plt.subplots(figsize=(16,10))
ax.set_ylim(0,6.0)
[sns.kdeplot(trace['rating_%s'%max(obs_period-1)][:,tmap[i]], shade=True, alpha=0.55, legend=True, ax=ax, label=v['Name']) for i,v in filt.iterrows()]
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))


Out[36]:
<matplotlib.legend.Legend at 0x28271181f98>

In [39]:
num_rows = int(np.ceil(len(filt)/4))
f, ax = plt.subplots(num_rows, 4, figsize=(16,30), sharex=True, sharey=True)
ax = ax.flatten()
condensed_ratings = {j: np.vstack([trace['rating_'+str(i)][:,tmap[j]] for i in range(n_periods)]).T for j,v in filt.iterrows()}
for i,(j,v) in enumerate(filt.iterrows()):
    ax[i].set_title(v['Name'])
    sns.tsplot(condensed_ratings[j], color='black', ci='sd', ax=ax[i], marker='s', linewidth=1)


C:\Users\kevin.pei\AppData\Local\Continuum\anaconda3\lib\site-packages\seaborn\timeseries.py:183: UserWarning: The tsplot function is deprecated and will be removed or replaced (in a substantially altered version) in a future release.
  warnings.warn(msg, UserWarning)

Save Model


In [40]:
EVENT_SET_SAVED = 'all_time_sc'

pm.backends.text.dump('saved_model/'+EVENT_SET_SAVED+'/trace', trace)
np.save('saved_model/'+EVENT_SET_SAVED+'/teams.npy', teams)
np.save('saved_model/'+EVENT_SET_SAVED+'/maps.npy', maps)
np.save('saved_model/'+EVENT_SET_SAVED+'/periods.npy', periods)
np.save('saved_model/'+EVENT_SET_SAVED+'/filter_teams.npy', FILTER_TEAMS[EVENT_SET])

In [7]:
obs[['Date', 'Team 1 ID', 'Team 2 ID', 'winner']].to_csv('data.csv')

Diagnostics


In [ ]:
with rating_model:
    approx = pm.fit(15000)
    ap_trace = approx.sample(5000)

In [ ]:
print('Gelman Rubin: %s' % pm.diagnostics.gelman_rubin(trace))
print('Effective N: %s' % pm.diagnostics.effective_n(trace))
print('Accept Prob: %.4f' % trace.get_sampler_stats('mean_tree_accept').mean())
print('Percentage of Divergent %.5f' % (trace['diverging'].nonzero()[0].size/float(len(trace))))

In [37]:
pm.traceplot(trace, varnames=['rho', 'sigma', 'omega', 'tau', 'gamma'])


Out[37]:
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x0000028234B129B0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x0000028234CDBDD8>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x00000282552E7048>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x0000028234C4EEB8>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x0000028235069B00>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x00000282335B8780>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x00000282550A1160>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x0000028274159438>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x000002823753C3C8>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x00000282553219B0>]], dtype=object)

In [38]:
rating_model.profile(pm.gradient(rating_model.logpt, rating_model.vars), n=100).summary()


Function profiling
==================
  Message: C:\Users\kevin.pei\AppData\Local\Continuum\anaconda3\lib\site-packages\pymc3\model.py:853
  Time in 100 calls to Function.__call__: 5.169590e-01s
  Time in Function.fn.__call__: 4.963956e-01s (96.022%)
  Time in thunks: 4.628580e-01s (89.535%)
  Total compile time: 4.792498e+01s
    Number of Apply nodes: 298
    Theano Optimizer time: 2.862026e+00s
       Theano validate time: 1.017601e-01s
    Theano Linker time (includes C, CUDA code generation/compiling): 4.372509e+01s
       Import time 7.344316e+00s
       Node make_thunk time 4.370604e+01s
           Node Elemwise{Composite{Switch(i0, (i1 * sqr((i2 - (i3 * i4)))), i5)}}(Elemwise{Composite{Cast{int8}(GT(i0, i1))}}.0, TensorConstant{(1,) of 0.5}, rating_10, InplaceDimShuffle{x}.0, rating_9, TensorConstant{(1,) of 0}) time 9.524312e+00s
           Node Elemwise{Composite{(Switch(Cast{int8}(GE(i0, i1)), (i2 * i0 * i0), i1) + i3 + ((i4 * ((i5 * (((i4 * i6 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i9 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0) + (i5 * (((i4 * i10 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i11 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0) + (i5 * (((i4 * i12 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i13 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0) + (i5 * (((i4 * i14 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i15 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0) + (i5 * (((i4 * i16 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i17 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0) + (i5 * (((i4 * i18 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i19 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0) + (i5 * (((i4 * i20 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i21 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0) + (i5 * (((i4 * i22 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i23 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0) + (i5 * (((i4 * i24 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i25 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0) + (i5 * (((i4 * i26 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7)) / i8) - (i27 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i7))) * i0))) / i7))}}[(0, 0)](sigma, TensorConstant{0}, TensorConstant{-0.4444444444444444}, TensorConstant{1.0}, TensorConstant{0.5}, TensorConstant{-2.0}, Sum{acc_dtype=float64}.0, Elemwise{sqrt,no_inplace}.0, Elemwise{Composite{inv(sqr(i0))}}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0) time 7.291565e+00s
           Node Elemwise{Composite{(Switch(Cast{int8}(GE(i0, i1)), (i2 * i0 * i0), i1) + i3 + (i4 * (((i5 * i6 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i0)) / i7) - (i8 * Composite{inv(Composite{(sqr(i0) * i0)}(i0))}(i0))) * i0))}}[(0, 0)](gamma, TensorConstant{0}, TensorConstant{-0.01}, TensorConstant{1.0}, TensorConstant{-2.0}, TensorConstant{0.5}, Sum{acc_dtype=float64}.0, Elemwise{Composite{inv(sqr(i0))}}.0, Sum{acc_dtype=float64}.0) time 5.495296e+00s
           Node Elemwise{Composite{Switch(i0, (i1 * sqr(i2)), i3)}}(Elemwise{Composite{Cast{int8}(GT(i0, i1))}}.0, TensorConstant{(1,) of 0.5}, rating_0, TensorConstant{(1,) of 0}) time 4.676282e+00s
           Node Elemwise{Composite{(Switch(Cast{int8}(GE(i0, i1)), ((i2 * i0 * i0) / (i3 + sqr((i4 * i0)))), i1) + i5 + ((i6 + i7 + i8 + i9 + i10 + i11 + i12 + i13 + i14 + i15 + i16) * i0))}}[(0, 0)](tau, TensorConstant{0}, TensorConstant{-8.0}, TensorConstant{1.0}, TensorConstant{2.0}, TensorConstant{1.0}, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0, Sum{acc_dtype=float64}.0) time 4.299679e+00s

Time in all call to theano.grad() 4.767390e+01s
Time since theano import 11979.101s
Class
---
<% time> <sum %> <apply time> <time per call> <type> <#call> <#apply> <Class name>
  70.2%    70.2%       0.325s       1.48e-04s     Py    2200      22   theano.tensor.subtensor.AdvancedIncSubtensor
  11.6%    81.8%       0.054s       2.44e-05s     Py    2200      22   theano.tensor.subtensor.AdvancedSubtensor
   9.3%    91.1%       0.043s       4.27e-06s     C    10100     101   theano.tensor.elemwise.Elemwise
   5.1%    96.2%       0.024s       4.21e-06s     C     5600      56   theano.tensor.elemwise.Sum
   1.1%    97.3%       0.005s       2.18e-06s     C     2300      23   theano.tensor.basic.Alloc
   0.9%    98.2%       0.004s       2.01e-05s     C      200       2   theano.tensor.basic.Join
   0.8%    98.9%       0.004s       7.33e-07s     C     4800      48   theano.tensor.elemwise.DimShuffle
   0.4%    99.3%       0.002s       3.34e-06s     C      600       6   theano.tensor.basic.Reshape
   0.4%    99.8%       0.002s       2.00e-05s     C      100       1   theano.tensor.basic.Split
   0.2%   100.0%       0.001s       8.40e-07s     C     1200      12   theano.compile.ops.Shape_i
   0.0%   100.0%       0.000s       0.00e+00s     C      500       5   theano.compile.ops.Rebroadcast
   ... (remaining 0 Classes account for   0.00%(0.00s) of the runtime)

Ops
---
<% time> <sum %> <apply time> <time per call> <type> <#call> <#apply> <Op name>
  70.2%    70.2%       0.325s       1.48e-04s     Py    2200       22   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}
  11.6%    81.8%       0.054s       2.44e-05s     Py    2200       22   AdvancedSubtensor
   4.2%    86.0%       0.020s       4.34e-06s     C     4500       45   Sum{acc_dtype=float64}
   2.7%    88.7%       0.013s       1.25e-05s     C     1000       10   Elemwise{add,no_inplace}
   2.1%    90.8%       0.010s       9.53e-05s     C      100        1   Elemwise{Composite{Switch(i0, (i1 * i2 * (i3 - (i4 * i5)) * (i6 - sqr(i5))), i7)}}
   1.2%    92.0%       0.006s       5.51e-05s     C      100        1   Elemwise{Composite{((-i0) + (i1 * i2) + (i3 * i2) + (i4 * i2) + (i5 * i2) + (i6 * i2) + (i7 * i2) + (i8 * i2) + (i9 * i2) + (i10 * i2) + (i11 * i2) + (i12 * i2))}}[(0, 1)]
   1.1%    93.1%       0.005s       2.18e-06s     C     2300       23   Alloc
   0.9%    93.9%       0.004s       3.65e-06s     C     1100       11   Sum{axis=[0], acc_dtype=float64}
   0.9%    94.8%       0.004s       2.01e-05s     C      200        2   Join
   0.5%    95.3%       0.003s       6.97e-07s     C     3600       36   InplaceDimShuffle{x}
   0.5%    95.9%       0.003s       2.51e-05s     C      100        1   Elemwise{Composite{tanh((i0 * i1))}}[(0, 1)]
   0.5%    96.4%       0.003s       2.79e-06s     C      900        9   Elemwise{Composite{(Switch(i0, ((i1 * i2 * (i3 - (i4 * i5))) + (i6 * (i7 - (i8 * i3)) * i9)), i10) + i11)}}[(0, 11)]
   0.5%    97.0%       0.003s       2.51e-06s     C     1000       10   Elemwise{Composite{Switch(i0, (i1 * sqr((i2 - (i3 * i4)))), i5)}}
   0.4%    97.4%       0.002s       2.01e-06s     C     1000       10   Elemwise{Mul}[(0, 0)]
   0.4%    97.8%       0.002s       3.34e-06s     C      600        6   Reshape{1}
   0.4%    98.3%       0.002s       2.00e-05s     C      100        1   Elemwise{Composite{Switch(i0, (i1 * sqr((i2 - (i3 * i4)))), i5)}}[(0, 4)]
   0.4%    98.7%       0.002s       2.00e-05s     C      100        1   Split{11}
   0.3%    99.0%       0.002s       1.50e-06s     C     1000       10   Elemwise{Composite{Switch(i0, (i1 * (i2 - (i3 * i4)) * i4), i5)}}
   0.2%    99.2%       0.001s       9.18e-07s     C     1100       11   InplaceDimShuffle{x,0}
   0.2%    99.5%       0.001s       8.40e-07s     C     1200       12   Shape_i{0}
   ... (remaining 19 Ops account for   0.54%(0.00s) of the runtime)

Apply
------
<% time> <sum %> <apply time> <time per call> <#call> <id> <Apply name>
   6.0%     6.0%       0.028s       2.76e-04s    100   218   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.4, TensorConstant{[2 4 1 ..., 5 1 2]}, TensorConstant{[ 36 111 1..4 346  84]})
   5.4%    11.4%       0.025s       2.51e-04s    100   242   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}.0, Elemwise{Neg}[(0, 0)].0, TensorConstant{[2 4 1 ..., 5 1 2]}, TensorConstant{[494 479 4..2  31  72]})
   5.3%    16.7%       0.025s       2.46e-04s    100   237   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}.0, Elemwise{Neg}[(0, 0)].0, TensorConstant{[0 4 2 ..., 0 7 1]}, TensorConstant{[338  68 2..8 588 479]})
   5.1%    21.8%       0.024s       2.36e-04s    100   244   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}.0, Elemwise{Neg}[(0, 0)].0, TensorConstant{[1 1 1 ..., 1 2 0]}, TensorConstant{[ 69 314 3..1 278 358]})
   4.9%    26.7%       0.023s       2.26e-04s    100   219   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.3, TensorConstant{[6 4 4 ..., 6 5 5]}, TensorConstant{[407 407 4..6 306 232]})
   4.0%    30.7%       0.019s       1.86e-04s    100   213   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.9, TensorConstant{[0 4 2 ..., 0 7 1]}, TensorConstant{[177 221 6..6 306 883]})
   4.0%    34.7%       0.019s       1.85e-04s    100   238   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}.0, Elemwise{Neg}[(0, 0)].0, TensorConstant{[7 7 0 ..., 4 0 0]}, TensorConstant{[193 644 5..9 229 240]})
   3.8%    38.5%       0.018s       1.75e-04s    100   214   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.8, TensorConstant{[7 7 0 ..., 4 0 0]}, TensorConstant{[ 72 533 8..3 423 678]})
   3.7%    42.1%       0.017s       1.70e-04s    100   220   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.2, TensorConstant{[1 1 1 ..., 1 2 0]}, TensorConstant{[111 348 2..3  64 131]})
   3.6%    45.7%       0.017s       1.66e-04s    100   243   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}.0, Elemwise{Neg}[(0, 0)].0, TensorConstant{[6 4 4 ..., 6 5 5]}, TensorConstant{[447 447 2..9  59  90]})
   3.6%    49.3%       0.017s       1.65e-04s    100   216   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.6, TensorConstant{[0 2 4 ..., 2 4 7]}, TensorConstant{[547 120  ..2 622 391]})
   3.4%    52.7%       0.016s       1.56e-04s    100   215   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.7, TensorConstant{[0 4 2 ..., 1 7 2]}, TensorConstant{[349 302 1..4 565 299]})
   2.9%    55.6%       0.014s       1.35e-04s    100   240   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}.0, Elemwise{Neg}[(0, 0)].0, TensorConstant{[0 2 4 ..., 2 4 7]}, TensorConstant{[294 237  ..0 280 449]})
   2.4%    58.0%       0.011s       1.10e-04s    100   241   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}.0, Elemwise{Neg}[(0, 0)].0, TensorConstant{[7 6 0 1 4..2 7 1 1 7]}, TensorConstant{[567 306 5..0 443 443]})
   2.2%    60.1%       0.010s       1.00e-04s    100   239   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}.0, Elemwise{Neg}[(0, 0)].0, TensorConstant{[0 4 2 ..., 1 7 2]}, TensorConstant{[103 315 2..8 736 124]})
   2.1%    62.2%       0.010s       9.53e-05s    100   206   Elemwise{Composite{Switch(i0, (i1 * i2 * (i3 - (i4 * i5)) * (i6 - sqr(i5))), i7)}}(Elemwise{Composite{Cast{int8}(GT(i0, i1))}}.0, TensorConstant{(1,) of 8.0}, InplaceDimShuffle{x}.0, TensorConstant{[ 14.  -9... -2.  -4.]}, TensorConstant{(1,) of 16.0}, Elemwise{Composite{tanh((i0 * i1))}}[(0, 1)].0, TensorConstant{(1,) of 1.0}, TensorConstant{(1,) of 0})
   1.9%    64.2%       0.009s       9.02e-05s    100   217   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.5, TensorConstant{[7 6 0 1 4..2 7 1 1 7]}, TensorConstant{[241 334 2..6 273 273]})
   1.7%    65.9%       0.008s       8.02e-05s    100   221   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.1, TensorConstant{[4 5 5 2 4..5 1 3 3 3]}, TensorConstant{[364 311 1..7 181 166]})
   1.6%    67.5%       0.008s       7.52e-05s    100   212   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(Alloc.0, Split{11}.10, TensorConstant{[7 2 6 2 4..5 0 1 0 5]}, TensorConstant{[565 565 4..6 269 103]})
   1.4%    68.9%       0.007s       6.55e-05s    100   245   AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}(AdvancedIncSubtensor{inplace=False,  set_instead_of_inc=False}.0, Elemwise{Neg}[(0, 0)].0, TensorConstant{[4 5 5 2 4..5 1 3 3 3]}, TensorConstant{[296 153 2..1 102 126]})
   ... (remaining 278 Apply instances account for 31.08%(0.14s) of the runtime)

Here are tips to potentially make your code run faster
                 (if you think of new ones, suggest them on the mailing list).
                 Test them first, as they are not guaranteed to always provide a speedup.
  - Try the Theano flag floatX=float32
  - Try installing amdlibm and set the Theano flag lib.amdlibm=True. This speeds up only some Elemwise operation.

In [ ]:
rating_model.profile(rating_model.logpt, n=100).summary()

Moar Plots


In [ ]:
sns.set_palette('Paired', n_teams)

f, ax = plt.subplots(figsize=(16,10))
ax.set_ylim(0,2.0)
[sns.kdeplot(trace['sigma'][:,i], shade=True, alpha=0.55, legend=True, ax=ax, label=m) for i,m in enumerate(maps)]
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

In [ ]:
f, axes = plt.subplots(n_maps,1,figsize=(12,34), sharex=True)
for m, ax in enumerate(axes):
    ax.set_title(dict(enumerate(maps))[m])
    ax.set_ylim(0,2.0)
    [sns.kdeplot(trace['rating | map'][:,m,tmap[i]], shade=True, alpha=0.55, legend=False ,
                 ax=ax, label=v['Name']) for i,v in filt.iterrows()]
ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

In [ ]:
filt

In [ ]:
i = np.where(teams==7880)
j = np.where(teams==7924)

diff = (trace['rating'][:,j] - trace['rating'][:,i]).flatten()
kappa = 32./(1+np.exp(-1.*trace['alpha']*diff))-16.
fig, (ax1,ax2) = plt.subplots(1,2,figsize=(10,6))
sns.kdeplot(kappa, ax=ax2)
sns.kdeplot(diff, ax=ax1)

In [18]:
a = pd.Series({v['Name']: np.percentile(ap_trace['rating_%s'%max(obs_period)][:,tmap[i]], 75) for i,v in filt.iterrows()}).sort_values(ascending=False)
a = pd.Series(np.arange(1,len(filt)+1), a.index)
b = pd.Series({v['Name']: np.percentile(trace['rating_%s'%max(obs_period)][:,tmap[i]], 75) for i,v in filt.iterrows()}).sort_values(ascending=False)
b = pd.Series(np.arange(1,len(filt)+1), b.index)
pd.DataFrame([a,b], index=['approx', 'nuts']).T.sort_values('nuts')


Out[18]:
approx nuts
FaZe 2 1
SK 3 2
Astralis 5 3
G2 6 4
Cloud9 1 5
Liquid 4 6
North 14 7
fnatic 11 8
OpTic 7 9
mousesports 10 10
EnVyUs 8 11
NiP 16 12
Renegades 12 13
Virtus.pro 13 14
Luminosity 9 15
BIG 20 16
CLG 17 17
Misfits 18 18
Immortals 23 19
NRG 19 20
Heroic 24 21
GODSENT 22 22
LDLC 21 23
compLexity 15 24
Rogue 27 25
Splyce 25 26
Ghost 26 27

In [ ]:
a = np.arange(1,n_periods)
with pm.Model() as rating_model:
    
    rho = pm.Normal('rho', 0, 1)
    omega = pm.HalfCauchy('omega', 0.5)
    tau = pm.HalfCauchy('tau', 0.5)
    gamma = pm.HalfCauchy('gamma', 0.5)
    theta_tilde = pm.Normal('rate_t', mu=0, sd=1, shape=(n_maps, n_teams))
    
    time_rating = [pm.Normal('rating_0', 0, omega, shape=n_teams)]
    time_variance = [pm.Lognormal('sd_0', tt.log(omega), tau, shape=n_teams)]
    time_rating_map = [pm.Deterministic('rating_0 | map', time_rating[0] + gamma * theta_tilde)]
    
    for i in a:
        time_variance.append(pm.Lognormal('sd_'+str(i), tt.log(time_variance[i-1]), tau, shape=n_teams))
        time_rating.append(pm.Normal('rating_'+str(i), rho*time_rating[i-1], time_variance[i], shape=n_teams))
        time_rating_map.append(pm.Deterministic('rating_'+str(i)+' | map', time_rating[i] + gamma * theta_tilde))
    
    diff = [time_rating_map[i][obs_map[obs_period == i], obs_team_1[obs_period == i]] - time_rating_map[i][obs_map[obs_period == i], obs_team_2[obs_period == i]] for i in range(n_periods)]
    diff = tt.concatenate(diff)
    p = 0.5*pm.math.tanh(diff)+0.5
    #alpha = 0.31
    #kappa = 16.*pm.math.tanh(alpha*diff)
    #tau = pm.HalfNormal('tau', 10)
    
    #sc = pm.Normal('observed score diff', kappa, tau, observed=obs['score_diff'])
    wl = pm.Bernoulli('observed wl', p=p, observed=(obs['Team 1 ID'] == obs['winner']).values)