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 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.form(key='filter_form'):
787
- max_dupes = st.number_input("Max acceptable dupes?", value=1000, min_value=1, step=1)
788
- min_salary = st.number_input("Min acceptable salary?", value=1000, min_value=1000, step=100)
789
- max_salary = st.number_input("Max acceptable salary?", value=60000, min_value=1000, step=100)
790
- max_finish_percentile = st.number_input("Max acceptable finish percentile?", value=.50, min_value=0.005, step=.001)
791
- min_lineup_edge = st.number_input("Min acceptable Lineup Edge?", value=-.5, min_value=-1.00, step=.001)
792
- player_names = set()
793
- for col in st.session_state['portfolio'].columns:
794
- if col not in excluded_cols:
795
- player_names.update(st.session_state['portfolio'][col].unique())
796
- player_lock = st.multiselect("Lock players?", options=sorted(list(player_names)), default=[])
797
- player_remove = st.multiselect("Remove players?", options=sorted(list(player_names)), default=[])
798
- if stack_dict is not None:
799
- stack_toggle = st.selectbox("Include specific stacks?", options=['All Stacks', 'Specific Stacks'], index=0)
800
- stack_selections = st.multiselect("If Specific Stacks, Which to include?", options=sorted(list(set(stack_dict.values()))), default=[])
801
- stack_remove = st.multiselect("If Specific Stacks, Which to remove?", options=sorted(list(set(stack_dict.values()))), default=[])
802
-
803
- st.session_state['math_done'] = False
804
- submitted = st.form_submit_button("Submit")
 
 
 
 
 
805
 
806
  with col2:
807
- if 'math_done' not in st.session_state or st.session_state['math_done'] == False:
808
- st.session_state['portfolio'] = predict_dupes(st.session_state['portfolio'], map_dict, site_var, type_var, Contest_Size, strength_var)
809
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Dupes'] <= max_dupes]
810
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['salary'] >= min_salary]
811
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['salary'] <= max_salary]
812
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Finish_percentile'] <= max_finish_percentile]
813
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Lineup Edge'] >= min_lineup_edge]
814
- if stack_dict is not None:
815
- if stack_toggle == 'All Stacks':
816
- st.session_state['portfolio'] = st.session_state['portfolio']
817
- st.session_state['portfolio'] = st.session_state['portfolio'][~st.session_state['portfolio']['Stack'].isin(stack_remove)]
818
- else:
819
- st.session_state['portfolio'] = st.session_state['portfolio'][st.session_state['portfolio']['Stack'].isin(stack_selections)]
820
- st.session_state['portfolio'] = st.session_state['portfolio'][~st.session_state['portfolio']['Stack'].isin(stack_remove)]
821
- if player_remove:
822
- # Create mask for lineups that contain any of the removed players
823
- player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
824
- remove_mask = st.session_state['portfolio'][player_columns].apply(
825
- lambda row: not any(player in list(row) for player in player_remove), axis=1
826
- )
827
- st.session_state['portfolio'] = st.session_state['portfolio'][remove_mask]
 
 
 
828
 
829
- if player_lock:
830
- # Create mask for lineups that contain all locked players
831
- player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
832
-
833
- lock_mask = st.session_state['portfolio'][player_columns].apply(
834
- lambda row: all(player in list(row) for player in player_lock), axis=1
835
- )
836
- st.session_state['portfolio'] = st.session_state['portfolio'][lock_mask]
837
- export_file = st.session_state['portfolio'].copy()
838
- st.session_state['portfolio'] = st.session_state['portfolio'].sort_values(by='median', ascending=False)
839
- if csv_file is not None:
840
- player_columns = [col for col in st.session_state['portfolio'].columns if col not in excluded_cols]
841
- for col in player_columns:
842
- export_file[col] = export_file[col].map(st.session_state['export_dict'])
843
- with st.expander("Download options"):
844
- if stack_dict is not None:
845
- with st.form(key='stack_form'):
846
- st.subheader("Stack Count Adjustments")
847
- 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.")
848
- # Create a container for stack value inputs
849
- sort_container = st.container()
850
- with sort_container:
851
- sort_var = st.selectbox("Sort export portfolio by:", options=['median', 'Lineup Edge', 'Own'])
852
-
853
- # Get unique stack values
854
- unique_stacks = sorted(list(set(stack_dict.values())))
855
-
856
- # Create a dictionary to store stack multipliers
857
- if 'stack_multipliers' not in st.session_state:
858
- st.session_state.stack_multipliers = {stack: 0.0 for stack in unique_stacks}
859
-
860
- # Create columns for the stack inputs
861
- num_cols = 6 # Number of columns to display
862
- for i in range(0, len(unique_stacks), num_cols):
863
- cols = st.columns(num_cols)
864
- for j, stack in enumerate(unique_stacks[i:i+num_cols]):
865
- with cols[j]:
866
- # Create a unique key for each number input
867
- key = f"stack_count_{stack}"
868
- # Get the current count of this stack in the portfolio
869
- current_stack_count = len(st.session_state['portfolio'][st.session_state['portfolio']['Stack'] == stack])
870
- # Create number input with current value and max value based on actual count
871
- st.session_state.stack_multipliers[stack] = st.number_input(
872
- f"{stack} count",
873
- min_value=0.0,
874
- max_value=float(current_stack_count),
875
- value=0.0,
876
- step=1.0,
877
- key=key
878
- )
879
-
880
- # Create a copy of the portfolio
881
- portfolio_copy = st.session_state['portfolio'].copy()
882
-
883
- # Create a list to store selected rows
884
- selected_rows = []
885
-
886
- # For each stack, select the top N rows based on the count value
887
- for stack in unique_stacks:
888
- if stack in st.session_state.stack_multipliers:
889
- count = int(st.session_state.stack_multipliers[stack])
890
- # Get rows for this stack
891
- stack_rows = portfolio_copy[portfolio_copy['Stack'] == stack]
892
- # Sort by median and take top N rows
893
- top_rows = stack_rows.nlargest(count, sort_var)
894
- selected_rows.append(top_rows)
895
-
896
- # Combine all selected rows
897
- portfolio_copy = pd.concat(selected_rows)
898
-
899
- # Update export_file with filtered data
900
- export_file = portfolio_copy.copy()
901
- for col in export_file.columns:
902
- if col not in excluded_cols:
903
- export_file[col] = export_file[col].map(st.session_state['export_dict'])
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['Product Own'] = portfolio[own_columns].product(axis=1)
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
- working_portfolio = portfolio.sort_values(by=performance_type, ascending = False).reset_index(drop=True)
 
 
 
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