Spaces:
Sleeping
Sleeping
James McCool
commited on
Commit
·
25fcef5
1
Parent(s):
f08f4f1
Enhance portfolio filtering and trimming options in app.py: introduce expandable sections for filter and trimming options, update portfolio trimming logic to support geomean calculations, and improve export functionality with stack count adjustments.
Browse files- app.py +123 -122
- global_func/predict_dupes.py +2 -1
- global_func/trim_portfolio.py +4 -1
app.py
CHANGED
|
@@ -780,132 +780,133 @@ with tab3:
|
|
| 780 |
)
|
| 781 |
|
| 782 |
col1, col2 = st.columns([1, 10])
|
| 783 |
-
if st.button('Trim Portfolio'):
|
| 784 |
-
st.session_state['portfolio'] = trim_portfolio(st.session_state['portfolio'], 'median', 'Own')
|
| 785 |
with col1:
|
| 786 |
-
with st.
|
| 787 |
-
|
| 788 |
-
|
| 789 |
-
|
| 790 |
-
|
| 791 |
-
|
| 792 |
-
|
| 793 |
-
|
| 794 |
-
|
| 795 |
-
|
| 796 |
-
|
| 797 |
-
|
| 798 |
-
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
|
| 802 |
-
|
| 803 |
-
|
| 804 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 805 |
|
| 806 |
with col2:
|
| 807 |
-
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
if
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
|
| 818 |
-
|
| 819 |
-
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
-
|
|
|
|
|
|
|
|
|
|
| 828 |
|
| 829 |
-
|
| 830 |
-
|
| 831 |
-
|
| 832 |
-
|
| 833 |
-
|
| 834 |
-
|
| 835 |
-
|
| 836 |
-
|
| 837 |
-
|
| 838 |
-
|
| 839 |
-
|
| 840 |
-
|
| 841 |
-
|
| 842 |
-
|
| 843 |
-
|
| 844 |
-
|
| 845 |
-
|
| 846 |
-
|
| 847 |
-
st.
|
| 848 |
-
|
| 849 |
-
|
| 850 |
-
|
| 851 |
-
|
| 852 |
-
|
| 853 |
-
|
| 854 |
-
|
| 855 |
-
|
| 856 |
-
|
| 857 |
-
|
| 858 |
-
|
| 859 |
-
|
| 860 |
-
|
| 861 |
-
|
| 862 |
-
|
| 863 |
-
|
| 864 |
-
|
| 865 |
-
|
| 866 |
-
|
| 867 |
-
|
| 868 |
-
|
| 869 |
-
|
| 870 |
-
|
| 871 |
-
|
| 872 |
-
|
| 873 |
-
|
| 874 |
-
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
| 878 |
-
|
| 879 |
-
|
| 880 |
-
|
| 881 |
-
|
| 882 |
-
|
| 883 |
-
|
| 884 |
-
|
| 885 |
-
|
| 886 |
-
|
| 887 |
-
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
|
| 892 |
-
|
| 893 |
-
|
| 894 |
-
|
| 895 |
-
|
| 896 |
-
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
|
| 904 |
-
|
| 905 |
-
submitted = st.form_submit_button("Submit")
|
| 906 |
-
if submitted:
|
| 907 |
-
st.write('Export portfolio updated!')
|
| 908 |
-
st.session_state['math_done'] = True
|
| 909 |
|
| 910 |
st.download_button(label="Download Portfolio", data=export_file.to_csv(index=False), file_name="portfolio.csv", mime="text/csv")
|
| 911 |
|
|
|
|
| 780 |
)
|
| 781 |
|
| 782 |
col1, col2 = st.columns([1, 10])
|
|
|
|
|
|
|
| 783 |
with col1:
|
| 784 |
+
with st.expander('Filter Options'):
|
| 785 |
+
with st.form(key='filter_form'):
|
| 786 |
+
max_dupes = st.number_input("Max acceptable dupes?", value=1000, min_value=1, step=1)
|
| 787 |
+
min_salary = st.number_input("Min acceptable salary?", value=1000, min_value=1000, step=100)
|
| 788 |
+
max_salary = st.number_input("Max acceptable salary?", value=60000, min_value=1000, step=100)
|
| 789 |
+
max_finish_percentile = st.number_input("Max acceptable finish percentile?", value=.50, min_value=0.005, step=.001)
|
| 790 |
+
min_lineup_edge = st.number_input("Min acceptable Lineup Edge?", value=-.5, min_value=-1.00, step=.001)
|
| 791 |
+
player_names = set()
|
| 792 |
+
for col in st.session_state['portfolio'].columns:
|
| 793 |
+
if col not in excluded_cols:
|
| 794 |
+
player_names.update(st.session_state['portfolio'][col].unique())
|
| 795 |
+
player_lock = st.multiselect("Lock players?", options=sorted(list(player_names)), default=[])
|
| 796 |
+
player_remove = st.multiselect("Remove players?", options=sorted(list(player_names)), default=[])
|
| 797 |
+
if stack_dict is not None:
|
| 798 |
+
stack_toggle = st.selectbox("Include specific stacks?", options=['All Stacks', 'Specific Stacks'], index=0)
|
| 799 |
+
stack_selections = st.multiselect("If Specific Stacks, Which to include?", options=sorted(list(set(stack_dict.values()))), default=[])
|
| 800 |
+
stack_remove = st.multiselect("If Specific Stacks, Which to remove?", options=sorted(list(set(stack_dict.values()))), default=[])
|
| 801 |
+
|
| 802 |
+
submitted = st.form_submit_button("Submit")
|
| 803 |
+
with st.expander('Trimming Options'):
|
| 804 |
+
performance_type = st.selectbox("Select sort type", ['median', 'Finish_percentile'])
|
| 805 |
+
own_type = st.selectbox("Select trimming variable type", ['Own', 'Geomean'])
|
| 806 |
+
if st.button('Trim Portfolio'):
|
| 807 |
+
st.session_state['portfolio'] = trim_portfolio(st.session_state['portfolio'], performance_type, own_type)
|
| 808 |
|
| 809 |
with col2:
|
| 810 |
+
st.session_state['portfolio'] = predict_dupes(st.session_state['portfolio'], map_dict, site_var, type_var, Contest_Size, strength_var)
|
| 811 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Dupes'] <= max_dupes]
|
| 812 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['salary'] >= min_salary]
|
| 813 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['salary'] <= max_salary]
|
| 814 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Finish_percentile'] <= max_finish_percentile]
|
| 815 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Lineup Edge'] >= min_lineup_edge]
|
| 816 |
+
if stack_dict is not None:
|
| 817 |
+
if stack_toggle == 'All Stacks':
|
| 818 |
+
st.session_state['portfolio'] = st.session_state['portfolio']
|
| 819 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][~st.session_state['portfolio']['Stack'].isin(stack_remove)]
|
| 820 |
+
else:
|
| 821 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Stack'].isin(stack_selections)]
|
| 822 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][~st.session_state['portfolio']['Stack'].isin(stack_remove)]
|
| 823 |
+
if player_remove:
|
| 824 |
+
# Create mask for lineups that contain any of the removed players
|
| 825 |
+
player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
|
| 826 |
+
remove_mask = st.session_state['portfolio'][player_columns].apply(
|
| 827 |
+
lambda row: not any(player in list(row) for player in player_remove), axis=1
|
| 828 |
+
)
|
| 829 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][remove_mask]
|
| 830 |
+
|
| 831 |
+
if player_lock:
|
| 832 |
+
# Create mask for lineups that contain all locked players
|
| 833 |
+
player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
|
| 834 |
|
| 835 |
+
lock_mask = st.session_state['portfolio'][player_columns].apply(
|
| 836 |
+
lambda row: all(player in list(row) for player in player_lock), axis=1
|
| 837 |
+
)
|
| 838 |
+
st.session_state['portfolio'] = st.session_state['portfolio'][lock_mask]
|
| 839 |
+
export_file = st.session_state['portfolio'].copy()
|
| 840 |
+
st.session_state['portfolio'] = st.session_state['portfolio'].sort_values(by='median', ascending=False)
|
| 841 |
+
if csv_file is not None:
|
| 842 |
+
player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
|
| 843 |
+
for col in player_columns:
|
| 844 |
+
export_file[col] = export_file[col].map(st.session_state['export_dict'])
|
| 845 |
+
with st.expander("Download options"):
|
| 846 |
+
if stack_dict is not None:
|
| 847 |
+
with st.form(key='stack_form'):
|
| 848 |
+
st.subheader("Stack Count Adjustments")
|
| 849 |
+
st.info("This allows you to fine tune the stacks that you wish to export. If you want to make sure you don't export any of a specific stack you can 0 it out.")
|
| 850 |
+
# Create a container for stack value inputs
|
| 851 |
+
sort_container = st.container()
|
| 852 |
+
with sort_container:
|
| 853 |
+
sort_var = st.selectbox("Sort export portfolio by:", options=['median', 'Lineup Edge', 'Own'])
|
| 854 |
+
|
| 855 |
+
# Get unique stack values
|
| 856 |
+
unique_stacks = sorted(list(set(stack_dict.values())))
|
| 857 |
+
|
| 858 |
+
# Create a dictionary to store stack multipliers
|
| 859 |
+
if 'stack_multipliers' not in st.session_state:
|
| 860 |
+
st.session_state.stack_multipliers = {stack: 0.0 for stack in unique_stacks}
|
| 861 |
+
|
| 862 |
+
# Create columns for the stack inputs
|
| 863 |
+
num_cols = 6 # Number of columns to display
|
| 864 |
+
for i in range(0, len(unique_stacks), num_cols):
|
| 865 |
+
cols = st.columns(num_cols)
|
| 866 |
+
for j, stack in enumerate(unique_stacks[i:i+num_cols]):
|
| 867 |
+
with cols[j]:
|
| 868 |
+
# Create a unique key for each number input
|
| 869 |
+
key = f"stack_count_{stack}"
|
| 870 |
+
# Get the current count of this stack in the portfolio
|
| 871 |
+
current_stack_count = len(st.session_state['portfolio'][st.session_state['portfolio']['Stack'] == stack])
|
| 872 |
+
# Create number input with current value and max value based on actual count
|
| 873 |
+
st.session_state.stack_multipliers[stack] = st.number_input(
|
| 874 |
+
f"{stack} count",
|
| 875 |
+
min_value=0.0,
|
| 876 |
+
max_value=float(current_stack_count),
|
| 877 |
+
value=0.0,
|
| 878 |
+
step=1.0,
|
| 879 |
+
key=key
|
| 880 |
+
)
|
| 881 |
+
|
| 882 |
+
# Create a copy of the portfolio
|
| 883 |
+
portfolio_copy = st.session_state['portfolio'].copy()
|
| 884 |
+
|
| 885 |
+
# Create a list to store selected rows
|
| 886 |
+
selected_rows = []
|
| 887 |
+
|
| 888 |
+
# For each stack, select the top N rows based on the count value
|
| 889 |
+
for stack in unique_stacks:
|
| 890 |
+
if stack in st.session_state.stack_multipliers:
|
| 891 |
+
count = int(st.session_state.stack_multipliers[stack])
|
| 892 |
+
# Get rows for this stack
|
| 893 |
+
stack_rows = portfolio_copy[portfolio_copy['Stack'] == stack]
|
| 894 |
+
# Sort by median and take top N rows
|
| 895 |
+
top_rows = stack_rows.nlargest(count, sort_var)
|
| 896 |
+
selected_rows.append(top_rows)
|
| 897 |
+
|
| 898 |
+
# Combine all selected rows
|
| 899 |
+
portfolio_copy = pd.concat(selected_rows)
|
| 900 |
+
|
| 901 |
+
# Update export_file with filtered data
|
| 902 |
+
export_file = portfolio_copy.copy()
|
| 903 |
+
for col in export_file.columns:
|
| 904 |
+
if col not in excluded_cols:
|
| 905 |
+
export_file[col] = export_file[col].map(st.session_state['export_dict'])
|
| 906 |
+
|
| 907 |
+
submitted = st.form_submit_button("Submit")
|
| 908 |
+
if submitted:
|
| 909 |
+
st.write('Export portfolio updated!')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 910 |
|
| 911 |
st.download_button(label="Download Portfolio", data=export_file.to_csv(index=False), file_name="portfolio.csv", mime="text/csv")
|
| 912 |
|
global_func/predict_dupes.py
CHANGED
|
@@ -3,6 +3,7 @@ import numpy as np
|
|
| 3 |
import pandas as pd
|
| 4 |
import time
|
| 5 |
from fuzzywuzzy import process
|
|
|
|
| 6 |
|
| 7 |
def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, strength_var):
|
| 8 |
if strength_var == 'Weak':
|
|
@@ -181,7 +182,7 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 181 |
portfolio['Lineup Edge'] = portfolio['Win%'] * ((.5 - portfolio['Finish_percentile']) * (Contest_Size / 2.5))
|
| 182 |
portfolio['Lineup Edge'] = portfolio.apply(lambda row: row['Lineup Edge'] / (row['Dupes'] + 1) if row['Dupes'] > 0 else row['Lineup Edge'], axis=1)
|
| 183 |
portfolio['Lineup Edge'] = portfolio['Lineup Edge'] - portfolio['Lineup Edge'].mean()
|
| 184 |
-
portfolio['
|
| 185 |
portfolio = portfolio.drop(columns=dup_count_columns)
|
| 186 |
portfolio = portfolio.drop(columns=own_columns)
|
| 187 |
portfolio = portfolio.drop(columns=calc_columns)
|
|
|
|
| 3 |
import pandas as pd
|
| 4 |
import time
|
| 5 |
from fuzzywuzzy import process
|
| 6 |
+
from scipy.stats import gmean
|
| 7 |
|
| 8 |
def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, strength_var):
|
| 9 |
if strength_var == 'Weak':
|
|
|
|
| 182 |
portfolio['Lineup Edge'] = portfolio['Win%'] * ((.5 - portfolio['Finish_percentile']) * (Contest_Size / 2.5))
|
| 183 |
portfolio['Lineup Edge'] = portfolio.apply(lambda row: row['Lineup Edge'] / (row['Dupes'] + 1) if row['Dupes'] > 0 else row['Lineup Edge'], axis=1)
|
| 184 |
portfolio['Lineup Edge'] = portfolio['Lineup Edge'] - portfolio['Lineup Edge'].mean()
|
| 185 |
+
portfolio['Geomean'] = portfolio[own_columns].apply(lambda row: gmean(row), axis=1)
|
| 186 |
portfolio = portfolio.drop(columns=dup_count_columns)
|
| 187 |
portfolio = portfolio.drop(columns=own_columns)
|
| 188 |
portfolio = portfolio.drop(columns=calc_columns)
|
global_func/trim_portfolio.py
CHANGED
|
@@ -1,5 +1,8 @@
|
|
| 1 |
def trim_portfolio(portfolio, performance_type, own_type):
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
| 3 |
rows_to_drop = []
|
| 4 |
curr_own_type_max = working_portfolio.loc[0, own_type]
|
| 5 |
|
|
|
|
| 1 |
def trim_portfolio(portfolio, performance_type, own_type):
|
| 2 |
+
if performance_type == 'Finish_percentile':
|
| 3 |
+
working_portfolio = portfolio.sort_values(by=performance_type, ascending = True).reset_index(drop=True)
|
| 4 |
+
else:
|
| 5 |
+
working_portfolio = portfolio.sort_values(by=performance_type, ascending = False).reset_index(drop=True)
|
| 6 |
rows_to_drop = []
|
| 7 |
curr_own_type_max = working_portfolio.loc[0, own_type]
|
| 8 |
|