Esempio n. 1
0
File: elo.py Progetto: Taxane/dppl
def rank(player1, player2):
    """ This function will calculate the TrueSkill ranking of each player. It
    accepts two players arguments. The first is the winning player, the second
    is the losing player. Both should be Profile objects. This will not save
    the players.

    Args:
        player1: The winning user profile
        player2: The losing user profile

    Returns:
        A tuple of (player1, player2)
    """
    DRAW_PROBABILITY = 0  # It's impossible to draw 1 on 1
    approx = lambda f: round(f, 6)  # Round all floats to 6 decimals

    ts = TrueSkill(draw_probability=DRAW_PROBABILITY)
    t1 = (ts.Rating(mu=player1.mu, sigma=player1.sigma), )
    t2 = (ts.Rating(mu=player2.mu, sigma=player2.sigma), )
    r1, r2 = tuple(x[0] for x in ts.transform_ratings(rating_groups=(t1, t2)))

    player1.mu = approx(r1.mu)
    player1.sigma = approx(r1.sigma)
    player1.exposure = approx(r1.exposure)

    player2.mu = approx(r2.mu)
    player2.sigma = approx(r2.sigma)
    player2.exposure = approx(r2.exposure)

    player1.save()
    player2.save()

    return player1, player2
Esempio n. 2
0
def createTrueskillRating():
    ts = TrueSkill(draw_probability=0.01) # 0.01 is arbitary small number
    beta = 25 / 6  # default value

    def win_probability(p1, p2):
        delta_mu = p1.mu - p2.mu
        sum_sigma = p1.sigma * p1.sigma + p2.sigma * p2.sigma
        denom = np.sqrt(2 * (beta * beta) + sum_sigma)
        return ts.cdf(delta_mu / denom)

    submit = sample_sub_pd
    submit[['Season', 'Team1', 'Team2']] = submit.apply(lambda r:pd.Series([int(t) for t in r.ID.split('_')]), axis=1)

    df_tour = reg_season_compact_pd
    teamIds = np.unique(np.concatenate([df_tour.WTeamID.values, df_tour.LTeamID.values]))
    ratings = { tid:ts.Rating() for tid in teamIds }

    def feed_season_results(season):
        print("season = {}".format(season))
        df1 = df_tour[df_tour.Season == season]
        for r in df1.itertuples():
            ratings[r.WTeamID], ratings[r.LTeamID] = rate_1vs1(ratings[r.WTeamID], ratings[r.LTeamID])

    def update_pred(season):
        beta = np.std([r.mu for r in ratings.values()]) 
        print("beta = {}".format(beta))
        submit.loc[submit.Season==season, 'Pred'] = submit[submit.Season==season].apply(lambda r:win_probability(ratings[r.Team1], ratings[r.Team2]), axis=1)

    for season in sorted(df_tour.Season.unique()[:-1]): # exclude last 4 years [:-4]/ last 1 year [:-1]
        feed_season_results(season)

#    update_pred(2014)
#    feed_season_results(2014)
#    update_pred(2015)
#    feed_season_results(2015)
#    update_pred(2016)
#    feed_season_results(2016)
#    update_pred(2017)
    feed_season_results(2017)
    update_pred(2018)

    submit.drop(['Season', 'Team1', 'Team2'], axis=1, inplace=True)
    submit.to_csv('Data/Predictions/trueskill_results2018.csv', index=None)
Esempio n. 3
0
class FrcTrueSkill:
    # Constants for sending requests to TBA.
    TBA_API_BASE = 'https://www.thebluealliance.com/api/v2'
    HEADERS = {"X-TBA-App-Id": "frc-4774:TrueSkill:1.0"}

    # Ranks for TrueSkill.rate. Lower is better.
    WON = 0
    LOST = 1

    TIE = (WON, WON)
    RED_WIN = (WON, LOST)
    BLUE_WIN = (LOST, WON)

    def __init__(self):
        self.env = TrueSkill(draw_probability=0.02)
        self.trueskills = {}
        self.events = {}
        self.nicknames = {}
        self.processed_matches = set()

        self.session = requests.Session()
        self.session.headers.update(self.HEADERS)

        self.get_previous_matches()

    def init_teams(self, red_alliance, blue_alliance):
        for team in red_alliance + blue_alliance:
            if team not in self.trueskills:
                self.trueskills[team] = self.env.Rating()

    def update(self, match_data):
        if match_data['key'] in self.processed_matches:
            return None

        alliances = match_data['alliances']
        red_teams = [int(x[3:]) for x in alliances['red']['teams']]
        blue_teams = [int(x[3:]) for x in alliances['blue']['teams']]

        self.init_teams(red_teams, blue_teams)
        # Update ratings based on result
        corrected_scores = self.correct_scores(match_data)

        if corrected_scores.red == corrected_scores.blue:  # Tied
            if corrected_scores.red == -1:
                return None  # No result yet
            ranks = self.TIE
        elif corrected_scores.red > corrected_scores.blue:  # Red beat blue
            ranks = self.RED_WIN
        else:
            ranks = self.BLUE_WIN

        new_red, new_blue = self.env.rate([
            [self.trueskills[t] for t in red_teams],
            [self.trueskills[t] for t in blue_teams]], ranks)

        # Store the new values
        for team, rating in zip(red_teams + blue_teams, new_red + new_blue):
            self.trueskills[team] = rating
        self.processed_matches.add(match_data['key'])
        return ranks

    def predict(self, red_alliance, blue_alliance):
        self.init_teams(red_alliance, blue_alliance)
        a = [self.trueskills[t] for t in red_alliance]
        b = [self.trueskills[t] for t in blue_alliance]
        delta_mu = sum([x.mu for x in a]) - sum([x.mu for x in b])
        sum_sigma = sum([x.sigma ** 2 for x in a + b])
        player_count = len(a) + len(b)
        denominator = (player_count * (self.env.beta**2) + sum_sigma) ** 0.5
        return backends.cdf(delta_mu / denominator)

    def skill(self, team):
        if team not in self.trueskills:
            self.trueskills[team] = self.env.Rating()
        return self.env.expose(self.trueskills[team])

    def get_teams_at_event(self, event):
        if event not in self.events:
            # We haven't got this one yet
            teams = self.session.get("%s/event/%s/teams" % (self.TBA_API_BASE, event))
            teams = teams.json()
            self.events[event] = [team["team_number"] for team in teams]
            for team in teams:
                self.nicknames[team["team_number"]] = team["nickname"]
        return self.events[event]

    def get_previous_matches(self):
        all_matches = []
        events = self.session.get(self.TBA_API_BASE + "/events/2017")
        events = events.json()

        for event in events:
            if event['event_type'] > 5:
                continue
            if event['start_date'] <= str(datetime.date(datetime.today()+timedelta(days=1))):
                matches = self.session.get("%s/event/%s/matches" % (self.TBA_API_BASE, event['key']))
                matches = matches.json()
                all_matches += matches
        all_matches.sort(key=lambda m: m['time'])

        for match in all_matches:
            self.update(match)

    def correct_scores(self, match):
        alliances = match['alliances']
        red = alliances['red']
        blue = alliances['blue']

        score = match['score_breakdown']
        red_score = red['score']
        blue_score = blue['score']
        if score is None:
            return Scores(red_score, blue_score)

        red_stats = score['red']
        blue_stats = score['blue']

        if red_stats["rotorRankingPointAchieved"]:
            red_score += 100
        if red_stats["kPaRankingPointAchieved"]:
            red_score += 20

        if blue_stats["rotorRankingPointAchieved"]:
            blue_score += 100
        if blue_stats["kPaRankingPointAchieved"]:
            blue_score += 20

        return Scores(red_score, blue_score)
Esempio n. 4
0
def win_probability(p1, p2):
    delta_mu = p1.mu - p2.mu
    sum_sigma = p1.sigma * p1.sigma + p2.sigma * p2.sigma
    denom = np.sqrt(2 * (beta * beta) + sum_sigma)
    return ts.cdf(delta_mu / denom)


submit = pd.read_csv('../input/SampleSubmissionStage1.csv')
submit[['Season', 'Team1', 'Team2']] = submit.apply(
    lambda r: pd.Series([int(t) for t in r.ID.split('_')]), axis=1)

df_tour = pd.read_csv('../input/RegularSeasonCompactResults.csv')
teamIds = np.unique(
    np.concatenate([df_tour.WTeamID.values, df_tour.LTeamID.values]))
ratings = {tid: ts.Rating() for tid in teamIds}


def feed_season_results(season):
    print("season = {}".format(season))
    df1 = df_tour[df_tour.Season == season]
    for r in df1.itertuples():
        ratings[r.WTeamID], ratings[r.LTeamID] = rate_1vs1(
            ratings[r.WTeamID], ratings[r.LTeamID])


def update_pred(season):
    beta = np.std([r.mu for r in ratings.values()])
    print("beta = {}".format(beta))
    submit.loc[submit.Season == season, 'Pred'] = submit[
        submit.Season == season].apply(
Esempio n. 5
0
class FrcTrueSkill:
    def __init__(self):
        self.env = TrueSkill(draw_probability=0.02)
        self.trueskills = {}
        self.events = {}
        self.get_previous_matches()
        #for team in self.trueskills.keys():
         #   print team, self.skill(team)

    def update(self, red_alliance, red_score, blue_alliance, blue_score):
        # Calculate teams per alliance
        for alliance in [red_alliance, blue_alliance]:
            for team in alliance:
                if not team in self.trueskills:
                    self.trueskills[team] = self.env.Rating()
        # Update ratings based on result
        if red_score == blue_score:  # Tied
            if red_score == -1:
                return  # No result yet
            ranks = [0, 0]
        elif red_score > blue_score:  # Red beat blue
            ranks = [0, 1]  # Lower is better
        else:
            ranks = [1, 0]
        new_red, new_blue = self.env.rate([[self.trueskills[number] for number in red_alliance],
                                      [self.trueskills[number] for number in blue_alliance]], ranks)
        # Store the new values
        new_ratings = new_red + new_blue
        for rating, team_number in zip(new_ratings, red_alliance + blue_alliance):
            self.trueskills[team_number] = rating


    def predict(self, red_alliance, blue_alliance):
        proba = self.env.quality([[self.trueskills[team] for team in red_alliance],
                            [self.trueskills[team] for team in blue_alliance]])
        return round(proba*100)

    def skill(self, team):
        return self.env.expose(self.trueskills[team])

    def get_previous_matches(self):
        started_events = []
        all_matches = []
        events = requests.get("https://www.thebluealliance.com/api/v2/events/2017")
        events = events.json()

        for event in events:
            if event['event_type'] > 5:
                continue
            if event['start_date'] < str(datetime.date(datetime.today())):
                started_events.append(event["key"])

            teams = requests.get("https://www.thebluealliance.com/api/v2/event/"+event['key']+"/teams", headers={"X-TBA-App-Id":"frc-4774:TrueSkill:1.0"})
            teams = teams.json()
            self.events[event['key']] = teams

        for event in started_events:
            matches = requests.get("https://www.thebluealliance.com/api/v2/event/"+event+"/matches", headers={"X-TBA-App-Id":"frc-4774:TrueSkill:1.0"})

            matches = matches.json()
            all_matches += matches
        all_matches.sort(key=lambda m: m['time'])

        for match in all_matches:
            score = match['score_breakdown']
            if score is None:
                continue

            red_stats = score['red']
            blue_stats = score['blue']

            alliances = match['alliances']
            red = alliances['red']
            blue = alliances['blue']

            if red_stats["rotor3Engaged"]:
                red['score'] += 100
            if red_stats["kPaRankingPointAchieved"]:
                red['score'] += 20

            if blue_stats["rotor3Engaged"]:
                blue['score'] += 100
            if blue_stats["kPaRankingPointAchieved"]:
                blue['score'] += 20

            self.update(red['teams'], red['score'], blue['teams'], blue['score'])
Esempio n. 6
0
class LeaderboardTrueskill(Leaderboard):
    def __init__(self, leaderboard_type, file_path):
        super().__init__(leaderboard_type, file_path)
        self._trueskill = TrueSkill(mu=TRUESKILL_START_MU,
                                    sigma=TRUESKILL_START_SIGMA)
        self._ratings = {'current': {}, 'history': []}

    def update_from_placings(self, placings):
        placings_ids = [agent_id for agent_id, _ in placings]
        current_ratings = [
            self._trueskill.Rating(*self._ratings['current'].get(agent, ()))
            for agent in placings_ids
        ]
        new_rating_groups = self._trueskill.rate([(cr, )
                                                  for cr in current_ratings])
        hist_append = {}
        for agent, new_rating_group in zip(placings_ids, new_rating_groups):
            new_rating = (new_rating_group[0].mu, new_rating_group[0].sigma)
            self._ratings['current'][agent] = new_rating
            hist_append[agent] = new_rating
        self._ratings['history'].append(hist_append)
        self.changed = True

    def get_all_rankings(self):
        sorted_ratings = sorted(self._ratings['current'].items(),
                                key=lambda x: x[1][0],
                                reverse=True)
        return sorted_ratings

    def get_rating_of_agent(self, agent_id):
        # TODO ranking != mu, but keep atm
        return self._ratings['current'].get(
            agent_id, (TRUESKILL_START_MU, TRUESKILL_START_SIGMA))

    def reset_rankings(self):
        self._ratings = {'current': {}, 'history': []}
        self.changed = True

    def plot_leaderboard(self, agent_manager):

        plt.figure(0)
        plt.subplot()

        mu = np.ndarray((len(self._ratings['history']), ))
        sigma_2 = np.ndarray((len(self._ratings['history']), ))
        x = np.arange(len(self._ratings['history']))

        agent_types = {
            agent_type: idx
            for idx, agent_type in enumerate(AGENT_TYPES.keys())
        }
        #palette = sns.color_palette("husl", n_colors=len(agent_types))
        palette = [(60, 180, 75), (255, 225, 25), (0, 130, 200),
                   (245, 130, 48), (220, 190, 255), (128, 0, 0), (0, 0, 128),
                   (128, 128, 128), (0, 0, 0), (64, 64, 64)]
        palette = [(r / 255, g / 255, b / 255) for r, g, b in palette]
        for agent_id in self._ratings['current'].keys():
            agent_info = agent_manager.get_info(agent_id)
            color = palette[agent_types[agent_info.AGENT_TYPE]]

            for idx, game in enumerate(self._ratings['history']):
                if agent_id in game:
                    mu[idx] = game[agent_id][0]
                    sigma_2[idx] = game[agent_id][1] * 2
                else:
                    mu[idx] = np.NaN
                    sigma_2[idx] = np.NaN
            mask = np.isfinite(mu)
            sns.lineplot(x=x[mask],
                         y=mu[mask],
                         style=agent_info.TRAINABLE,
                         dashes={
                             False: [],
                             True: [2, 2]
                         },
                         color=color)
            # plt.errorbar(x=x[mask],
            #              y=mu[mask],
            #              yerr=sigma_2[mask],
            #              linestyle='-')
            # plt.ylim(87, 125)

        fake_lines = [plt.Line2D([0], [0], color=color) for color in palette]
        #plt.title('[{}]: {}'.format(self.LEADERBOARD_TYPE, self.FILE_PATH))
        plt.xlabel('rounds played')
        plt.ylabel('trueskill rating')
        plt.legend(fake_lines, agent_types)
        plt.show()

    def print_leaderboard(self, agent_manager):
        ratings = [(v[0], v[1], k, agent_manager.get_info(k))
                   for k, v in self._ratings['current'].items()]
        output = "\n".join(
            '{:>4}: {} {}.{} {:<20} {:>7.2f} +/- {:>5.2f}'.format(
                idx + 1, agent_info.AGENT_TYPE, agent_info.ORIGIN_DIVI,
                agent_id, agent_info.AGENT_NAME, mu, 2 * sigma)
            for idx, (mu, sigma, agent_id,
                      agent_info) in enumerate(sorted(ratings, reverse=True)))
        print(output)