James McCool
Enhance Late Swap optimization with additional player filtering and UI improvements
2d1ce07
import streamlit as st | |
import numpy as np | |
import pandas as pd | |
import time | |
from fuzzywuzzy import process | |
def optimize_lineup(row): | |
current_lineup = [] | |
total_salary = 0 | |
salary_cap = 50000 | |
used_players = set() | |
# Convert row to dictionary with roster positions | |
roster = {} | |
for col, player in zip(row.index, row): | |
if col not in ['salary', 'median', 'Own', 'Finish_percentile', 'Dupes', 'Lineup Edge']: | |
roster[col] = { | |
'name': player, | |
'position': map_dict['pos_map'].get(player, '').split('/'), | |
'team': map_dict['team_map'].get(player, ''), | |
'salary': map_dict['salary_map'].get(player, 0), | |
'median': map_dict['proj_map'].get(player, 0), | |
'ownership': map_dict['own_map'].get(player, 0) | |
} | |
total_salary += roster[col]['salary'] | |
used_players.add(player) | |
# Optimize each roster position in random order | |
roster_positions = list(roster.items()) | |
random.shuffle(roster_positions) | |
for roster_pos, current in roster_positions: | |
# Skip optimization for players from removed teams | |
if current['team'] in remove_teams_var: | |
continue | |
valid_positions = position_rules[roster_pos] | |
better_options = [] | |
# Find valid replacements for this roster position | |
for pos in valid_positions: | |
if pos in position_groups: | |
pos_options = [ | |
p for p in position_groups[pos] | |
if p['median'] > current['median'] | |
and (total_salary - current['salary'] + p['salary']) <= salary_cap | |
and p['player_names'] not in used_players | |
and any(valid_pos in p['positions'] for valid_pos in valid_positions) | |
and map_dict['team_map'].get(p['player_names']) not in remove_teams_var # Check team restriction | |
] | |
better_options.extend(pos_options) | |
if better_options: | |
# Remove duplicates | |
better_options = {opt['player_names']: opt for opt in better_options}.values() | |
# Sort by median projection and take the best one | |
best_replacement = max(better_options, key=lambda x: x['median']) | |
# Update the lineup and tracking variables | |
used_players.remove(current['name']) | |
used_players.add(best_replacement['player_names']) | |
total_salary = total_salary - current['salary'] + best_replacement['salary'] | |
roster[roster_pos] = { | |
'name': best_replacement['player_names'], | |
'position': map_dict['pos_map'][best_replacement['player_names']].split('/'), | |
'team': map_dict['team_map'][best_replacement['player_names']], | |
'salary': best_replacement['salary'], | |
'median': best_replacement['median'], | |
'ownership': best_replacement['ownership'] | |
} | |
# Return optimized lineup maintaining original column order | |
return [roster[pos]['name'] for pos in row.index if pos in roster] |