James McCool commited on
Commit
95b08b3
·
1 Parent(s): 8f74703

Add MLB support to ROO build functions and Streamlit display, including percentage formatting and data upload instructions

Browse files
Files changed (2) hide show
  1. app.py +6 -2
  2. function_hold/MLB_functions.py +469 -0
app.py CHANGED
@@ -21,11 +21,13 @@ from function_hold.NBA_functions import DK_NBA_ROO_Build, FD_NBA_ROO_Build
21
  from function_hold.MMA_functions import DK_MMA_ROO_Build, FD_MMA_ROO_Build
22
  from function_hold.NHL_functions import DK_NHL_ROO_Build, FD_NHL_ROO_Build
23
  from function_hold.NFL_functions import DK_NFL_ROO_Build, FD_NFL_ROO_Build
 
24
 
25
  nba_percentages_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '4x%': '{:.2%}', '5x%': '{:.2%}', '6x%': '{:.2%}', 'GPP%': '{:.2%}'}
26
  nhl_percentages_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '4x%': '{:.2%}', '5x%': '{:.2%}', '6x%': '{:.2%}', 'GPP%': '{:.2%}'}
27
  nfl_percentages_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '4x%': '{:.2%}', '5x%': '{:.2%}', '6x%': '{:.2%}', 'GPP%': '{:.2%}'}
28
  mma_percentages_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '100+%': '{:.2%}', '10x%': '{:.2%}', '11x%': '{:.2%}', '12x%': '{:.2%}', 'GPP%': '{:.2%}'}
 
29
 
30
  def load_file(upload):
31
  if upload is not None:
@@ -59,7 +61,7 @@ with tab1:
59
  elif sport_var == "NFL":
60
  st.info("upload a projections file that has Data oriented in the following format: 'Player', 'Team', 'Opp', 'Position', 'Salary', 'Median', 'Rush Yards', 'Receptions', 'Own'")
61
  elif sport_var == "MLB":
62
- st.info("upload a projections file that has Data oriented in the following format: 'Player', 'Team', 'Opp', 'Position', 'Salary', 'Median', 'Minutes', 'Own'")
63
  elif sport_var == "MMA":
64
  st.info("upload a projections file that has Data oriented in the following format: 'Player', 'Salary', 'Median', 'KO Odds', 'Submission Odds', 'Own'")
65
  # Create two columns for the uploader and template button
@@ -74,7 +76,7 @@ with tab1:
74
  elif sport_var == "NFL":
75
  template_df = pd.DataFrame(columns=['Player', 'Team', 'Opp', 'Position', 'Salary', 'Median', 'Rush Yards', 'Receptions', 'Own'])
76
  elif sport_var == "MLB":
77
- template_df = pd.DataFrame(columns=['Player', 'Team', 'Opp', 'Position', 'Salary', 'Median', 'Minutes', 'Own'])
78
  elif sport_var == "MMA":
79
  template_df = pd.DataFrame(columns=['Player', 'Salary', 'Median', 'KO_odds', 'Sub_odds', 'Own'])
80
  # Add download button for template
@@ -147,5 +149,7 @@ with tab2:
147
  st.dataframe(disp_file.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(nfl_percentages_format, precision=2), height=1000, use_container_width = True)
148
  elif sport_var == "MMA":
149
  st.dataframe(disp_file.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(mma_percentages_format, precision=2), height=1000, use_container_width = True)
 
 
150
  except:
151
  pass
 
21
  from function_hold.MMA_functions import DK_MMA_ROO_Build, FD_MMA_ROO_Build
22
  from function_hold.NHL_functions import DK_NHL_ROO_Build, FD_NHL_ROO_Build
23
  from function_hold.NFL_functions import DK_NFL_ROO_Build, FD_NFL_ROO_Build
24
+ from function_hold.MLB_functions import DK_MLB_ROO_Build, FD_MLB_ROO_Build
25
 
26
  nba_percentages_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '4x%': '{:.2%}', '5x%': '{:.2%}', '6x%': '{:.2%}', 'GPP%': '{:.2%}'}
27
  nhl_percentages_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '4x%': '{:.2%}', '5x%': '{:.2%}', '6x%': '{:.2%}', 'GPP%': '{:.2%}'}
28
  nfl_percentages_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '4x%': '{:.2%}', '5x%': '{:.2%}', '6x%': '{:.2%}', 'GPP%': '{:.2%}'}
29
  mma_percentages_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '100+%': '{:.2%}', '10x%': '{:.2%}', '11x%': '{:.2%}', '12x%': '{:.2%}', 'GPP%': '{:.2%}'}
30
+ mlb_percentages_format = {'Top_finish': '{:.2%}', 'Top_5_finish': '{:.2%}', 'Top_10_finish': '{:.2%}', '20+%': '{:.2%}', '2x%': '{:.2%}', '3x%': '{:.2%}', '4x%': '{:.2%}', 'GPP%': '{:.2%}'}
31
 
32
  def load_file(upload):
33
  if upload is not None:
 
61
  elif sport_var == "NFL":
62
  st.info("upload a projections file that has Data oriented in the following format: 'Player', 'Team', 'Opp', 'Position', 'Salary', 'Median', 'Rush Yards', 'Receptions', 'Own'")
63
  elif sport_var == "MLB":
64
+ st.info("upload a projections file that has Data oriented in the following format: 'Player', 'Team', 'Opp', 'Position', 'Salary', 'Median', 'Own'")
65
  elif sport_var == "MMA":
66
  st.info("upload a projections file that has Data oriented in the following format: 'Player', 'Salary', 'Median', 'KO Odds', 'Submission Odds', 'Own'")
67
  # Create two columns for the uploader and template button
 
76
  elif sport_var == "NFL":
77
  template_df = pd.DataFrame(columns=['Player', 'Team', 'Opp', 'Position', 'Salary', 'Median', 'Rush Yards', 'Receptions', 'Own'])
78
  elif sport_var == "MLB":
79
+ template_df = pd.DataFrame(columns=['Player', 'Team', 'Opp', 'Position', 'Salary', 'Median', 'Own'])
80
  elif sport_var == "MMA":
81
  template_df = pd.DataFrame(columns=['Player', 'Salary', 'Median', 'KO_odds', 'Sub_odds', 'Own'])
82
  # Add download button for template
 
149
  st.dataframe(disp_file.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(nfl_percentages_format, precision=2), height=1000, use_container_width = True)
150
  elif sport_var == "MMA":
151
  st.dataframe(disp_file.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(mma_percentages_format, precision=2), height=1000, use_container_width = True)
152
+ elif sport_var == "MLB":
153
+ st.dataframe(disp_file.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(mlb_percentages_format, precision=2), height=1000, use_container_width = True)
154
  except:
155
  pass
function_hold/MLB_functions.py ADDED
@@ -0,0 +1,469 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from numpy import nan as np_nan
2
+ from numpy import where as np_where
3
+ from numpy import random as np_random
4
+ from numpy import zeros as np_zeros
5
+ from numpy import array as np_array
6
+ from pandas import concat as pd_concat
7
+ from pandas import merge as pd_merge
8
+ from pandas import DataFrame
9
+
10
+ def DK_MLB_ROO_Build(projections_file, floor_var, ceiling_var, std_var, distribution_type):
11
+ sp_frame = projections_file[projections_file['Position'].str.contains('P')]
12
+ hit_frame = projections_file[~projections_file['Position'].str.contains('P')]
13
+ sp_norm_var = 200 / sp_frame['Own'].sum()
14
+ sp_frame['Own'] = sp_frame['Own'] * sp_norm_var
15
+ hit_norm_var = 800 / hit_frame['Own'].sum()
16
+ hit_frame['Own'] = hit_frame['Own'] * hit_norm_var
17
+
18
+ working_roo = pd_concat([sp_frame, hit_frame])
19
+
20
+ own_dict = dict(zip(working_roo.Player, working_roo.Own))
21
+ team_dict = dict(zip(working_roo.Player, working_roo.Team))
22
+ player_id_dict = dict(zip(working_roo.Player, working_roo.player_ID))
23
+ total_sims = 1000
24
+
25
+ basic_own_df = working_roo.copy()
26
+ basic_own_df['name_team'] = basic_own_df['Player'] + basic_own_df['Position']
27
+
28
+ def calculate_ownership(df):
29
+ # Filter the dataframe based on the position
30
+ frame = df.copy()
31
+
32
+ # Calculate Small Field Own%
33
+ frame['Base Own%'] = np_where(
34
+ (frame['Own'] - frame['Own'].mean() >= 0),
35
+ frame['Own'] * (5 * (frame['Own'] - (frame['Own'].mean() / 1.5)) / 100) + frame['Own'].mean(),
36
+ frame['Own']
37
+ )
38
+ frame['Base Own%'] = np_where(
39
+ frame['Base Own%'] > 85,
40
+ 85,
41
+ frame['Base Own%']
42
+ )
43
+
44
+ # Calculate Small Field Own%
45
+ frame['Small Field Own%'] = np_where(
46
+ (frame['Own'] - frame['Own'].mean() >= 0),
47
+ frame['Own'] * (6 * (frame['Own'] - frame['Own'].mean()) / 100) + frame['Own'].mean(),
48
+ frame['Own']
49
+ )
50
+ frame['Small Field Own%'] = np_where(
51
+ frame['Small Field Own%'] > 85,
52
+ 85,
53
+ frame['Small Field Own%']
54
+ )
55
+
56
+ # Calculate Large Field Own%
57
+ frame['Large Field Own%'] = np_where(
58
+ (frame['Own'] - frame['Own'].mean() >= 0),
59
+ frame['Own'] * (2.5 * (frame['Own'] - frame['Own'].mean()) / 100) + frame['Own'].mean(),
60
+ frame['Own']
61
+ )
62
+ frame['Large Field Own%'] = np_where(
63
+ frame['Large Field Own%'] > 85,
64
+ 85,
65
+ frame['Large Field Own%']
66
+ )
67
+
68
+ # Calculate Cash Own%
69
+ frame['Cash Own%'] = np_where(
70
+ (frame['Own'] - frame['Own'].mean() >= 0),
71
+ frame['Own'] * (8 * (frame['Own'] - frame['Own'].mean()) / 100) + frame['Own'].mean(),
72
+ frame['Own']
73
+ )
74
+ frame['Cash Own%'] = np_where(
75
+ frame['Cash Own%'] > 85,
76
+ 85,
77
+ frame['Cash Own%']
78
+ )
79
+
80
+ return frame
81
+
82
+ # Apply the function to each dataframe
83
+ basic_own_df = calculate_ownership(basic_own_df)
84
+
85
+ own_norm_var_reg = 1000 / basic_own_df['Own'].sum()
86
+ own_norm_var_small = 1000 / basic_own_df['Small Field Own%'].sum()
87
+ own_norm_var_large = 1000 / basic_own_df['Large Field Own%'].sum()
88
+ own_norm_var_cash = 1000 / basic_own_df['Cash Own%'].sum()
89
+ basic_own_df['Own'] = basic_own_df['Own'] * own_norm_var_reg
90
+ basic_own_df['Small_Own'] = basic_own_df['Small Field Own%'] * own_norm_var_small
91
+ basic_own_df['Large_Own'] = basic_own_df['Large Field Own%'] * own_norm_var_large
92
+ basic_own_df['Cash_Own'] = basic_own_df['Cash Own%'] * own_norm_var_cash
93
+
94
+ basic_own_df['Own'] = np_where(basic_own_df['Own'] > 90, 90, basic_own_df['Own'])
95
+
96
+ # Apply the function to each dataframe
97
+ basic_own_df = calculate_ownership(basic_own_df)
98
+
99
+ own_norm_var_reg = 1000 / basic_own_df['Own'].sum()
100
+ own_norm_var_small = 1000 / basic_own_df['Small Field Own%'].sum()
101
+ own_norm_var_large = 1000 / basic_own_df['Large Field Own%'].sum()
102
+ own_norm_var_cash = 1000 / basic_own_df['Cash Own%'].sum()
103
+ basic_own_df['Own'] = basic_own_df['Own'] * own_norm_var_reg
104
+ basic_own_df['Small_Own'] = basic_own_df['Small Field Own%'] * own_norm_var_small
105
+ basic_own_df['Large_Own'] = basic_own_df['Large Field Own%'] * own_norm_var_large
106
+ basic_own_df['Cash_Own'] = basic_own_df['Cash Own%'] * own_norm_var_cash
107
+
108
+ own_dict = dict(zip(basic_own_df.Player, basic_own_df.Own))
109
+ small_own_dict = dict(zip(basic_own_df.Player, basic_own_df['Small Field Own%']))
110
+ large_own_dict = dict(zip(basic_own_df.Player, basic_own_df['Large Field Own%']))
111
+ cash_own_dict = dict(zip(basic_own_df.Player, basic_own_df['Cash Own%']))
112
+ team_dict = dict(zip(basic_own_df.name_team, basic_own_df.Team))
113
+ opp_dict = dict(zip(basic_own_df.Player, basic_own_df.Opp))
114
+
115
+ flex_file = basic_own_df[['Player', 'Position', 'Salary', 'Median']]
116
+ flex_file = flex_file.rename(columns={"Agg": "Median"})
117
+ flex_file['Floor'] = (flex_file['Median'] * floor_var)
118
+ flex_file['Ceiling'] = flex_file['Median'] + (5 * ceiling_var)
119
+ flex_file['STD'] = (flex_file['Median'] / std_var)
120
+ flex_file = flex_file[['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'STD']]
121
+ flex_file = flex_file.reset_index(drop=True)
122
+ hold_file = flex_file.copy()
123
+ overall_file = flex_file.copy()
124
+ salary_file = flex_file.copy()
125
+
126
+ try:
127
+ overall_floor_gpu = np_array(overall_file['Floor'])
128
+ overall_ceiling_gpu = np_array(overall_file['Ceiling'])
129
+ overall_median_gpu = np_array(overall_file['Median'])
130
+ overall_std_gpu = np_array(overall_file['STD'])
131
+ overall_salary_gpu = np_array(overall_file['Salary'])
132
+
133
+ data_shape = (len(overall_file['Player']), total_sims) # Example: 1000 rows
134
+ salary_array = np_zeros(data_shape)
135
+ sim_array = np_zeros(data_shape)
136
+
137
+ for x in range(0, total_sims):
138
+ result_gpu = overall_salary_gpu
139
+ salary_array[:, x] = result_gpu
140
+ cupy_array = salary_array
141
+
142
+ salary_file = salary_file.reset_index(drop=True)
143
+ salary_cupy = DataFrame(cupy_array, columns=list(range(0, total_sims)))
144
+ salary_check_file = pd_concat([salary_file, salary_cupy], axis=1)
145
+ except:
146
+ for x in range(0,total_sims):
147
+ salary_file[x] = salary_file['Salary']
148
+ salary_check_file = salary_file.copy()
149
+
150
+ salary_file=salary_check_file.drop(['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
151
+
152
+ salary_file = salary_file.div(1000)
153
+
154
+ try:
155
+ for x in range(0, total_sims):
156
+ if distribution_type == 'normal':
157
+ # Normal distribution (existing logic)
158
+ result_gpu = np_random.normal(overall_median_gpu, overall_std_gpu)
159
+ elif distribution_type == 'poisson':
160
+ # Poisson distribution - using median as lambda
161
+ result_gpu = np_random.poisson(overall_median_gpu)
162
+ elif distribution_type == 'bimodal':
163
+ # Bimodal distribution - mixture of two normal distributions
164
+ # First peak centered at 80% of median, second at 120% of median
165
+ if np_random.random() < 0.5:
166
+ result_gpu = np_random.normal(overall_floor_gpu, overall_std_gpu)
167
+ else:
168
+ result_gpu = np_random.normal(overall_ceiling_gpu, overall_std_gpu)
169
+ else:
170
+ raise ValueError("Invalid distribution type. Must be 'normal', 'poisson', or 'bimodal'")
171
+
172
+ sim_array[:, x] = result_gpu
173
+ add_array = sim_array
174
+
175
+ overall_file = overall_file.reset_index(drop=True)
176
+ df2 = DataFrame(add_array, columns=list(range(0, total_sims)))
177
+ check_file = pd_concat([overall_file, df2], axis=1)
178
+ except:
179
+ for x in range(0,total_sims):
180
+ if distribution_type == 'normal':
181
+ overall_file[x] = np_random.normal(overall_file['Median'], overall_file['STD'])
182
+ elif distribution_type == 'poisson':
183
+ overall_file[x] = np_random.poisson(overall_file['Median'])
184
+ elif distribution_type == 'bimodal':
185
+ # Bimodal distribution fallback
186
+ if np_random.random() < 0.5:
187
+ overall_file[x] = np_random.normal(overall_file['Median'] * 0.8, overall_file['STD'])
188
+ else:
189
+ overall_file[x] = np_random.normal(overall_file['Median'] * 1.2, overall_file['STD'])
190
+ check_file = overall_file.copy()
191
+
192
+ overall_file=check_file.drop(['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
193
+
194
+ players_only = hold_file[['Player']]
195
+ raw_lineups_file = players_only
196
+
197
+ for x in range(0,total_sims):
198
+ maps_dict = {'proj_map':dict(zip(hold_file.Player,overall_file[x]))}
199
+ raw_lineups_file[x] = sum([raw_lineups_file['Player'].map(maps_dict['proj_map'])])
200
+ players_only[x] = raw_lineups_file[x].rank(ascending=False)
201
+
202
+ players_only=players_only.drop(['Player'], axis=1)
203
+
204
+ salary_2x_check = (overall_file - (salary_file*2))
205
+ salary_3x_check = (overall_file - (salary_file*3))
206
+ salary_4x_check = (overall_file - (salary_file*4))
207
+ gpp_check = (overall_file - ((salary_file*5)+10))
208
+
209
+ players_only['Average_Rank'] = players_only.mean(axis=1)
210
+ players_only['Top_finish'] = players_only[players_only == 1].count(axis=1)/total_sims
211
+ players_only['Top_5_finish'] = players_only[players_only <= 5].count(axis=1)/total_sims
212
+ players_only['Top_10_finish'] = players_only[players_only <= 10].count(axis=1)/total_sims
213
+ players_only['20+%'] = overall_file[overall_file >= 20].count(axis=1)/float(total_sims)
214
+ players_only['2x%'] = salary_2x_check[salary_2x_check >= 1].count(axis=1)/float(total_sims)
215
+ players_only['3x%'] = salary_3x_check[salary_3x_check >= 1].count(axis=1)/float(total_sims)
216
+ players_only['4x%'] = salary_4x_check[salary_4x_check >= 1].count(axis=1)/float(total_sims)
217
+ players_only['GPP%'] = gpp_check[gpp_check >= 1].count(axis=1)/float(total_sims)
218
+
219
+ players_only['Player'] = hold_file[['Player']]
220
+
221
+ final_outcomes = players_only[['Player', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'GPP%']]
222
+
223
+ final_Proj = pd_merge(hold_file, final_outcomes, on="Player")
224
+ final_Proj = final_Proj[['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'GPP%']]
225
+
226
+ final_Proj['name_team'] = final_Proj['Player'] + final_Proj['Position']
227
+ final_Proj['Own'] = final_Proj['Player'].map(own_dict)
228
+ final_Proj['Small_Own'] = final_Proj['Player'].map(small_own_dict)
229
+ final_Proj['Large_Own'] = final_Proj['Player'].map(large_own_dict)
230
+ final_Proj['Cash_Own'] = final_Proj['Player'].map(cash_own_dict)
231
+ final_Proj['Team'] = final_Proj['name_team'].map(team_dict)
232
+ final_Proj['Opp'] = final_Proj['Player'].map(opp_dict)
233
+
234
+ final_Proj = final_Proj[['Player', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'GPP%',
235
+ 'Own', 'Small_Own', 'Large_Own', 'Cash_Own']]
236
+ final_Proj = final_Proj.sort_values(by='Median', ascending=False)
237
+
238
+ return final_Proj.copy()
239
+
240
+ def FD_MLB_ROO_Build(projections_file, floor_var, ceiling_var, std_var, distribution_type):
241
+ sp_frame = projections_file[projections_file['Position'].str.contains('P')]
242
+ hit_frame = projections_file[~projections_file['Position'].str.contains('P')]
243
+ sp_norm_var = 100 / sp_frame['Own'].sum()
244
+ sp_frame['Own'] = sp_frame['Own'] * sp_norm_var
245
+ hit_norm_var = 800 / hit_frame['Own'].sum()
246
+ hit_frame['Own'] = hit_frame['Own'] * hit_norm_var
247
+
248
+ working_roo = pd_concat([sp_frame, hit_frame])
249
+
250
+ own_dict = dict(zip(working_roo.Player, working_roo.Own))
251
+ team_dict = dict(zip(working_roo.Player, working_roo.Team))
252
+ player_id_dict = dict(zip(working_roo.Player, working_roo.player_ID))
253
+ total_sims = 1000
254
+
255
+ basic_own_df = working_roo.copy()
256
+ basic_own_df['name_team'] = basic_own_df['Player'] + basic_own_df['Position']
257
+
258
+ def calculate_ownership(df):
259
+ # Filter the dataframe based on the position
260
+ frame = df.copy()
261
+
262
+ # Calculate Small Field Own%
263
+ frame['Base Own%'] = np_where(
264
+ (frame['Own'] - frame['Own'].mean() >= 0),
265
+ frame['Own'] * (5 * (frame['Own'] - (frame['Own'].mean() / 1.5)) / 100) + frame['Own'].mean(),
266
+ frame['Own']
267
+ )
268
+ frame['Base Own%'] = np_where(
269
+ frame['Base Own%'] > 85,
270
+ 85,
271
+ frame['Base Own%']
272
+ )
273
+
274
+ # Calculate Small Field Own%
275
+ frame['Small Field Own%'] = np_where(
276
+ (frame['Own'] - frame['Own'].mean() >= 0),
277
+ frame['Own'] * (6 * (frame['Own'] - frame['Own'].mean()) / 100) + frame['Own'].mean(),
278
+ frame['Own']
279
+ )
280
+ frame['Small Field Own%'] = np_where(
281
+ frame['Small Field Own%'] > 85,
282
+ 85,
283
+ frame['Small Field Own%']
284
+ )
285
+
286
+ # Calculate Large Field Own%
287
+ frame['Large Field Own%'] = np_where(
288
+ (frame['Own'] - frame['Own'].mean() >= 0),
289
+ frame['Own'] * (2.5 * (frame['Own'] - frame['Own'].mean()) / 100) + frame['Own'].mean(),
290
+ frame['Own']
291
+ )
292
+ frame['Large Field Own%'] = np_where(
293
+ frame['Large Field Own%'] > 85,
294
+ 85,
295
+ frame['Large Field Own%']
296
+ )
297
+
298
+ # Calculate Cash Own%
299
+ frame['Cash Own%'] = np_where(
300
+ (frame['Own'] - frame['Own'].mean() >= 0),
301
+ frame['Own'] * (8 * (frame['Own'] - frame['Own'].mean()) / 100) + frame['Own'].mean(),
302
+ frame['Own']
303
+ )
304
+ frame['Cash Own%'] = np_where(
305
+ frame['Cash Own%'] > 85,
306
+ 85,
307
+ frame['Cash Own%']
308
+ )
309
+
310
+ return frame
311
+
312
+ # Apply the function to each dataframe
313
+ basic_own_df = calculate_ownership(basic_own_df)
314
+
315
+ own_norm_var_reg = 900 / basic_own_df['Own'].sum()
316
+ own_norm_var_small = 900 / basic_own_df['Small Field Own%'].sum()
317
+ own_norm_var_large = 900 / basic_own_df['Large Field Own%'].sum()
318
+ own_norm_var_cash = 900 / basic_own_df['Cash Own%'].sum()
319
+ basic_own_df['Own'] = basic_own_df['Own'] * own_norm_var_reg
320
+ basic_own_df['Small_Own'] = basic_own_df['Small Field Own%'] * own_norm_var_small
321
+ basic_own_df['Large_Own'] = basic_own_df['Large Field Own%'] * own_norm_var_large
322
+ basic_own_df['Cash_Own'] = basic_own_df['Cash Own%'] * own_norm_var_cash
323
+
324
+ basic_own_df['Own'] = np_where(basic_own_df['Own'] > 90, 90, basic_own_df['Own'])
325
+
326
+ # Apply the function to each dataframe
327
+ basic_own_df = calculate_ownership(basic_own_df)
328
+
329
+ own_norm_var_reg = 900 / basic_own_df['Own'].sum()
330
+ own_norm_var_small = 900 / basic_own_df['Small Field Own%'].sum()
331
+ own_norm_var_large = 900 / basic_own_df['Large Field Own%'].sum()
332
+ own_norm_var_cash = 900 / basic_own_df['Cash Own%'].sum()
333
+ basic_own_df['Own'] = basic_own_df['Own'] * own_norm_var_reg
334
+ basic_own_df['Small_Own'] = basic_own_df['Small Field Own%'] * own_norm_var_small
335
+ basic_own_df['Large_Own'] = basic_own_df['Large Field Own%'] * own_norm_var_large
336
+ basic_own_df['Cash_Own'] = basic_own_df['Cash Own%'] * own_norm_var_cash
337
+
338
+ own_dict = dict(zip(basic_own_df.Player, basic_own_df.Own))
339
+ small_own_dict = dict(zip(basic_own_df.Player, basic_own_df['Small Field Own%']))
340
+ large_own_dict = dict(zip(basic_own_df.Player, basic_own_df['Large Field Own%']))
341
+ cash_own_dict = dict(zip(basic_own_df.Player, basic_own_df['Cash Own%']))
342
+ team_dict = dict(zip(basic_own_df.name_team, basic_own_df.Team))
343
+ opp_dict = dict(zip(basic_own_df.Player, basic_own_df.Opp))
344
+
345
+ flex_file = basic_own_df[['Player', 'Position', 'Salary', 'Median']]
346
+ flex_file = flex_file.rename(columns={"Agg": "Median"})
347
+ flex_file['Floor'] = (flex_file['Median'] * floor_var)
348
+ flex_file['Ceiling'] = flex_file['Median'] + (5 * ceiling_var)
349
+ flex_file['STD'] = (flex_file['Median'] / std_var)
350
+ flex_file = flex_file[['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'STD']]
351
+ flex_file = flex_file.reset_index(drop=True)
352
+ hold_file = flex_file.copy()
353
+ overall_file = flex_file.copy()
354
+ salary_file = flex_file.copy()
355
+
356
+ try:
357
+ overall_floor_gpu = np_array(overall_file['Floor'])
358
+ overall_ceiling_gpu = np_array(overall_file['Ceiling'])
359
+ overall_median_gpu = np_array(overall_file['Median'])
360
+ overall_std_gpu = np_array(overall_file['STD'])
361
+ overall_salary_gpu = np_array(overall_file['Salary'])
362
+
363
+ data_shape = (len(overall_file['Player']), total_sims) # Example: 1000 rows
364
+ salary_array = np_zeros(data_shape)
365
+ sim_array = np_zeros(data_shape)
366
+
367
+ for x in range(0, total_sims):
368
+ result_gpu = overall_salary_gpu
369
+ salary_array[:, x] = result_gpu
370
+ cupy_array = salary_array
371
+
372
+ salary_file = salary_file.reset_index(drop=True)
373
+ salary_cupy = DataFrame(cupy_array, columns=list(range(0, total_sims)))
374
+ salary_check_file = pd_concat([salary_file, salary_cupy], axis=1)
375
+ except:
376
+ for x in range(0,total_sims):
377
+ salary_file[x] = salary_file['Salary']
378
+ salary_check_file = salary_file.copy()
379
+
380
+ salary_file=salary_check_file.drop(['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
381
+
382
+ salary_file = salary_file.div(1000)
383
+
384
+ try:
385
+ for x in range(0, total_sims):
386
+ if distribution_type == 'normal':
387
+ # Normal distribution (existing logic)
388
+ result_gpu = np_random.normal(overall_median_gpu, overall_std_gpu)
389
+ elif distribution_type == 'poisson':
390
+ # Poisson distribution - using median as lambda
391
+ result_gpu = np_random.poisson(overall_median_gpu)
392
+ elif distribution_type == 'bimodal':
393
+ # Bimodal distribution - mixture of two normal distributions
394
+ # First peak centered at 80% of median, second at 120% of median
395
+ if np_random.random() < 0.5:
396
+ result_gpu = np_random.normal(overall_floor_gpu, overall_std_gpu)
397
+ else:
398
+ result_gpu = np_random.normal(overall_ceiling_gpu, overall_std_gpu)
399
+ else:
400
+ raise ValueError("Invalid distribution type. Must be 'normal', 'poisson', or 'bimodal'")
401
+
402
+ sim_array[:, x] = result_gpu
403
+ add_array = sim_array
404
+
405
+ overall_file = overall_file.reset_index(drop=True)
406
+ df2 = DataFrame(add_array, columns=list(range(0, total_sims)))
407
+ check_file = pd_concat([overall_file, df2], axis=1)
408
+ except:
409
+ for x in range(0,total_sims):
410
+ if distribution_type == 'normal':
411
+ overall_file[x] = np_random.normal(overall_file['Median'], overall_file['STD'])
412
+ elif distribution_type == 'poisson':
413
+ overall_file[x] = np_random.poisson(overall_file['Median'])
414
+ elif distribution_type == 'bimodal':
415
+ # Bimodal distribution fallback
416
+ if np_random.random() < 0.5:
417
+ overall_file[x] = np_random.normal(overall_file['Median'] * 0.8, overall_file['STD'])
418
+ else:
419
+ overall_file[x] = np_random.normal(overall_file['Median'] * 1.2, overall_file['STD'])
420
+ check_file = overall_file.copy()
421
+
422
+ overall_file=check_file.drop(['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
423
+
424
+ players_only = hold_file[['Player']]
425
+ raw_lineups_file = players_only
426
+
427
+ for x in range(0,total_sims):
428
+ maps_dict = {'proj_map':dict(zip(hold_file.Player,overall_file[x]))}
429
+ raw_lineups_file[x] = sum([raw_lineups_file['Player'].map(maps_dict['proj_map'])])
430
+ players_only[x] = raw_lineups_file[x].rank(ascending=False)
431
+
432
+ players_only=players_only.drop(['Player'], axis=1)
433
+
434
+ salary_2x_check = (overall_file - (salary_file*2))
435
+ salary_3x_check = (overall_file - (salary_file*3))
436
+ salary_4x_check = (overall_file - (salary_file*4))
437
+ gpp_check = (overall_file - ((salary_file*5)+10))
438
+
439
+ players_only['Average_Rank'] = players_only.mean(axis=1)
440
+ players_only['Top_finish'] = players_only[players_only == 1].count(axis=1)/total_sims
441
+ players_only['Top_5_finish'] = players_only[players_only <= 5].count(axis=1)/total_sims
442
+ players_only['Top_10_finish'] = players_only[players_only <= 10].count(axis=1)/total_sims
443
+ players_only['20+%'] = overall_file[overall_file >= 20].count(axis=1)/float(total_sims)
444
+ players_only['2x%'] = salary_2x_check[salary_2x_check >= 1].count(axis=1)/float(total_sims)
445
+ players_only['3x%'] = salary_3x_check[salary_3x_check >= 1].count(axis=1)/float(total_sims)
446
+ players_only['4x%'] = salary_4x_check[salary_4x_check >= 1].count(axis=1)/float(total_sims)
447
+ players_only['GPP%'] = gpp_check[gpp_check >= 1].count(axis=1)/float(total_sims)
448
+
449
+ players_only['Player'] = hold_file[['Player']]
450
+
451
+ final_outcomes = players_only[['Player', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'GPP%']]
452
+
453
+ final_Proj = pd_merge(hold_file, final_outcomes, on="Player")
454
+ final_Proj = final_Proj[['Player', 'Position', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'GPP%']]
455
+
456
+ final_Proj['name_team'] = final_Proj['Player'] + final_Proj['Position']
457
+ final_Proj['Own'] = final_Proj['Player'].map(own_dict)
458
+ final_Proj['Small_Own'] = final_Proj['Player'].map(small_own_dict)
459
+ final_Proj['Large_Own'] = final_Proj['Player'].map(large_own_dict)
460
+ final_Proj['Cash_Own'] = final_Proj['Player'].map(cash_own_dict)
461
+ final_Proj['Team'] = final_Proj['name_team'].map(team_dict)
462
+ final_Proj['Opp'] = final_Proj['Player'].map(opp_dict)
463
+
464
+ final_Proj = final_Proj[['Player', 'Position', 'Team', 'Opp', 'Salary', 'Floor', 'Median', 'Ceiling', 'Top_finish', 'Top_5_finish', 'Top_10_finish', '20+%', '2x%', '3x%', '4x%', 'GPP%',
465
+ 'Own', 'Small_Own', 'Large_Own', 'Cash_Own']]
466
+ final_Proj['Salary'] = final_Proj['Salary'].astype(int)
467
+ final_Proj = final_Proj.sort_values(by='Median', ascending=False)
468
+
469
+ return final_Proj.copy()