James McCool commited on
Commit
119b2bf
·
1 Parent(s): eb3c53f

Replace distribute_preset with hedging_preset to manage player exposure in lineup generation. Update app.py to reflect the new preset option and remove the obsolete distribute_preset function. This change enhances the flexibility of lineup strategies by allowing users to hedge against high-exposure players while maintaining performance metrics.

Browse files
app.py CHANGED
@@ -22,7 +22,7 @@ from global_func.trim_portfolio import trim_portfolio
22
  from global_func.get_portfolio_names import get_portfolio_names
23
  from global_func.small_field_preset import small_field_preset
24
  from global_func.large_field_preset import large_field_preset
25
- from global_func.distribute_preset import distribute_preset
26
 
27
  freq_format = {'Finish_percentile': '{:.2%}', 'Lineup Edge': '{:.2%}', 'Win%': '{:.2%}'}
28
  stacking_sports = ['MLB', 'NHL', 'NFL']
@@ -1111,7 +1111,7 @@ with tab2:
1111
  with st.expander('Presets'):
1112
  st.info("Still heavily in testing here, I'll announce when they are ready for use.")
1113
  with st.form(key='Small Field Preset'):
1114
- preset_choice = st.selectbox("Preset", options=['Small Field (Heavy Own)', 'Large Field (Finish Percentile / Edge)', 'Distributed (Spread Out Risk)'], index=0)
1115
  lineup_target = st.number_input("Lineups to produce", value=150, min_value=1, step=1)
1116
  submitted = st.form_submit_button("Submit")
1117
  if submitted:
@@ -1119,8 +1119,8 @@ with tab2:
1119
  parsed_frame = small_field_preset(st.session_state['working_frame'], lineup_target, excluded_cols)
1120
  elif preset_choice == 'Large Field (Finish Percentile / Edge)':
1121
  parsed_frame = large_field_preset(st.session_state['working_frame'], lineup_target, excluded_cols)
1122
- elif preset_choice == 'Distributed (Spread Out Risk)':
1123
- parsed_frame = distribute_preset(st.session_state['working_frame'], lineup_target, excluded_cols)
1124
  st.session_state['working_frame'] = parsed_frame.reset_index(drop=True)
1125
  st.session_state['export_merge'] = st.session_state['working_frame'].copy()
1126
 
 
22
  from global_func.get_portfolio_names import get_portfolio_names
23
  from global_func.small_field_preset import small_field_preset
24
  from global_func.large_field_preset import large_field_preset
25
+ from global_func.hedging_preset import hedging_preset
26
 
27
  freq_format = {'Finish_percentile': '{:.2%}', 'Lineup Edge': '{:.2%}', 'Win%': '{:.2%}'}
28
  stacking_sports = ['MLB', 'NHL', 'NFL']
 
1111
  with st.expander('Presets'):
1112
  st.info("Still heavily in testing here, I'll announce when they are ready for use.")
1113
  with st.form(key='Small Field Preset'):
1114
+ preset_choice = st.selectbox("Preset", options=['Small Field (Heavy Own)', 'Large Field (Finish Percentile / Edge)', 'Hedge Chalk (Manage Leverage)'], index=0)
1115
  lineup_target = st.number_input("Lineups to produce", value=150, min_value=1, step=1)
1116
  submitted = st.form_submit_button("Submit")
1117
  if submitted:
 
1119
  parsed_frame = small_field_preset(st.session_state['working_frame'], lineup_target, excluded_cols)
1120
  elif preset_choice == 'Large Field (Finish Percentile / Edge)':
1121
  parsed_frame = large_field_preset(st.session_state['working_frame'], lineup_target, excluded_cols)
1122
+ elif preset_choice == 'Hedge Chalk (Manage Leverage)':
1123
+ parsed_frame = hedging_preset(st.session_state['working_frame'], lineup_target, st.session_state['projections_df'])
1124
  st.session_state['working_frame'] = parsed_frame.reset_index(drop=True)
1125
  st.session_state['export_merge'] = st.session_state['working_frame'].copy()
1126
 
global_func/distribute_preset.py DELETED
@@ -1,80 +0,0 @@
1
- import pandas as pd
2
- import math
3
-
4
- def distribute_preset(portfolio: pd.DataFrame, lineup_target: int, exclude_cols: list):
5
-
6
- excluded_cols = ['salary', 'median', 'Own', 'Finish_percentile', 'Dupes', 'Stack', 'Size', 'Win%', 'Lineup Edge', 'Weighted Own', 'Geomean', 'Similarity Score']
7
- player_columns = [col for col in portfolio.columns if col not in excluded_cols]
8
- for slack_var in range(1, 20):
9
- init_portfolio = pd.DataFrame(columns=portfolio.columns)
10
-
11
- for team in portfolio['Stack'].unique():
12
- rows_to_drop = []
13
- working_portfolio = portfolio.copy()
14
- working_portfolio = working_portfolio[working_portfolio['Stack'] == team].sort_values(by='median', ascending = False)
15
- working_portfolio = working_portfolio.reset_index(drop=True)
16
- curr_own_type_max = working_portfolio.loc[0, 'Similarity Score'] + (slack_var / 20 * working_portfolio.loc[0, 'Similarity Score'])
17
-
18
- for i in range(1, len(working_portfolio)):
19
- if working_portfolio.loc[i, 'Similarity Score'] > curr_own_type_max:
20
- rows_to_drop.append(i)
21
- else:
22
- curr_own_type_max = working_portfolio.loc[i, 'Similarity Score'] + (slack_var / 20 * working_portfolio.loc[i, 'Similarity Score'])
23
-
24
- working_portfolio = working_portfolio.drop(rows_to_drop).reset_index(drop=True)
25
- init_portfolio = pd.concat([init_portfolio, working_portfolio])
26
-
27
- if len(init_portfolio) >= lineup_target:
28
- init_portfolio.sort_values(by='median', ascending=True).head(lineup_target)
29
-
30
- player_list = set()
31
- player_stats = []
32
- for cols in init_portfolio.columns:
33
- if cols not in excluded_cols:
34
- player_list.update(init_portfolio[cols].unique())
35
-
36
- for player in player_list:
37
- # Select only the columns that are NOT in excluded_cols
38
- player_cols = [col for col in init_portfolio.columns if col not in excluded_cols]
39
- player_mask = init_portfolio[player_cols].apply(
40
- lambda row: player in list(row), axis=1
41
- )
42
-
43
- if player_mask.any():
44
- player_stats.append({
45
- 'Player': player,
46
- 'Lineup Count': player_mask.sum(),
47
- 'Exposure': player_mask.sum() / len(init_portfolio)
48
- })
49
-
50
- player_summary = pd.DataFrame(player_stats)
51
- print(player_summary.sort_values('Lineup Count', ascending=False).head(10))
52
- player_remove_list = player_summary.sort_values('Lineup Count', ascending=False).head(5)['Player'].tolist()
53
-
54
- for slack_var in range(1, 20):
55
- concat_portfolio = pd.DataFrame(columns=portfolio.columns)
56
-
57
- for player_out in player_remove_list:
58
- rows_to_drop = []
59
- working_portfolio = portfolio.copy()
60
- remove_mask = working_portfolio[player_columns].apply(
61
- lambda row: player_out not in list(row), axis=1
62
- )
63
- working_portfolio = working_portfolio[remove_mask]
64
- print(working_portfolio.head(10))
65
- working_portfolio = working_portfolio.sort_values(by='median', ascending=False).reset_index(drop=True)
66
- curr_own_type_max = working_portfolio.loc[0, 'Similarity Score'] + (slack_var / 20 * working_portfolio.loc[0, 'Similarity Score'])
67
-
68
- for i in range(1, len(working_portfolio)):
69
- if working_portfolio.loc[i, 'Similarity Score'] > curr_own_type_max:
70
- rows_to_drop.append(i)
71
- else:
72
- curr_own_type_max = working_portfolio.loc[i, 'Similarity Score'] + (slack_var / 20 * working_portfolio.loc[i, 'Similarity Score'])
73
-
74
- working_portfolio = working_portfolio.drop(rows_to_drop).reset_index(drop=True)
75
- concat_portfolio = pd.concat([concat_portfolio, working_portfolio.head(math.ceil(lineup_target / 5))])
76
-
77
- if len(concat_portfolio) >= lineup_target:
78
- return concat_portfolio.sort_values(by='median', ascending=False).head(lineup_target)
79
-
80
- return concat_portfolio.sort_values(by='median', ascending=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
global_func/hedging_preset.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import math
3
+ from small_field_preset import small_field_preset
4
+ from large_field_preset import large_field_preset
5
+
6
+ def hedging_preset(portfolio: pd.DataFrame, lineup_target: int, projections_file: pd.DataFrame):
7
+
8
+ excluded_cols = ['salary', 'median', 'Own', 'Finish_percentile', 'Dupes', 'Stack', 'Size', 'Win%', 'Lineup Edge', 'Weighted Own', 'Geomean', 'Similarity Score']
9
+
10
+ check_own_df = projections_file.copy()
11
+ check_own_df = check_own_df.sort_values(by='Own', ascending=False)
12
+ top_owned = check_own_df['player_names'].head(3).tolist()
13
+
14
+ concat_portfolio = pd.DataFrame(columns=portfolio.columns)
15
+
16
+ for players in top_owned:
17
+ working_df = portfolio.copy()
18
+
19
+ # Create mask for lineups that contain any of the removed players
20
+ player_columns = [col for col in working_df.columns if col not in excluded_cols]
21
+
22
+ remove_mask = working_df[player_columns].apply(
23
+ lambda row: not any(player in list(row) for player in players), axis=1
24
+ )
25
+ lock_mask = working_df[player_columns].apply(
26
+ lambda row: all(player in list(row) for player in players), axis=1
27
+ )
28
+
29
+ removed_df = working_df[remove_mask]
30
+ locked_df = working_df[lock_mask]
31
+
32
+ removed_lineups = small_field_preset(removed_df, math.ceil(lineup_target / 2), excluded_cols)
33
+ locked_lineups = large_field_preset(locked_df, math.ceil(lineup_target / 2), excluded_cols)
34
+
35
+ concat_portfolio = pd.concat([concat_portfolio, removed_lineups, locked_lineups])
36
+
37
+ return concat_portfolio.sort_values(by='median', ascending=False).head(lineup_target)
global_func/large_field_preset.py CHANGED
@@ -1,6 +1,9 @@
1
  import pandas as pd
2
 
3
  def large_field_preset(portfolio: pd.DataFrame, lineup_target: int, exclude_cols: list):
 
 
 
4
 
5
  for slack_var in range(1, 20):
6
  concat_portfolio = pd.DataFrame(columns=portfolio.columns)
 
1
  import pandas as pd
2
 
3
  def large_field_preset(portfolio: pd.DataFrame, lineup_target: int, exclude_cols: list):
4
+
5
+ excluded_cols = ['salary', 'median', 'Own', 'Finish_percentile', 'Dupes', 'Stack', 'Size', 'Win%', 'Lineup Edge', 'Weighted Own', 'Geomean', 'Similarity Score']
6
+ player_columns = [col for col in portfolio.columns if col not in excluded_cols]
7
 
8
  for slack_var in range(1, 20):
9
  concat_portfolio = pd.DataFrame(columns=portfolio.columns)
global_func/small_field_preset.py CHANGED
@@ -2,6 +2,9 @@ import pandas as pd
2
 
3
  def small_field_preset(portfolio: pd.DataFrame, lineup_target: int, exclude_cols: list):
4
 
 
 
 
5
  for slack_var in range(1, 20):
6
  concat_portfolio = pd.DataFrame(columns=portfolio.columns)
7
 
 
2
 
3
  def small_field_preset(portfolio: pd.DataFrame, lineup_target: int, exclude_cols: list):
4
 
5
+ excluded_cols = ['salary', 'median', 'Own', 'Finish_percentile', 'Dupes', 'Stack', 'Size', 'Win%', 'Lineup Edge', 'Weighted Own', 'Geomean', 'Similarity Score']
6
+ player_columns = [col for col in portfolio.columns if col not in excluded_cols]
7
+
8
  for slack_var in range(1, 20):
9
  concat_portfolio = pd.DataFrame(columns=portfolio.columns)
10