Пример #1
0
    def play_game(self):

        elo = Elo()

        # get expected results for all systems
        wl1 = self.team1.wl
        wl2 = self.team2.wl

        wlmx = (wl1 + (1 - wl2)) / 2

        elo_diff = self.team1.elo - self.team2.elo
        dim_diff = self.team1.dim - self.team2.dim
        mov_diff = self.team1.mov - self.team2.mov
        dimv_diff = self.team1.dimv - self.team2.dimv

        # baseline: 1.215, 1.187, 1.189, 1.1646
        if self.loc == "H":
            elo_diff += h_adv
            dim_diff += h_adv
            mov_diff += h_adv
            dimv_diff += h_adv
        elif self.loc == "A":
            elo_diff -= h_adv
            dim_diff -= h_adv
            mov_diff -= h_adv
            dimv_diff -= h_adv

        # basic elo systems
        elox = elo.get_expected(elo_diff)
        dimx = elo.get_expected(dim_diff)

        # mov systems
        movx = elo.get_expected(mov_diff)
        dimvx = elo.get_expected(dimv_diff)

        # glicko
        # glickox = glicko.get_expected(self.team1.glicko, self.team2.glicko)

        # step
        # stephx = steph.get_expected(self.team1.steph, self.team2.steph)

        self.team1.played_game()
        self.team2.played_game()

        self.team1.add_win()
        self.team2.add_loss()

        self.team1.calc_win_loss()
        self.team2.calc_win_loss()

        p1_x = {
            "wlm": wlmx,
            "elo": elox,
            "dim": dimx,
            "mov": movx,
            "dimv": dimvx,
            # "glicko":glickox,
            # "steph":stephx
        }
        p2_x = {
            "wlm": 1 - wlmx,
            "elo": 1 - elox,
            "dim": 1 - dimx,
            "mov": 1 - movx,
            "dimv": 1 - dimvx,
            # "glicko":glickox,
            # "steph":stephx
        }

        self.team1.add_errors(1, p1_x)
        self.team2.add_errors(0, p2_x)

        # update ratings
        elo_K = elo_set['K']
        elo_delta = elo.get_delta(1, elox, elo_K)

        if self.games_played <= 2:
            dim_K = 170
        elif self.games_played <= 4:
            dim_K = 97.5
        elif self.games_played <= 5:
            dim_K = 67
        elif self.games_played <= 8:
            dim_K = 67
        elif self.games_played <= 10:
            dim_K = 30
        else:
            dim_K = dim_set['K']
        dim_delta = elo.get_delta(1, dimx, dim_K)

        mov_K = mov_set['K']
        mov_delta = elo.get_mov_delta(1, movx, self.margin,
                                      (self.team1.mov - self.team2.mov), mov_K)

        if self.games_played <= 4:
            dimv_K = 60
        # else:
        #     dimv_K = 170.59 * (self.games_played ** -0.673)
        elif self.games_played <= 8:
            dimv_K = 45
        elif self.games_played <= 12:
            dimv_K = 31
        elif self.games_played <= 16:
            dimv_K = 28.5
        elif self.games_played <= 20:
            dimv_K = 22
        elif self.games_played <= 24:
            dimv_K = 18
        elif self.games_played <= 28:
            dimv_K = 18
        elif self.games_played <= 32:
            dimv_K = 18
        else:
            dimv_K = dimv_set['K']
        dimv_delta = elo.get_mov_delta(1, dimvx, self.margin,
                                       (self.team1.dimv - self.team2.dimv),
                                       dimv_K)

        self.team1.elo += elo_delta
        self.team1.dim += dim_delta
        self.team1.mov += mov_delta
        self.team1.dimv += dimv_delta

        self.team2.elo -= elo_delta
        self.team2.dim -= dim_delta
        self.team2.mov -= mov_delta
        self.team2.dimv -= dimv_delta

        return self.team1, self.team2
Пример #2
0
def test_systems():
    # load season data
    sdf = pd.read_csv('./data/SeasonResults.csv')

    # separate data into individual seasons
    seasons = list(sdf.Season.unique())

    # set how long before glicko updates
    g_resolve = glicko_set['resolve_time']

    # track error per season
    sea_error = []
    wkbywk_err = None
    first_season = seasons[0]
    for season in tqdm(seasons):
        sea_df = sdf.loc[sdf.Season == season]

        # sort in order
        sea_df = sea_df.sort_values(by='DayNum')
        sea_df = sea_df[[
            'Season', 'DayNum', 'WTeam', 'WScore', 'LTeam', 'LScore'
        ]]

        # get list of teams in season
        wteams = list(sea_df.WTeam.unique())
        lteams = list(sea_df.LTeam.unique())
        teams = list(set((wteams + lteams)))

        load_preseason = False
        # use for preseason rankings
        if season > first_season:
            load_preseason = True
        else:
            prev_team_dir = None

        # create team directory to track everything
        team_dir = init_td(teams, load_preseason, prev_team_dir)

        # init classes
        elo = Elo()
        glicko = Glicko()

        # track error per week
        week_err = []
        wk_l5err = wk_eloerr = wk_ieloerr = wk_gerr = wk_tserr = 0
        wk_gp = 0
        wk_thres = 7
        wk_cnt = 0

        # iterate games
        for index, row in sea_df.iterrows():
            t1 = row['WTeam']
            t2 = row['LTeam']
            team1 = team_dir[t1]
            team2 = team_dir[t2]

            # set max number of games for testing
            # if (team1.gp > 11):
            #     continue
            # if (team2.gp > 11):
            #     continue

            # tracking error by week, so check if it's a new week
            day_num = row['DayNum']
            if day_num > wk_thres:
                # it's a new week
                # add end date of next week
                wk_thres += 7
                # ignore weeks that don't have games
                if wk_gp > 0:
                    wk_l5err /= wk_gp
                    wk_eloerr /= wk_gp
                    wk_ieloerr /= wk_gp
                    wk_gerr /= wk_gp
                    wk_tserr /= wk_gp
                    week_err.append([
                        season, wk_cnt, wk_l5err, wk_eloerr, wk_ieloerr,
                        wk_gerr, wk_tserr
                    ])
                wk_cnt += 1
                wk_l5err = wk_eloerr = wk_ieloerr = wk_gerr = wk_serr = 0
                wk_gp = 0

            # track games played this week
            wk_gp += 1

            margin = row['WScore'] - row['LScore']

            # get expected outcome for each system
            log5_expect = l5_x(team1.wl, team2.wl)
            elo_expect = elo.x(team1.elo, team2.elo)
            ielo_expect = elo.x(team1.ielo, team2.ielo)
            ts_expect = ts_win_prob([team1.tskill], [team2.tskill])

            # special steps for glicko expectation
            mu, phi = glicko.scale_down(team1.glicko, team1.g_phi)
            mu2, phi2 = glicko.scale_down(team2.glicko, team2.g_phi)
            impact = glicko.reduce_impact(phi2)
            glicko_expect = glicko.get_expected(mu, mu2, impact)

            # update error
            if log5_expect == 0:
                log5_expect += .001
            expects = [
                log5_expect, elo_expect, ielo_expect, glicko_expect, ts_expect
            ]
            t1_errors = calc_error(expects, 1)
            t2_errors = t1_errors
            team1.update_errors(t1_errors)
            team2.update_errors(t2_errors)

            # update week error
            wk_l5err += t1_errors[0]
            wk_eloerr += t1_errors[1]
            wk_ieloerr += t1_errors[2]
            wk_gerr += t1_errors[3]
            wk_tserr += t1_errors[4]

            ## update ratings ##

            # elo
            elo_delta = elo.get_delta(elo_expect)
            t1_ielo_delta, t2_ielo_delta = elo.get_ielo_delta(
                ielo_expect, margin, team1, team2)

            team1.update_rating("elo", elo_delta)
            team1.update_rating("ielo", t1_ielo_delta)

            team2.update_rating("elo", -elo_delta)
            team2.update_rating("ielo", t2_ielo_delta)

            team1.update_ts(team2.tskill, "won")
            team2.update_ts(team1.tskill, "lost")

            # log5
            team1.add_win()
            team2.add_loss()

            # glicko (second arg is win or loss)
            team1.add_glicko_opp(team2, 1)
            team2.add_glicko_opp(team1, 0)

            # check if time to resolve
            if team1.gp % g_resolve == 0:
                team1 = glicko.update(team1)
            if team2.gp % g_resolve == 0:
                team2 = glicko.update(team2)

            team_dir[t1] = team1
            team_dir[t2] = team2

        # add week_err df to season trackers
        week_err = pd.DataFrame(
            week_err,
            columns=['Season', 'Week', 'Log5', 'Elo', 'IElo', 'Glicko', 'TS'])
        if wkbywk_err is None:
            wkbywk_err = week_err
        else:
            wkbywk_err = pd.concat([wkbywk_err, week_err])

        # find total error in season
        sea_gp = 0
        sea_l5err = 0
        sea_eloerr = 0
        sea_ieloerr = 0
        sea_gerr = 0
        sea_tserr = 0
        for team in team_dir.values():
            sea_gp += team.gp
            sea_l5err += team.l5err
            sea_eloerr += team.eloerr
            sea_ieloerr += team.ieloerr
            sea_gerr += team.glickoerr
            sea_tserr += team.tserr
        sea_l5err /= sea_gp
        sea_eloerr /= sea_gp
        sea_ieloerr /= sea_gp
        sea_gerr /= sea_gp
        sea_tserr /= sea_gp

        sea_error.append(
            [season, sea_l5err, sea_eloerr, sea_ieloerr, sea_gerr, sea_tserr])

        # store rankings for preseason rankings next season
        prev_team_dir = team_dir

    final_table = pd.DataFrame(
        sea_error, columns=['Season', 'Log5', 'Elo', 'IElo', 'Glicko', 'TS'])
    print(final_table)
    print(final_table.mean())

    wkbywk = pd.DataFrame(
        wkbywk_err,
        columns=['Season', 'Week', 'Log5', 'Elo', 'IElo', 'Glicko', 'TS'])
    wkbywk = wkbywk.drop(columns=['TS'])
    wk_avg = wkbywk.groupby('Week').mean()

    def plot_weeks(wk_avg):
        import matplotlib.pyplot as plt
        fig, ax = plt.subplots(figsize=(15, 7))
        plt.plot(wk_avg.index.values, wk_avg.Log5, '-k', label='Log5 Baseline')
        plt.plot(wk_avg.index.values, wk_avg.Elo, '-c', label='Elo')
        plt.plot(wk_avg.index.values, wk_avg.IElo, '-b', label='Improved Elo')
        plt.plot(wk_avg.index.values, wk_avg.Glicko, '-r', label='Glicko')

        plt.xlabel("Week of Season")
        plt.ylabel("Cross Entropy Error")
        xint = range(0, math.ceil(17) + 1)
        plt.xticks(xint)

        plt.legend(loc='upper left')

        plt.show()
        return

    plot_weeks(wk_avg)
    return