class TeamGenerator: def __init__(self, config): self.salary_cap = 60000 self.selection_multiplier = 100 #Multiply EFPPG by 100 so we can encapsulate remainder in integer array self.config = config self.team_selector = TeamSelector(config['TeamSelector']) def select_top_team(self, player_stats, player_costs, date): print 'Selecting top team for date: ' + str(date) start_time = time.time() players = self._merge_player_stats_and_costs(player_stats, player_costs, date) players = self._filter_players(players) possible_teams = self._all_possible_teams(players) possible_teams = self._filter_on_cap_exceeded_np(possible_teams) top_team = self.team_selector.select_team(possible_teams, player_stats, date) end_time = time.time() print 'Simulation finished with runtime: ' + str(end_time - start_time) expected_points = self._expected_points(top_team) self._print_top_teams(top_team, players) return {'team': top_team, 'expected': expected_points} def _merge_player_stats_and_costs(self, player_stats, player_costs, date): player_stats['Name'] = player_stats['PLAYER'] player_stats = player_stats[player_stats['Date'] < date] player_stats = player_stats.sort_values('Date') player_stats = player_stats.groupby('Player_ID').tail(1) player_costs['Name'] = player_costs['First Name'] + ' ' + player_costs['Last Name'] player_costs['FPPG_Per_Dollar'] = player_costs['FPPG'] / player_costs['Salary'] * 10000 player_stats_costs = pd.merge(player_costs, player_stats, on='Name', how='outer') # Eliminate players with no E_FPPG player_stats_costs = player_stats_costs[np.isfinite(player_stats_costs[self.config['Selection_Field']])] player_stats_costs['EFPPG_Per_Dollar'] = player_stats_costs['E_FPPG'] / player_stats_costs['Salary'] *10000 player_stats_costs = player_stats_costs[np.isfinite(player_stats_costs['EFPPG_Per_Dollar'])] print 'Unfiltered Player Count : {0}'.format(len(player_costs)) return player_stats_costs def _filter_players(self, players): filtered_players = players[players['Injury Indicator'].isnull()] filtered_players = filtered_players.sort_values(self.config['Filter_Field'], ascending=False) filtered_players = filtered_players.iloc[0:self.config['Player_Count']] print 'Filtered Player Count : {0}'.format(len(filtered_players)) return filtered_players def _filter_team_fppg_per_dollar_pctile(self, input_teams, pctile): fppg_totals = np.sum(input_teams[:,:,2], axis=1) / (1.0 * np.sum(input_teams[:,:,3], axis=1)) new_len = int(input_teams.shape[0]*pctile) index = np.argsort(fppg_totals) return input_teams[index[new_len:], :, :] def _filter_on_cap_exceeded_np(self, input_teams): mask = np.sum(input_teams[:, :, 3], axis=1) <= self.salary_cap return input_teams[mask, :, :] def _cartesian(self, x, y): return np.concatenate((np.tile(x, (len(y), 1, 1)), np.repeat(y, len(x), axis=0)), axis=1) def _player_array_from_position(self, players, position): mask = players['Position'] == position player_data = [players['Player_ID'][mask], players['TeamID'][mask], players[self.config['Selection_Field']][mask] * self.selection_multiplier, players['Salary'][mask]] player_data = np.asarray(player_data).astype(np.int32).T.tolist() return player_data def _possible_teams_from_combos(self, first_position_combos, second_position_combos, filter_size_bytes): first_position_combos = self._filter_team_fppg_per_dollar_pctile(first_position_combos, filter_size_bytes) return self._cartesian(first_position_combos, second_position_combos) def _position_combos(self, players, position, num): position_players = self._player_array_from_position(players, position) if num == 1: return np.expand_dims(np.array(position_players), 1).astype(np.int32) else: return np.array(list(combinations(position_players, 2))).astype(np.int32) def _all_possible_teams(self, players): pg_combos = self._position_combos(players, 'PG', 2) sg_combos = self._position_combos(players, 'SG', 2) pf_combos = self._position_combos(players, 'PF', 2) sf_combos = self._position_combos(players, 'SF', 2) c_combos = self._position_combos(players, 'C', 1) possible_teams = self._possible_teams_from_combos(pg_combos, sg_combos, self.config['Team_Size_Bytes_1']) possible_teams = self._possible_teams_from_combos(possible_teams, pf_combos, self.config['Team_Size_Bytes_1']) possible_teams = self._possible_teams_from_combos(possible_teams, sf_combos, self.config['Team_Size_Bytes_2']) return self._possible_teams_from_combos(possible_teams, c_combos, self.config['Team_Size_Bytes_3']) def _expected_points(self, team): return np.sum(team[:,:,2], axis=1) / (1.0 * self.selection_multiplier) def _print_top_teams(self, top_teams, players): fppg_totals = np.sum(top_teams[:,:,2], axis=1) / (1.0 * self.selection_multiplier) salary_totals = np.sum(top_teams[:, :, 3], axis=1) for i, team in enumerate(top_teams): print "Team Expectation: " + str(fppg_totals[i]) print "Salary Utilized: " + str(salary_totals[i]) for player_id in team[:,0]: if player_id > 0: player = players['Name'][players['Player_ID'] == player_id].iloc[0] team = players['Team'][players['Player_ID'] == player_id].iloc[0] position = players['Position'][players['Player_ID'] == player_id].iloc[0] points = players[self.config['Selection_Field']][players['Player_ID']==player_id].iloc[0] salary = players['Salary'][players['Player_ID']==player_id].iloc[0] print player + ' ' + team + ' ' + position + ' ' + str(points) + ' $' + str(salary) print ''