|
import streamlit as st |
|
import numpy as np |
|
import pandas as pd |
|
import time |
|
from fuzzywuzzy import process |
|
|
|
def find_name_mismatches(portfolio_df, projections_df): |
|
""" |
|
Find and handle name mismatches between portfolio and projections dataframes. |
|
Returns the updated projections dataframe with matched names. |
|
""" |
|
|
|
portfolio_players = set() |
|
for col in portfolio_df.columns: |
|
if col not in ['salary', 'median', 'Own', 'Finish_percentile', 'Dupes', 'Stack', 'Win%', 'Lineup Edge']: |
|
portfolio_players.update(portfolio_df[col].unique()) |
|
|
|
|
|
projection_players_list = projections_df['player_names'].tolist() |
|
|
|
|
|
players_missing_from_projections = [player for player in portfolio_players if player not in projection_players_list] |
|
|
|
|
|
players_to_process = [] |
|
for player in players_missing_from_projections: |
|
if not isinstance(player, str): |
|
st.warning(f"Skipping non-string value: {player}") |
|
continue |
|
closest_matches = process.extract(player, projection_players_list, limit=1) |
|
if closest_matches[0][1] == 90: |
|
match_name = closest_matches[0][0] |
|
projections_df.loc[projections_df['player_names'] == match_name, 'player_names'] = player |
|
st.success(f"Automatically matched '{match_name}' with '{player}' (100% match)") |
|
else: |
|
players_to_process.append(player) |
|
|
|
|
|
if players_missing_from_projections: |
|
st.warning("Players in portfolio but missing from projections") |
|
|
|
|
|
if players_to_process: |
|
st.info(f"Players to process ({len(players_to_process)}):\n" + |
|
"\n".join(f"- {player}" for player in players_to_process)) |
|
|
|
|
|
with st.form("player_matching_form"): |
|
|
|
tabs = st.tabs([f"Player {i+1}" for i in range(len(players_to_process))]) |
|
|
|
|
|
selections = {} |
|
|
|
|
|
for idx, (tab, player) in enumerate(zip(tabs, players_to_process)): |
|
with tab: |
|
st.write(f"**Missing Player {idx + 1} of {len(players_to_process)}:** {player}") |
|
|
|
|
|
closest_matches = process.extract(player, projection_players_list, limit=3) |
|
|
|
|
|
options = [f"{match[0]} ({match[1]}%)" for match in closest_matches] |
|
options.append("None of these") |
|
|
|
selected_option = st.radio( |
|
f"Select correct match for {player}:", |
|
options, |
|
key=f"radio_{player}" |
|
) |
|
|
|
selections[player] = selected_option |
|
|
|
|
|
submitted = st.form_submit_button("Submit All Changes") |
|
|
|
if submitted: |
|
|
|
for player, selection in selections.items(): |
|
if selection != "None of these": |
|
selected_name = selection.split(" (")[0] |
|
projections_df.loc[projections_df['player_names'] == selected_name, 'player_names'] = player |
|
st.success(f"Replaced '{selected_name}' with '{player}'") |
|
|
|
|
|
st.session_state['projections_df'] = projections_df |
|
st.success("All player name changes have been applied!") |
|
else: |
|
st.success("All portfolio players found in projections!") |
|
|
|
return projections_df |