File size: 18,452 Bytes
158eaa8 18eaa68 67af571 158eaa8 72c43b1 158eaa8 8e462c9 bdf6978 8e462c9 05f2b9c bdf6978 05f2b9c 8e462c9 d5f1d98 8e462c9 bdf6978 8e462c9 f35aa8d 8e462c9 b9049ff 8e462c9 b9049ff 8e462c9 b9049ff 8e462c9 ad242a2 bdf6978 8e462c9 ad242a2 8e462c9 bdf6978 8e462c9 ad242a2 8e462c9 ad242a2 8e462c9 7f0bbb5 8e462c9 7f0bbb5 8e462c9 05f2b9c 8e462c9 8913211 158eaa8 aef223f 7dd1418 f4f6da8 7dd1418 f4f6da8 abd4533 8b34fed c0ae0e3 abd4533 158eaa8 8913211 efbfb51 158eaa8 0a58221 158eaa8 2371c4f 4399601 3076618 158eaa8 efbfb51 3ff610a 1b89d01 6029c0b efbfb51 f93672b 2344dbb b452fab 38f865e 9034a8a efbfb51 9034a8a 3a20f4f 9e53f8f bcf121e 3a20f4f 38f865e 9034a8a 87bb04e 9034a8a 298e2c8 9034a8a 076e322 5fe15cf 41b98e8 9034a8a 298e2c8 a0d4812 298e2c8 9034a8a 87bb04e 9034a8a efbfb51 2fd6d6d 3a20f4f 5fe15cf f13359a 3a20f4f dc53b72 ad242a2 dc53b72 9034a8a efbfb51 c5323ea 9034a8a dc53b72 41b98e8 9034a8a 8ea397a bce8275 3820d21 583a033 5fe15cf ad242a2 583a033 ce96fd8 583a033 9034a8a ce96fd8 9034a8a ce96fd8 158eaa8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
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, specific_columns, 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]
if type_var == 'Showdown':
comp_salary_low = comparable_players['salary'][0] - 1000
else:
comp_salary_low = comparable_players['salary'][0] - 500
comp_projection_high = comparable_players['median'][0]
if type_var == 'Showdown':
comp_projection_low = comparable_players['median'][0] - (comparable_players['median'][0] * .5)
else:
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
if specific_columns != []:
player_mask = working_frame[specific_columns].apply(
lambda row: exposure_player in list(row), axis=1
)
else:
player_mask = working_frame[working_frame.columns].apply(
lambda row: exposure_player in list(row), axis=1
)
if specific_columns != []:
replace_mask = working_frame[specific_columns].apply(
lambda row: exposure_player not in list(row), axis=1
)
else:
replace_mask = working_frame[working_frame.columns].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)
print(player_exposure)
print(lineups_to_remove)
print(lineups_to_add)
# 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
if specific_columns != []:
current_row_data = working_frame.iloc[row][specific_columns]
else:
current_row_data = working_frame.iloc[row]
# Filter out players that are already present in this row
existing_players = set(current_row_data.values)
try:
comparable_players = comparable_players[~comparable_players['player_names'].isin(existing_players)]
comparable_player_list = comparable_players['player_names'].tolist()
except:
comparable_player_list = []
print(comparable_player_list)
print("^^^^ comparable player list")
if comparable_player_list:
insert_player = random.choice(comparable_player_list)
# Find which column contains the exposure_player
if specific_columns != []:
row_data = working_frame.iloc[row][specific_columns]
working_columns = specific_columns
else:
row_data = working_frame.iloc[row]
working_columns = working_frame.columns
print(working_columns)
for col in working_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))
]
else:
if type_var == 'Showdown':
comparable_players = projections_df[
(projections_df['salary'] >= comp_salary_low) &
(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 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()
print(comp_salary_low)
print(comp_salary_high)
print(comparable_player_list)
print("^^^^ comparable player list")
if comparable_player_list:
# Find which column contains the exposure_player
if specific_columns != []:
row_data = working_frame.iloc[row][specific_columns]
working_columns = specific_columns
else:
row_data = working_frame.iloc[row]
working_columns = working_frame.columns
for col in working_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:
if type_var == 'Classic':
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 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
|