Win/Loss Rating Model Prediction

Load the model and make predictions


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

Get a list of all CS Games


In [31]:
import cfscrape # need nodejs
import json
scraper = cfscrape.create_scraper()
games = json.loads(scraper.get("http://thunderpick.com/api/matches").content)
games = pd.DataFrame(games['data'])
games = games[games.gameId == 6].sort_values('startTime')
games = games[games['championship'].str.contains('ESEA')]

bet_games = []
for i,v in games.iterrows():
    if((v['isTournament'] == False )& (v['canWager'] == True)):
        ratio = v['matchBet']['buckets'][0]['amount']/v['matchBet']['buckets'][1]['amount']
        odds = (ratio**-1+1, ratio+1)
        wr = (odds[1]/np.sum(odds)*100., odds[0]/np.sum(odds)*100.)
        det = json.loads(scraper.get('https://thunderpick.com/api/matches/'+str(v['id'])).content)['data']
        print('Date: %s  |  Event: %s  | (BO%s) %s vs. %s  |  (%.1f:%.1f) | Total Coins: %i' % 
              (v['startTime'][:10], v['championship'], det['bestOfMaps'], v['matchBet']['buckets'][0]['label'], 
               v['matchBet']['buckets'][1]['label'], wr[0], wr[1], v['matchBet']['amount']))
        bet_games.append({'1': v['matchBet']['buckets'][0]['label'], '2': v['matchBet']['buckets'][1]['label'], 'bo': det['bestOfMaps'], 'o1': odds[0], 'o2': odds[1], 'wr': wr[0]})
bet_games = pd.DataFrame(bet_games)


Date: 2017-10-30  |  Event: ESEA MDL Season 26  | (BO1) TEAM5 vs. Nexus  |  (52.3:47.7) | Total Coins: 8601
Date: 2017-10-30  |  Event: ESEA MDL Season 26  | (BO1) Kinguin vs. Red Reserve  |  (64.8:35.2) | Total Coins: 12093
Date: 2017-10-30  |  Event: ESEA MDL Season 26  | (BO1) Red Reserve vs. Nexus  |  (73.7:26.3) | Total Coins: 6644
Date: 2017-10-30  |  Event: ESEA MDL Season 26  | (BO1) Kinguin vs. Space Soldiers  |  (19.7:80.3) | Total Coins: 8134
Date: 2017-10-30  |  Event: ESEA MDL Season 26  | (BO1) Fragsters vs. igame.com  |  (65.9:34.1) | Total Coins: 5134
Date: 2017-10-30  |  Event: ESEA MDL Season 26  | (BO1) Nexus vs. aAa  |  (35.0:65.0) | Total Coins: 5000
Date: 2017-10-31  |  Event: ESEA MDL Season 26  | (BO1) SoaR vs. Morior Invictus  |  (46.2:53.8) | Total Coins: 5107
Date: 2017-10-31  |  Event: ESEA MDL Season 26  | (BO1) Rise Nation vs. Gale Force  |  (59.6:40.4) | Total Coins: 5200
Date: 2017-10-31  |  Event: ESEA MDL Season 26  | (BO1) Muffin Lightning vs. Good People  |  (60.8:39.2) | Total Coins: 5100
Date: 2017-10-31  |  Event: ESEA MDL Season 26  | (BO1) seadoggs vs. conspiracy  |  (75.2:24.8) | Total Coins: 6986
Date: 2017-10-31  |  Event: ESEA MDL Season 26  | (BO1) Noxide vs. SIN  |  (40.0:60.0) | Total Coins: 5000
Date: 2017-11-01  |  Event: ESEA MDL Season 26  | (BO1) Gale Force vs. GX  |  (60.0:40.0) | Total Coins: 5000
Date: 2017-11-01  |  Event: ESEA MDL Season 26  | (BO1) SoaR vs. Mythic  |  (40.0:60.0) | Total Coins: 5000
Date: 2017-11-01  |  Event: ESEA MDL Season 26  | (BO1) CLG Academy vs. Naventic  |  (47.0:53.0) | Total Coins: 5000

Load Ratings Model


In [9]:
TEAM_SET = 'mdleu'

teams = np.load('saved_model/'+TEAM_SET+'/teams.npy')
maps = np.load('saved_model/'+TEAM_SET+'/maps.npy')
filt = np.chararray.lower(np.load('saved_model/'+TEAM_SET+'/filter_teams.npy'))
h_teams = pd.read_csv('hltv_csv/teams.csv').set_index('ID').loc[teams]
h_teams = fix_teams(h_teams)
h_teams.Name = h_teams.Name.str.lower()
h_teams_filt = h_teams[h_teams.Name.isin(filt)]

rating_model = prep_pymc_model(len(teams), len(maps))
trace = pm.backends.text.load('saved_model/'+TEAM_SET+'/trace', model=rating_model)

Ban/Pick Predictions


In [10]:
h_bp = pd.read_csv('hltv_csv/picksAndBans.csv').set_index('Match ID')
h_matches = pd.read_csv('hltv_csv/matchResults.csv').set_index('Match ID')
h_matches['Date'] = pd.to_datetime(h_matches['Date'])
h_matches = h_matches[h_matches['Date'] >= dt.datetime(2017,1,1)]
h_bp = h_bp.join(h_matches[['Date']], how='left')
h_bp['Date'] = pd.to_datetime(h_bp['Date'])
h_bp = h_bp[h_bp['Date'] >= dt.datetime(2017,1,1)]

In [11]:
def model_mp(train, t1, t2):
    tab = train[train['Team'].isin([t1, t2])].groupby(['Team', ' Pick Type', 'Map'])['Date'].count().unstack([' Pick Type', 'Team']).fillna(0)
    return (tab/tab.sum(axis=0)).mean(level=0,axis=1)# get average

def model_played(train, t1, t2):
    a = train[train['Team 1 ID'].isin([t1,t2])].groupby(['Team 1 ID', 'Map'])['Date'].count()
    b = train[train['Team 2 ID'].isin([t1,t2])].groupby(['Team 2 ID', 'Map'])['Date'].count()
    c = pd.DataFrame([a,b], index=['a','b']).T.fillna(0)
    c = (c['a']+c['b']).unstack(level=0).fillna(0)
    return (c/c.sum()).mean(axis=1)

def predict_map(func, data, t1, t2):
    res = func(data, t1, t2)
    return res.loc[res.index != 'Default'].sort_values(ascending=False)

Bet Predictions


In [36]:
money = 4500.
bet_games['1'] = bet_games['1'].str.lower().replace({'ex-denial': 'denial', 'red reserve': 'japaleno'})
bet_games['2'] = bet_games['2'].str.lower().replace({'ex-denial': 'denial', 'red reserve': 'japaleno'})
matches = bet_games[bet_games['1'].isin(filt) & bet_games['2'].isin(filt)].drop_duplicates()
def sig(x):
    return 1 / (1 + np.exp(-x))
def abs_norm_interval(start,end,loc,scale):
    return (norm.cdf(end,loc,scale) - norm.cdf(start,loc,scale)) + (norm.cdf(-1*start,loc,scale) - norm.cdf(-1*end,loc,scale))

t_rating = trace['rating']
t_map_rating = trace['rating | map']
t_alpha = 0.3485
for i,v in matches.iterrows():
    t1_id = h_teams_filt[h_teams_filt.Name == v['1']].index[0]; t1_ind = np.where(teams == t1_id)[0][0];
    t2_id = h_teams_filt[h_teams_filt.Name == v['2']].index[0]; t2_ind = np.where(teams == t2_id)[0][0];
    trace_1 = t_rating[:,t1_ind]; trace_2 = t_rating[:,t2_ind]
    mr_1 = trace_1.mean(); mr_2 = trace_2.mean();
    diff = trace_1-trace_2
    p_wl = sig(diff)
    wr_25 = np.percentile(p_wl, 25); wr_75 = np.percentile(p_wl, 75)
    kelly_pct_1 = ((v['o1']*np.percentile(p_wl, 45)-(1.-np.percentile(p_wl, 45)))/v['o1'])*0.15
    kelly_pct_2 = ((v['o2']*(1.-np.percentile(p_wl, 45))-(np.percentile(p_wl, 45)))/v['o2'])*0.15
    print('%s (%.3f) vs %s (%.3f) - P:%.2f%% - %.2f%% - %.2f%%  -  K: %.1f%% (%i) - %.1f%% (%i)' % 
          (v['1'], mr_1, v['2'], mr_2,  wr_25*100, v['wr'], wr_75*100, kelly_pct_1*100., 
           kelly_pct_1*money, kelly_pct_2*100., kelly_pct_2*money))


team5 (0.026) vs nexus (1.330) - P:13.12% - 52.34% - 33.24%  -  K: -3.4% (-151) - 10.7% (479)
kinguin (1.598) vs japaleno (1.133) - P:48.54% - 64.82% - 72.78%  -  K: 4.7% (213) - 3.1% (141)
japaleno (1.133) vs nexus (1.330) - P:31.96% - 73.66% - 58.62%  -  K: 0.0% (0) - 7.0% (312)
kinguin (1.598) vs space soldiers (2.443) - P:21.36% - 19.67% - 40.38%  -  K: 2.1% (95) - 7.4% (330)
fragsters (1.186) vs igame.com (1.074) - P:41.28% - 65.91% - 64.20%  -  K: 2.7% (120) - 4.8% (217)
nexus (1.330) vs aaa (0.804) - P:43.22% - 35.00% - 78.90%  -  K: 6.8% (304) - 0.3% (13)

In [ ]:
PRINT_RD_DIFF = False
for i,v in matches.iterrows():
    t1_id = h_teams_filt[h_teams_filt.Name == v['1']].index[0]; t1_ind = np.where(teams == t1_id)[0][0];
    t2_id = h_teams_filt[h_teams_filt.Name == v['2']].index[0]; t2_ind = np.where(teams == t2_id)[0][0];
    print('---------- %s vs %s ---------------------------------' % (v['1'], v['2']))
    pred_maps = predict_map(model_played, h_matches, t1_id, t2_id)
    pred_maps = pred_maps/pred_maps.sum()
    for m,s in pred_maps.iteritems():
        m_ind = np.where(maps == m)[0][0]
        trace_1 = t_map_rating[:,m_ind,t1_ind]; trace_2 = t_map_rating[:,m_ind,t2_ind]
        mr_1 = trace_1.mean(); mr_2 = trace_2.mean();
        diff = trace_1-trace_2
        p_wl = sig(diff)
        wr_25 = np.percentile(p_wl, 25); wr_75 = np.percentile(p_wl, 75)
        kappa = 32*sig(t_alpha*diff)-16.
        kelly_pct_1 = ((v['o1']*np.percentile(p_wl, 45)-(1.-np.percentile(p_wl, 45)))/v['o1'])*0.1
        kelly_pct_2 = ((v['o2']*(1.-np.percentile(p_wl, 45))-(np.percentile(p_wl, 45)))/v['o2'])*0.1
        print('    Map: %s (%.2f)  -  %s (%.3f) vs %s (%.3f) - P:%.2f%% - %.2f%% - %.2f%%  -  K: %.1f%% (%i) - %.1f%% (%i)' % 
             (m, s*100., v['1'], mr_1, v['2'], mr_2,  wr_25*100, v['wr'], wr_75*100, kelly_pct_1*100., 
               kelly_pct_1*money, kelly_pct_2*100., kelly_pct_2*money))
        
        if(PRINT_RD_DIFF):
            p_sc = [abs_norm_interval(x[0],x[1],kappa,trace['sigma'][:,m_ind]) for x in [[1.5,3.5],[3.5,5.5],[5.5,7.5],[7.5,9.5],[9.5,16]]]
            for i,sd in enumerate(['2 - 3 Rounds', '4 - 5 rounds', '6 - 7 rounds', '8 - 9 rounds', '10 rounds or more']):
                sc_25 = np.percentile(p_sc[i], 25); sc_75 = np.percentile(p_sc[i], 75)
                print('      %s : %.2f%% - %.2f%%' % (sd, sc_25*100, sc_75*100))

In [ ]:
np.inner(np.ones((8,25)), np.ones((8,25))).shape

In [ ]:
np.ones((8,25)).flatten().shape

In [ ]:
np.zeros((8000, 200))

In [ ]:
plt.ylim(0,1.2)
sns.kdeplot(trace_1, shade=True, alpha=0.65, legend=True, label=v['1'])
sns.kdeplot(trace_2, shade=True, alpha=0.65, legend=True, label=v['2'])

In [ ]:
h_bp.groupby('Match ID').first().count()

In [ ]:
h_bp

In [ ]: