Win/Loss Rating Model Prediction

Load the model and make predictions


In [121]:
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 wl_model.spcl_case import *
plt.style.use('fivethirtyeight')
%matplotlib inline

Get a list of all CS Games


In [122]:
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')

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)
bet_games['1'] = bet_games['1'].str.lower()
bet_games['2'] = bet_games['2'].str.lower()


Date: 2017-11-15  |  Event: WCA 2017  | (BO3) BIG vs. Natus Vincere  |  (24.1:75.9) | Total Coins: 35960
Date: 2017-11-15  |  Event: Mother Russia  | (BO1) GoodJob vs. Tricked  |  (22.8:77.2) | Total Coins: 8774
Date: 2017-11-15  |  Event: X-BET.co Invitational  | (BO1) HAVU vs. EnVyUs Academy  |  (72.1:27.9) | Total Coins: 8346
Date: 2017-11-15  |  Event: CEVO Main Season 13  | (BO3) WASD vs. Movistar Riders  |  (61.1:38.9) | Total Coins: 5400
Date: 2017-11-15  |  Event: Mother Russia  | (BO1) GameAgents vs. Nexus  |  (41.3:58.7) | Total Coins: 5195
Date: 2017-11-15  |  Event: CEVO Main Season 13  | (BO3) Pompa Team vs. PURSI$EURA  |  (55.0:45.0) | Total Coins: 5000
Date: 2017-11-15  |  Event: Nordic Championship  | (BO1) HAVU vs. Passions  |  (60.0:40.0) | Total Coins: 5000
Date: 2017-11-15  |  Event: ECS Season 4 Development League  | (BO1) Virtus.pro vs. mousesports  |  (45.7:54.3) | Total Coins: 8938
Date: 2017-11-15  |  Event: Intel Extreme Masters 2017  | (BO1) SK vs. Astralis  |  (66.0:34.0) | Total Coins: 17940
Date: 2017-11-15  |  Event: Intel Extreme Masters 2017  | (BO1) NiP vs. Cloud9  |  (39.6:60.4) | Total Coins: 18312
Date: 2017-11-15  |  Event: ECS Season 4 Development League  | (BO1) mousesports vs. Virtus.pro  |  (51.4:48.6) | Total Coins: 7384
Date: 2017-11-15  |  Event: Mother Russia  | (BO1) eXtatus vs. Gatekeepers  |  (68.6:31.4) | Total Coins: 5420
Date: 2017-11-15  |  Event: Nordic Championship  | (BO1) HAVU vs. NYYRIKKI  |  (65.0:35.0) | Total Coins: 5000
Date: 2017-11-15  |  Event: CEVO Main Season 13  | (BO3) Nexus vs. ZetMac  |  (65.0:35.0) | Total Coins: 5000
Date: 2017-11-15  |  Event: ESEA MDL Season 26  | (BO3) eXtatus vs. Space Soldiers  |  (24.5:75.5) | Total Coins: 15312
Date: 2017-11-15  |  Event: Legend Series  | (BO1) Epsilon vs. squared  |  (65.0:35.0) | Total Coins: 5000
Date: 2017-11-15  |  Event: Skinhub CS:GO Championship  | (BO3) North Academy vs. Red Reserve  |  (73.5:26.5) | Total Coins: 7550
Date: 2017-11-15  |  Event: ESEA MDL Season 26  | (BO3) Virtus.pro vs. AGO  |  (60.7:39.3) | Total Coins: 15574
Date: 2017-11-15  |  Event: Intel Extreme Masters 2017  | (BO1) EnVyUs vs. Cloud9  |  (39.3:60.7) | Total Coins: 15646
Date: 2017-11-15  |  Event: Intel Extreme Masters 2017  | (BO1) NiP vs. TheMongolz  |  (68.3:31.7) | Total Coins: 16567
Date: 2017-11-15  |  Event: Intel Extreme Masters 2017  | (BO1) EnVyUs vs. NiP  |  (43.6:56.4) | Total Coins: 15250
Date: 2017-11-15  |  Event: Intel Extreme Masters 2017  | (BO1) Cloud9 vs. SK  |  (39.5:60.5) | Total Coins: 15183
Date: 2017-11-15  |  Event: Intel Extreme Masters 2017  | (BO1) TheMongolz vs. Astralis  |  (32.9:67.1) | Total Coins: 15954
Date: 2017-11-16  |  Event: Intel Extreme Masters 2017  | (BO1) FaZe vs. Gambit  |  (76.7:23.3) | Total Coins: 15462
Date: 2017-11-16  |  Event: Intel Extreme Masters 2017  | (BO1) OpTic vs. Liquid  |  (47.5:52.5) | Total Coins: 15150
Date: 2017-11-16  |  Event: Intel Extreme Masters 2017  | (BO1) OpTic vs. Renegades  |  (52.4:47.6) | Total Coins: 15650
Date: 2017-11-16  |  Event: Intel Extreme Masters 2017  | (BO1) G2 vs. Liquid  |  (66.8:33.2) | Total Coins: 15050
Date: 2017-11-16  |  Event: ESEA MDL Season 26  | (BO3) SoaR vs. Ghost  |  (60.0:40.0) | Total Coins: 5000
Date: 2017-11-16  |  Event: Intel Extreme Masters 2017  | (BO1) Liquid vs. FaZe  |  (25.0:75.0) | Total Coins: 15000
Date: 2017-11-16  |  Event: Intel Extreme Masters 2017  | (BO1) G2 vs. OpTic  |  (69.8:30.2) | Total Coins: 15050
Date: 2017-11-16  |  Event: Intel Extreme Masters 2017  | (BO1) Renegades vs. Gambit  |  (46.0:54.0) | Total Coins: 15000
Date: 2017-11-16  |  Event: ESEA MDL Season 26  | (BO3) GX vs. Rise Nation  |  (40.0:60.0) | Total Coins: 5000
Date: 2017-11-16  |  Event: CyberGamer  | (BO3) Ground Zero vs. Masterminds  |  (62.0:38.0) | Total Coins: 5000
Date: 2017-11-16  |  Event: MakeMy.Bet Cup #1  | (BO3) Seed vs. LDLC  |  (62.0:38.0) | Total Coins: 5000
Date: 2017-11-16  |  Event: Legend Series  | (BO1) Venatores vs. Windigo  |  (45.0:55.0) | Total Coins: 5000
Date: 2017-11-16  |  Event: Legend Series  | (BO1) Nexus vs. WASD  |  (60.0:40.0) | Total Coins: 5000
Date: 2017-11-16  |  Event: Nordic Championship  | (BO1) Acapella vs. HAVU  |  (38.0:62.0) | Total Coins: 5000
Date: 2017-11-16  |  Event: Skinhub CS:GO Championship  | (BO3) TEAM5 vs. PRIDE  |  (38.0:62.0) | Total Coins: 5000

Load Ratings Model


In [118]:
TEAM_SET = 'all_player_sc'

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

h_teams = pd.read_csv('wl_model/hltv_csv/teams_w_ranking.csv').set_index('ID').dropna() # top 360 only
h_teams = fix_teams(h_teams)
h_teams.Name = h_teams.Name.str.lower()
h_matches = pd.read_csv('wl_model/hltv_csv/matchResults.csv').set_index('Match ID')
h_matches['Date'] = pd.to_datetime(h_matches['Date'])
h_players = pd.read_csv('wl_model/hltv_csv/matchLineups.csv').set_index('Match ID')
h_matches = h_matches.join(h_players)

player_col_names = ['Team 1 Player 1', 'Team 1 Player 2', 'Team 1 Player 3', 'Team 1 Player 4', 'Team 1 Player 5',
                 'Team 2 Player 1', 'Team 2 Player 2', 'Team 2 Player 3', 'Team 2 Player 4', 'Team 2 Player 5',]

In [139]:
tab_match = pd.DataFrame(np.concatenate([h_matches[['Date','Team 1 ID']+player_col_names[:5]].values, 
                h_matches[['Date', 'Team 2 ID']+player_col_names[5:]].values]), columns=['date', 'team','1','2','3','4','5']).set_index('team')
teams_from_games = h_teams[h_teams.Name.isin(np.concatenate([bet_games['1'].values, bet_games['2'].values]))].drop_duplicates()
player_table = tab_match.loc[teams_from_games.index].sort_values('date').groupby(level=0).last().dropna()

Bet Predictions


In [141]:
money = 4500.
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))

matches = bet_games[bet_games['1'].isin(teams_from_games.Name.values) & bet_games['2'].isin(teams_from_games.Name.values)]

t_rating = trace['rating']
t_map_rating = trace['rating | map']
t_alpha = 0.5
t_sigma = trace['sigma']
for i,v in matches.iterrows():
    t1_id = teams_from_games[teams_from_games.Name == v['1']].index[0]; t1_ind = np.searchsorted(players, player_table.loc[t1_id, ['1','2','3','4','5']].values);
    t2_id = teams_from_games[teams_from_games.Name == v['2']].index[0]; t2_ind = np.searchsorted(players, player_table.loc[t2_id, ['1','2','3','4','5']].values);
    trace_1 = np.sum(t_rating[:,t1_ind], axis=1); trace_2 = np.sum(t_rating[:,t2_ind], axis=1)
    mr_1 = trace_1.mean(); mr_2 = trace_2.mean();
    diff = trace_1-trace_2
    p_wl = 1.-norm.cdf(0,loc=16*np.tanh(t_alpha*diff), scale=t_sigma)
    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.10
    kelly_pct_2 = ((v['o2']*(1.-np.percentile(p_wl, 45))-(np.percentile(p_wl, 45)))/v['o2'])*0.10
    print('%s (%.3f) vs %s (%.3f) - P:%.2f%% - %.2f%% - %.2f%%  -  K: %.1f%% (%i) - %.1f%% (%i)' % 
          (v['1'], mr_1, v['2'], mr_2,  v['wr']-wr_25*100, v['wr'], wr_75*100-v['wr'], kelly_pct_1*100., 
           kelly_pct_1*money, kelly_pct_2*100., kelly_pct_2*money))


big (0.934) vs natus vincere (0.999) - P:-15.87% - 24.06% - 29.56%  -  K: 3.2% (145) - 2.0% (90)
goodjob (0.077) vs tricked (0.584) - P:2.87% - 22.79% - 11.00%  -  K: 0.7% (32) - 5.7% (255)
havu (0.871) vs envyus academy (0.429) - P:6.38% - 72.11% - 3.83%  -  K: 4.8% (216) - 1.1% (47)
wasd (0.401) vs movistar riders (0.329) - P:14.92% - 61.11% - -0.27%  -  K: 2.3% (105) - 2.7% (121)
gameagents (-0.133) vs nexus (0.423) - P:24.27% - 41.29% - -7.39%  -  K: -0.9% (-39) - 6.4% (285)
havu (0.871) vs passions (0.770) - P:14.44% - 60.00% - 4.85%  -  K: 2.6% (115) - 2.5% (112)
virtus.pro (0.987) vs mousesports (1.248) - P:13.33% - 45.74% - -3.97%  -  K: 0.7% (31) - 4.4% (198)
sk (1.475) vs astralis (1.467) - P:20.80% - 66.00% - -10.62%  -  K: 1.6% (74) - 3.3% (150)
nip (1.255) vs cloud9 (1.323) - P:-1.44% - 39.61% - 12.83%  -  K: 2.3% (105) - 2.8% (124)
mousesports (1.248) vs virtus.pro (0.987) - P:-6.84% - 51.39% - 16.20%  -  K: 4.3% (192) - 0.8% (34)
extatus (0.666) vs gatekeepers (-0.283) - P:-9.88% - 68.63% - 23.48%  -  K: 7.6% (341) - -1.3% (-57)
havu (0.871) vs nyyrikki (-0.297) - P:-19.10% - 65.00% - 29.78%  -  K: 8.4% (377) - -2.2% (-98)
extatus (0.666) vs space soldiers (0.872) - P:-7.73% - 24.49% - 23.30%  -  K: 2.3% (105) - 3.2% (146)
epsilon (0.074) vs squared (-0.302) - P:4.03% - 65.00% - 10.01%  -  K: 4.6% (207) - 0.9% (40)
north academy (0.828) vs red reserve (0.677) - P:25.17% - 73.51% - -6.76%  -  K: 2.4% (107) - 2.9% (130)
virtus.pro (0.987) vs ago (0.954) - P:14.26% - 60.74% - -3.52%  -  K: 2.1% (93) - 2.9% (132)
envyus (1.034) vs cloud9 (1.323) - P:8.79% - 39.31% - 1.15%  -  K: 0.9% (39) - 4.5% (200)
nip (1.255) vs themongolz (0.229) - P:-17.36% - 68.31% - 22.72%  -  K: 8.0% (361) - -1.6% (-73)
envyus (1.034) vs nip (1.255) - P:10.03% - 43.61% - 0.64%  -  K: 1.1% (48) - 4.1% (183)
cloud9 (1.323) vs sk (1.475) - P:2.32% - 39.52% - 7.99%  -  K: 1.8% (82) - 3.4% (150)
themongolz (0.229) vs astralis (1.467) - P:26.60% - 32.91% - -23.09%  -  K: -2.3% (-103) - 8.8% (393)
faze (1.634) vs gambit (1.112) - P:7.00% - 76.72% - 2.00%  -  K: 5.3% (238) - 0.9% (42)
optic (1.181) vs liquid (1.159) - P:1.95% - 47.52% - 9.12%  -  K: 2.7% (120) - 2.3% (104)
optic (1.181) vs renegades (1.074) - P:3.92% - 52.40% - 9.69%  -  K: 3.0% (136) - 2.0% (89)
g2 (1.485) vs liquid (1.159) - P:4.75% - 66.78% - 3.24%  -  K: 4.2% (189) - 1.3% (58)
soar (0.361) vs ghost (0.271) - P:14.58% - 60.00% - 3.03%  -  K: 2.5% (113) - 2.5% (114)
liquid (1.159) vs faze (1.634) - P:1.76% - 25.00% - 6.92%  -  K: 0.8% (36) - 5.4% (241)
g2 (1.485) vs optic (1.181) - P:10.28% - 69.77% - 0.35%  -  K: 4.0% (178) - 1.6% (72)
renegades (1.074) vs gambit (1.112) - P:4.21% - 46.00% - 8.27%  -  K: 2.2% (99) - 2.8% (126)
gx (0.323) vs rise nation (0.444) - P:4.69% - 40.00% - 12.39%  -  K: 1.9% (85) - 3.3% (146)
seed (0.447) vs ldlc (0.733) - P:35.15% - 62.00% - -17.20%  -  K: -0.7% (-30) - 5.3% (238)
venatores (0.336) vs windigo (0.692) - P:20.40% - 45.00% - -2.95%  -  K: 0.0% (0) - 5.2% (233)
nexus (0.423) vs wasd (0.401) - P:18.57% - 60.00% - 0.78%  -  K: 1.9% (85) - 3.1% (138)
acapella (0.210) vs havu (0.871) - P:24.26% - 38.00% - -8.09%  -  K: -1.2% (-53) - 6.9% (311)
team5 (-0.332) vs pride (0.508) - P:27.08% - 38.00% - -17.05%  -  K: -1.8% (-80) - 7.6% (344)

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 [ ]: