Spaces:
Sleeping
Sleeping
James McCool
Implement error handling in 'exposure_spread' to ensure comparable player list is generated safely, defaulting to an empty list if an exception occurs, enhancing robustness in player selection logic.
076e322
| import random | |
| import numpy as np | |
| import math | |
| #### Goal is to choose a player and adjust the amount of lineups that have them | |
| #### First thing you need to do is find comparable players in the projections, so any player in the projections that is within $500 of the player and within 10% of the projection | |
| #### Take that list of players and create a list that can be accessed for random insertion into the portfolio | |
| #### Find the player and the amount of rows that contain them and then find an exposure rate which is the percentage of total rows | |
| #### Use the exposure target argument and try to replace the player from as many rows as necessary to be at or just under the target | |
| #### makes sure to check if the player is eligible for the position before replacing them | |
| def check_nba_position_eligibility(column_name, player_positions): | |
| if 'PG' in column_name: | |
| return 'PG' in player_positions | |
| elif 'SG' in column_name: | |
| return 'SG' in player_positions | |
| elif 'SF' in column_name: | |
| return 'SF' in player_positions | |
| elif 'PF' in column_name: | |
| return 'PF' in player_positions | |
| elif 'C' in column_name: | |
| return 'C' in player_positions | |
| elif 'G' in column_name: | |
| return any(pos in ['PG', 'SG'] for pos in player_positions) | |
| elif 'F' in column_name: | |
| return any(pos in ['SF', 'PF'] for pos in player_positions) | |
| elif 'UTIL' in column_name: | |
| return True # UTIL can be any position | |
| return False | |
| def check_lol_position_eligibility(column_name, player_positions): | |
| if 'TOP' in column_name: | |
| return 'TOP' in player_positions | |
| elif 'JNG' in column_name: | |
| return 'JNG' in player_positions | |
| elif 'MID' in column_name: | |
| return 'MID' in player_positions | |
| elif 'ADC' in column_name: | |
| return 'ADC' in player_positions | |
| elif 'SUP' in column_name: | |
| return 'SUP' in player_positions | |
| elif 'Team' in column_name: | |
| return 'Team' in player_positions | |
| elif 'CPT' in column_name: | |
| return any(pos in ['TOP', 'JNG', 'MID', 'ADC', 'SUP'] for pos in player_positions) | |
| return False | |
| def check_mlb_position_eligibility(column_name, player_positions): | |
| if any(pos in column_name for pos in ['P', 'SP', 'RP']): | |
| return any(pos in ['P', 'SP', 'RP'] for pos in player_positions) | |
| elif 'C' in column_name: | |
| return 'C' in player_positions | |
| elif '1B' in column_name: | |
| return '1B' in player_positions | |
| elif '2B' in column_name: | |
| return '2B' in player_positions | |
| elif '3B' in column_name: | |
| return '3B' in player_positions | |
| elif 'SS' in column_name: | |
| return 'SS' in player_positions | |
| elif 'OF' in column_name: | |
| return 'OF' in player_positions | |
| return False | |
| def check_nfl_position_eligibility(column_name, player_positions): | |
| if 'QB' in column_name: | |
| return 'QB' in player_positions | |
| elif 'RB' in column_name: | |
| return 'RB' in player_positions | |
| elif 'WR' in column_name: | |
| return 'WR' in player_positions | |
| elif 'TE' in column_name: | |
| return 'TE' in player_positions | |
| elif 'DST' in column_name: | |
| return 'DST' in player_positions | |
| elif 'FLEX' in column_name: | |
| return any(pos in ['RB', 'WR', 'TE'] for pos in player_positions) | |
| elif 'UTIL' in column_name: | |
| return any(pos in ['RB', 'WR', 'TE'] for pos in player_positions) | |
| return False | |
| def check_golf_position_eligibility(column_name, player_positions): | |
| if 'FLEX' in column_name: | |
| return any(pos in ['G'] for pos in player_positions) | |
| return True | |
| def check_tennis_position_eligibility(column_name, player_positions): | |
| if 'FLEX' in column_name: | |
| return any(pos in ['T'] for pos in player_positions) | |
| return True | |
| def check_mma_position_eligibility(column_name, player_positions): | |
| if 'FLEX' in column_name: | |
| return any(pos in ['F'] for pos in player_positions) | |
| return True | |
| def check_nascar_position_eligibility(column_name, player_positions): | |
| if 'FLEX' in column_name: | |
| return any(pos in ['D'] for pos in player_positions) | |
| return True | |
| def check_ncaaf_position_eligibility(column_name, player_positions): | |
| if 'QB' in column_name: | |
| return 'QB' in player_positions | |
| elif 'RB' in column_name: | |
| return 'RB' in player_positions | |
| elif 'WR' in column_name: | |
| return 'WR' in player_positions | |
| elif 'FLEX' in column_name: | |
| return any(pos in ['RB', 'WR'] for pos in player_positions) | |
| elif 'SFLEX' in column_name: | |
| return any(pos in ['RB', 'WR', 'QB'] for pos in player_positions) | |
| return False | |
| def check_nhl_position_eligibility(column_name, player_positions): | |
| if 'C' in column_name: | |
| return 'C' in player_positions | |
| elif 'W' in column_name: | |
| return 'W' in player_positions | |
| elif 'D' in column_name: | |
| return 'D' in player_positions | |
| elif 'G' in column_name: | |
| return 'G' in player_positions | |
| elif 'FLEX' in column_name: | |
| return any(pos in ['C', 'W', 'D'] for pos in player_positions) | |
| elif 'UTIL' in column_name: | |
| return any(pos in ['C', 'W', 'D'] for pos in player_positions) | |
| return False | |
| def check_position_eligibility(sport, column_name, player_positions): | |
| if sport == 'NBA': | |
| return check_nba_position_eligibility(column_name, player_positions) | |
| elif sport == 'MLB': | |
| return check_mlb_position_eligibility(column_name, player_positions) | |
| elif sport == 'NFL': | |
| return check_nfl_position_eligibility(column_name, player_positions) | |
| elif sport == 'NHL': | |
| return check_nhl_position_eligibility(column_name, player_positions) | |
| elif sport == 'MMA': | |
| return check_mma_position_eligibility(column_name, player_positions) | |
| elif sport == 'GOLF': | |
| return check_golf_position_eligibility(column_name, player_positions) | |
| elif sport == 'TENNIS': | |
| return check_tennis_position_eligibility(column_name, player_positions) | |
| elif sport == 'LOL': | |
| return check_lol_position_eligibility(column_name, player_positions) | |
| else: | |
| # Default fallback - assume exact position match | |
| return column_name in player_positions | |
| def exposure_spread(working_frame, exposure_player, exposure_target, ignore_stacks, remove_teams, specific_replacements, projections_df, sport_var, type_var, salary_max, stacking_sports): | |
| comparable_players = projections_df[projections_df['player_names'] == exposure_player] | |
| comparable_players = comparable_players.reset_index(drop=True) | |
| comp_salary_high = comparable_players['salary'][0] | |
| comp_salary_low = comparable_players['salary'][0] - 500 | |
| comp_projection_high = comparable_players['median'][0] | |
| comp_projection_low = comparable_players['median'][0] - (comparable_players['median'][0] * .75) | |
| # players can be eligible at multiple positions, so we need to find all the positions the player is eligible at | |
| # the position column can have positions designated as 1B/OF which means they are eligible at 1B and OF | |
| comp_player_position = comparable_players['position'].tolist() | |
| comp_team = comparable_players['team'].tolist() | |
| try: | |
| comp_player_position = [pos.split('/') for pos in comp_player_position] | |
| comp_player_position = [item for sublist in comp_player_position for item in sublist] | |
| comp_player_position = list(set(comp_player_position)) | |
| except: | |
| comp_player_position = comparable_players['position'].tolist() | |
| def has_position_overlap(player_positions, target_positions): | |
| player_pos_list = player_positions.split('/') | |
| return any(pos in target_positions for pos in player_pos_list) | |
| # find the exposure rate of the player in the working frame | |
| player_mask = working_frame[working_frame.columns].apply( | |
| lambda row: exposure_player in list(row), axis=1 | |
| ) | |
| replace_mask = working_frame.apply( | |
| lambda row: exposure_player not in list(row), axis=1 | |
| ) | |
| player_exposure = player_mask.sum() / len(working_frame) | |
| replace_exposure = replace_mask.sum() / len(working_frame) | |
| # find the number of lineups that need to be removed to reach the target exposure | |
| if exposure_target == 0: | |
| lineups_to_remove = (player_exposure * len(working_frame)) | |
| else: | |
| lineups_to_remove = ((player_exposure - exposure_target) * len(working_frame)) * 1.01 | |
| lineups_to_add = ((exposure_target - player_exposure) * (len(working_frame) - (player_exposure * len(working_frame)))) * 1.10 | |
| # isolate the rows that contain the player | |
| player_rows = working_frame[player_mask] | |
| replace_rows = working_frame[replace_mask] | |
| if ignore_stacks != []: | |
| player_rows = player_rows[~player_rows['Stack'].isin(ignore_stacks)] | |
| replace_rows = replace_rows[~replace_rows['Stack'].isin(ignore_stacks)] | |
| change_counter = 0 | |
| random_row_indices_insert = list(player_rows.index) | |
| random_row_indices_replace = list(replace_rows.index) | |
| random.shuffle(random_row_indices_insert) | |
| random.shuffle(random_row_indices_replace) | |
| # for each row to the the number of lineups to remove, replace with random choice from comparable player list if they can be inserted | |
| # we will need to use two separate functions here, one for an exposure player who has a lineups to remove above 0 and one for below 0 | |
| # key concept here is if they have a lineups to remove above 0 it means that we are trying to replace them with comparable players | |
| # if the lineups to remove is below zero it means we want to find comparable players and replace them with the exposure player | |
| if lineups_to_remove > 0: | |
| for row in random_row_indices_insert: | |
| if change_counter < math.ceil(lineups_to_remove): | |
| if specific_replacements != []: | |
| comparable_players = projections_df[(projections_df['player_names'].isin(specific_replacements)) & | |
| (projections_df['salary'] <= comp_salary_high + (salary_max - working_frame['salary'][row])) | |
| ] | |
| else: | |
| comparable_players = projections_df[ | |
| (projections_df['salary'] >= comp_salary_low) & | |
| (projections_df['salary'] <= comp_salary_high + (salary_max - working_frame['salary'][row])) & | |
| (projections_df['median'] >= comp_projection_low) & | |
| (projections_df['position'].apply(lambda x: has_position_overlap(x, comp_player_position))) | |
| ] | |
| if exposure_target == 0: | |
| comparable_players = comparable_players[comparable_players['player_names'] != exposure_player] | |
| if remove_teams is not None: | |
| remove_mask = comparable_players.apply( | |
| lambda row: not any(team in list(row) for team in remove_teams), axis=1 | |
| ) | |
| comparable_players = comparable_players[remove_mask] | |
| # Get the current row data to check for existing players | |
| current_row_data = working_frame.iloc[row] | |
| # Filter out players that are already present in this row | |
| existing_players = set(current_row_data.values) | |
| print(existing_players) | |
| print(comparable_players) | |
| print("^^^^ comparable players") | |
| try: | |
| comparable_players = comparable_players[~comparable_players['player_names'].isin(existing_players)] | |
| comparable_player_list = comparable_players['player_names'].tolist() | |
| except: | |
| comparable_player_list = [] | |
| if comparable_player_list: | |
| insert_player = random.choice(comparable_player_list) | |
| # Find which column contains the exposure_player | |
| row_data = working_frame.iloc[row] | |
| for col in working_frame.columns: | |
| if row_data[col] == exposure_player: | |
| # Get the replacement player's positions | |
| replacement_player_positions = projections_df[projections_df['player_names'] == insert_player]['position'].iloc[0].split('/') | |
| # Check if the replacement player is eligible for this column | |
| if type_var == 'Classic': | |
| if check_position_eligibility(sport_var, col, replacement_player_positions): | |
| working_frame.at[row, col] = insert_player | |
| break | |
| else: | |
| working_frame.at[row, col] = insert_player | |
| break | |
| change_counter += 1 | |
| else: | |
| for row in random_row_indices_replace: | |
| if change_counter < math.ceil(lineups_to_add): | |
| if specific_replacements != []: | |
| comparable_players = projections_df[(projections_df['player_names'].isin(specific_replacements)) & | |
| (projections_df['salary'] <= comp_salary_high + (salary_max - working_frame['salary'][row])) | |
| ] | |
| else: | |
| comparable_players = projections_df[ | |
| (projections_df['salary'] >= comp_salary_low) & | |
| (projections_df['salary'] <= comp_salary_high + (salary_max - working_frame['salary'][row])) & | |
| (projections_df['position'].apply(lambda x: has_position_overlap(x, comp_player_position))) | |
| ] | |
| if sport_var in stacking_sports: | |
| if sport_var in stacking_sports: | |
| if working_frame.iloc[row]['Size'] == 5 and comp_team != working_frame.iloc[row]['Stack']: | |
| remove_mask = comparable_players.apply( | |
| lambda player_row: not any(team in list(player_row) for team in [working_frame.iloc[row]['Stack']]), axis=1 | |
| ) | |
| comparable_players = comparable_players[remove_mask] | |
| if remove_teams is not None: | |
| remove_mask = comparable_players.apply( | |
| lambda row: not any(team in list(row) for team in remove_teams), axis=1 | |
| ) | |
| comparable_players = comparable_players[remove_mask] | |
| comparable_players = comparable_players[comparable_players['player_names'] != exposure_player] | |
| # Create a list of comparable players | |
| comparable_player_list = comparable_players['player_names'].tolist() | |
| if comparable_player_list: | |
| # Find which column contains the exposure_player | |
| row_data = working_frame.iloc[row] | |
| for col in working_frame.columns: | |
| if row_data[col] in comparable_player_list: | |
| if working_frame.iloc[row]['salary'] - projections_df[projections_df['player_names'] == row_data[col]]['salary'].iloc[0] + projections_df[projections_df['player_names'] == exposure_player]['salary'].iloc[0] <= salary_max: | |
| # Get the replacement player's positions | |
| replacement_player_positions = projections_df[projections_df['player_names'] == row_data[col]]['position'].iloc[0].split('/') | |
| exposure_player_positions = projections_df[projections_df['player_names'] == exposure_player]['position'].iloc[0].split('/') | |
| # Check if the replacement player is eligible for this column | |
| if type_var == 'Classic': | |
| if check_position_eligibility(sport_var, col, exposure_player_positions): | |
| working_frame.at[row, col] = exposure_player | |
| change_counter += 1 | |
| break | |
| else: | |
| working_frame.at[row, col] = exposure_player | |
| change_counter += 1 | |
| break | |
| else: | |
| continue | |
| return working_frame | |