James McCool
commited on
Commit
·
42c2829
1
Parent(s):
63139f0
Enhance predict_dupes function by adding max_salary parameter for improved salary handling and adjusting sample range slider step in app.py for better user experience.
Browse files- app.py +2 -2
- global_func/predict_dupes.py +106 -247
app.py
CHANGED
|
@@ -1093,7 +1093,7 @@ with tab2:
|
|
| 1093 |
st.session_state['working_frame']['median'] = st.session_state['working_frame']['median'].astype('float32')
|
| 1094 |
st.session_state['working_frame']['salary'] = st.session_state['working_frame']['salary'].astype('uint16')
|
| 1095 |
|
| 1096 |
-
st.session_state['base_frame'] = predict_dupes(st.session_state['working_frame'], st.session_state['map_dict'], site_var, type_var, Contest_Size, strength_var, sport_var)
|
| 1097 |
st.session_state['working_frame'] = st.session_state['base_frame'].copy()
|
| 1098 |
# st.session_state['highest_owned_teams'] = st.session_state['projections_df'][~st.session_state['projections_df']['position'].isin(['P', 'SP'])].groupby('team')['ownership'].sum().sort_values(ascending=False).head(3).index.tolist()
|
| 1099 |
# st.session_state['highest_owned_pitchers'] = st.session_state['projections_df'][st.session_state['projections_df']['position'].isin(['P', 'SP'])]['player_names'].sort_values(by='ownership', ascending=False).head(3).tolist()
|
|
@@ -1441,7 +1441,7 @@ with tab2:
|
|
| 1441 |
with st.form(key='Stratification'):
|
| 1442 |
sorting_choice = st.selectbox("Stat Choice", options=['median', 'Own', 'Weighted Own', 'Geomean', 'Lineup Edge', 'Finish_percentile', 'Diversity'], index=0)
|
| 1443 |
lineup_target = st.number_input("Lineups to produce", value=150, min_value=1, step=1)
|
| 1444 |
-
strat_sample = st.slider("Sample range", value=[0.0, 100.0], min_value=0.0, max_value=100.0, step=0
|
| 1445 |
submitted_col, export_col = st.columns(2)
|
| 1446 |
st.info("Portfolio Button applies to your overall Portfolio, Export button applies to your Custom Export")
|
| 1447 |
with submitted_col:
|
|
|
|
| 1093 |
st.session_state['working_frame']['median'] = st.session_state['working_frame']['median'].astype('float32')
|
| 1094 |
st.session_state['working_frame']['salary'] = st.session_state['working_frame']['salary'].astype('uint16')
|
| 1095 |
|
| 1096 |
+
st.session_state['base_frame'] = predict_dupes(st.session_state['working_frame'], st.session_state['map_dict'], site_var, type_var, Contest_Size, strength_var, sport_var, salary_max)
|
| 1097 |
st.session_state['working_frame'] = st.session_state['base_frame'].copy()
|
| 1098 |
# st.session_state['highest_owned_teams'] = st.session_state['projections_df'][~st.session_state['projections_df']['position'].isin(['P', 'SP'])].groupby('team')['ownership'].sum().sort_values(ascending=False).head(3).index.tolist()
|
| 1099 |
# st.session_state['highest_owned_pitchers'] = st.session_state['projections_df'][st.session_state['projections_df']['position'].isin(['P', 'SP'])]['player_names'].sort_values(by='ownership', ascending=False).head(3).tolist()
|
|
|
|
| 1441 |
with st.form(key='Stratification'):
|
| 1442 |
sorting_choice = st.selectbox("Stat Choice", options=['median', 'Own', 'Weighted Own', 'Geomean', 'Lineup Edge', 'Finish_percentile', 'Diversity'], index=0)
|
| 1443 |
lineup_target = st.number_input("Lineups to produce", value=150, min_value=1, step=1)
|
| 1444 |
+
strat_sample = st.slider("Sample range", value=[0.0, 100.0], min_value=0.0, max_value=100.0, step=1.0)
|
| 1445 |
submitted_col, export_col = st.columns(2)
|
| 1446 |
st.info("Portfolio Button applies to your overall Portfolio, Export button applies to your Custom Export")
|
| 1447 |
with submitted_col:
|
global_func/predict_dupes.py
CHANGED
|
@@ -4,7 +4,6 @@ import pandas as pd
|
|
| 4 |
import time
|
| 5 |
import math
|
| 6 |
from difflib import SequenceMatcher
|
| 7 |
-
import heapq
|
| 8 |
|
| 9 |
def calculate_weighted_ownership_vectorized(ownership_array):
|
| 10 |
"""
|
|
@@ -106,182 +105,8 @@ def calculate_player_similarity_score_vectorized(portfolio, player_columns):
|
|
| 106 |
|
| 107 |
return similarity_scores
|
| 108 |
|
| 109 |
-
def predict_dupes_vectorized(portfolio, maps_dict, site_var, type_var, Contest_Size, strength_var, sport_var):
|
| 110 |
-
"""
|
| 111 |
-
Vectorized version of predict_dupes using NumPy arrays for better performance.
|
| 112 |
-
"""
|
| 113 |
-
# Set multipliers based on strength
|
| 114 |
-
if strength_var == 'Weak':
|
| 115 |
-
dupes_multiplier = 0.75
|
| 116 |
-
percentile_multiplier = 0.90
|
| 117 |
-
elif strength_var == 'Average':
|
| 118 |
-
dupes_multiplier = 1.00
|
| 119 |
-
percentile_multiplier = 1.00
|
| 120 |
-
elif strength_var == 'Sharp':
|
| 121 |
-
dupes_multiplier = 1.25
|
| 122 |
-
percentile_multiplier = 1.10
|
| 123 |
-
|
| 124 |
-
max_ownership = max(maps_dict['own_map'].values()) / 100
|
| 125 |
-
average_ownership = np.mean(list(maps_dict['own_map'].values())) / 100
|
| 126 |
-
|
| 127 |
-
# Convert portfolio to NumPy arrays for faster operations
|
| 128 |
-
portfolio_values = portfolio.values
|
| 129 |
-
n_rows = len(portfolio)
|
| 130 |
-
|
| 131 |
-
# Pre-allocate arrays for ownership data
|
| 132 |
-
if site_var == 'Fanduel':
|
| 133 |
-
if type_var == 'Showdown':
|
| 134 |
-
num_players = 5
|
| 135 |
-
salary_cap = 60000
|
| 136 |
-
player_cols = list(range(5)) # First 5 columns are players
|
| 137 |
-
elif type_var == 'Classic':
|
| 138 |
-
if sport_var == 'WNBA':
|
| 139 |
-
num_players = len([col for col in portfolio.columns if col not in ['salary', 'median', 'Own']])
|
| 140 |
-
salary_cap = 40000
|
| 141 |
-
player_cols = list(range(num_players))
|
| 142 |
-
else:
|
| 143 |
-
num_players = len([col for col in portfolio.columns if col not in ['salary', 'median', 'Own']])
|
| 144 |
-
salary_cap = 60000
|
| 145 |
-
player_cols = list(range(num_players))
|
| 146 |
-
elif site_var == 'Draftkings':
|
| 147 |
-
if type_var == 'Showdown':
|
| 148 |
-
num_players = 6
|
| 149 |
-
salary_cap = 50000
|
| 150 |
-
player_cols = list(range(6))
|
| 151 |
-
elif type_var == 'Classic':
|
| 152 |
-
if sport_var == 'CS2':
|
| 153 |
-
num_players = 6
|
| 154 |
-
salary_cap = 50000
|
| 155 |
-
player_cols = list(range(6))
|
| 156 |
-
elif sport_var == 'LOL':
|
| 157 |
-
num_players = 7
|
| 158 |
-
salary_cap = 50000
|
| 159 |
-
player_cols = list(range(7))
|
| 160 |
-
else:
|
| 161 |
-
num_players = len([col for col in portfolio.columns if col not in ['salary', 'median', 'Own']])
|
| 162 |
-
salary_cap = 50000
|
| 163 |
-
player_cols = list(range(num_players))
|
| 164 |
-
|
| 165 |
-
# Pre-allocate ownership arrays
|
| 166 |
-
ownership_array = np.zeros((n_rows, num_players), dtype=np.float32)
|
| 167 |
-
ownership_rank_array = np.zeros((n_rows, num_players), dtype=np.float32)
|
| 168 |
-
|
| 169 |
-
# Vectorized ownership mapping
|
| 170 |
-
for i, col_idx in enumerate(player_cols):
|
| 171 |
-
if i == 0 and type_var == 'Showdown': # Captain
|
| 172 |
-
ownership_array[:, i] = np.vectorize(lambda x: maps_dict['cpt_own_map'].get(x, 0))(portfolio_values[:, col_idx]) / 100
|
| 173 |
-
ownership_rank_array[:, i] = np.vectorize(lambda x: maps_dict['cpt_own_map'].get(x, 0))(portfolio_values[:, col_idx])
|
| 174 |
-
else: # Flex players
|
| 175 |
-
ownership_array[:, i] = np.vectorize(lambda x: maps_dict['own_map'].get(x, 0))(portfolio_values[:, col_idx]) / 100
|
| 176 |
-
ownership_rank_array[:, i] = np.vectorize(lambda x: maps_dict['own_map'].get(x, 0))(portfolio_values[:, col_idx])
|
| 177 |
-
|
| 178 |
-
# Calculate ranks for flex players (excluding captain)
|
| 179 |
-
if type_var == 'Showdown':
|
| 180 |
-
flex_ownerships = ownership_rank_array[:, 1:].flatten()
|
| 181 |
-
flex_rank = pd.Series(flex_ownerships).rank(pct=True).values.reshape(n_rows, -1)
|
| 182 |
-
ownership_rank_array[:, 1:] = flex_rank
|
| 183 |
-
|
| 184 |
-
# Convert to percentile ranks
|
| 185 |
-
ownership_rank_array = ownership_rank_array / 100
|
| 186 |
-
|
| 187 |
-
# Vectorized calculations
|
| 188 |
-
own_product = np.prod(ownership_array, axis=1)
|
| 189 |
-
own_average = (portfolio_values[:, portfolio.columns.get_loc('Own')].max() * 0.33) / 100
|
| 190 |
-
own_sum = np.sum(ownership_array, axis=1)
|
| 191 |
-
avg_own_rank = np.mean(ownership_rank_array, axis=1)
|
| 192 |
-
|
| 193 |
-
# Calculate dupes formula vectorized
|
| 194 |
-
salary_col = portfolio.columns.get_loc('salary')
|
| 195 |
-
own_col = portfolio.columns.get_loc('Own')
|
| 196 |
-
|
| 197 |
-
dupes_calc = (own_product * avg_own_rank) * Contest_Size + \
|
| 198 |
-
((portfolio_values[:, salary_col] - (salary_cap - portfolio_values[:, own_col])) / 100) - \
|
| 199 |
-
((salary_cap - portfolio_values[:, salary_col]) / 100)
|
| 200 |
-
|
| 201 |
-
dupes_calc *= dupes_multiplier
|
| 202 |
-
|
| 203 |
-
# Round and handle negative values
|
| 204 |
-
dupes = np.where(np.round(dupes_calc, 0) <= 0, 0, np.round(dupes_calc, 0) - 1)
|
| 205 |
-
|
| 206 |
-
# Calculate own_ratio vectorized
|
| 207 |
-
max_own_mask = np.any(ownership_array == max_ownership, axis=1)
|
| 208 |
-
own_ratio = np.where(max_own_mask,
|
| 209 |
-
own_sum / own_average,
|
| 210 |
-
(own_sum - max_ownership) / own_average)
|
| 211 |
-
|
| 212 |
-
# Calculate Finish_percentile vectorized
|
| 213 |
-
percentile_cut_scalar = portfolio_values[:, portfolio.columns.get_loc('median')].max()
|
| 214 |
-
|
| 215 |
-
if type_var == 'Classic':
|
| 216 |
-
own_ratio_nerf = 2 if sport_var == 'CS2' or sport_var == 'LOL' else 1.5
|
| 217 |
-
elif type_var == 'Showdown':
|
| 218 |
-
own_ratio_nerf = 1.5
|
| 219 |
-
|
| 220 |
-
median_col = portfolio.columns.get_loc('median')
|
| 221 |
-
finish_percentile = (own_ratio - own_ratio_nerf) / ((5 * (portfolio_values[:, median_col] / percentile_cut_scalar)) / 3)
|
| 222 |
-
finish_percentile = np.where(finish_percentile < 0.0005, 0.0005, finish_percentile / 2)
|
| 223 |
-
|
| 224 |
-
# Calculate other metrics vectorized
|
| 225 |
-
ref_proj = portfolio_values[:, median_col].max()
|
| 226 |
-
max_proj = ref_proj + 10
|
| 227 |
-
min_proj = ref_proj - 10
|
| 228 |
-
avg_ref = (max_proj + min_proj) / 2
|
| 229 |
-
|
| 230 |
-
win_percent = (((portfolio_values[:, median_col] / avg_ref) - (0.1 + ((ref_proj - portfolio_values[:, median_col])/100))) / (Contest_Size / 1000)) / 10
|
| 231 |
-
max_allowed_win = (1 / Contest_Size) * 5
|
| 232 |
-
win_percent = win_percent / win_percent.max() * max_allowed_win
|
| 233 |
-
|
| 234 |
-
finish_percentile = finish_percentile + 0.005 + (0.005 * (Contest_Size / 10000))
|
| 235 |
-
finish_percentile *= percentile_multiplier
|
| 236 |
-
win_percent *= (1 - finish_percentile)
|
| 237 |
-
|
| 238 |
-
# Calculate low ownership count vectorized
|
| 239 |
-
low_own_count = np.sum(ownership_array < 0.10, axis=1)
|
| 240 |
-
finish_percentile = np.where(low_own_count <= 0,
|
| 241 |
-
finish_percentile,
|
| 242 |
-
finish_percentile / low_own_count)
|
| 243 |
-
|
| 244 |
-
# Calculate Lineup Edge vectorized
|
| 245 |
-
lineup_edge = win_percent * ((0.5 - finish_percentile) * (Contest_Size / 2.5))
|
| 246 |
-
lineup_edge = np.where(dupes > 0, lineup_edge / (dupes + 1), lineup_edge)
|
| 247 |
-
lineup_edge = lineup_edge - lineup_edge.mean()
|
| 248 |
-
|
| 249 |
-
# Calculate Weighted Own vectorized
|
| 250 |
-
weighted_own = calculate_weighted_ownership_vectorized(ownership_array)
|
| 251 |
-
|
| 252 |
-
# Calculate Geomean vectorized
|
| 253 |
-
geomean = np.power(np.prod(ownership_array * 100, axis=1), 1 / num_players)
|
| 254 |
-
|
| 255 |
-
# Calculate Diversity vectorized
|
| 256 |
-
diversity = calculate_player_similarity_score_vectorized(portfolio, player_cols)
|
| 257 |
-
|
| 258 |
-
# Create result DataFrame with optimized data types
|
| 259 |
-
result_data = {
|
| 260 |
-
'Dupes': dupes.astype('uint16'),
|
| 261 |
-
'median': portfolio_values[:, portfolio.columns.get_loc('median')].astype('float32'),
|
| 262 |
-
'Own': portfolio_values[:, portfolio.columns.get_loc('Own')].astype('float32'),
|
| 263 |
-
'salary': portfolio_values[:, portfolio.columns.get_loc('salary')].astype('uint16'),
|
| 264 |
-
'Finish_percentile': finish_percentile.astype('float32'),
|
| 265 |
-
'Win%': win_percent.astype('float32'),
|
| 266 |
-
'Lineup Edge': lineup_edge.astype('float32'),
|
| 267 |
-
'Weighted Own': weighted_own.astype('float32'),
|
| 268 |
-
'Geomean': geomean.astype('float32'),
|
| 269 |
-
'Diversity': diversity.astype('float32')
|
| 270 |
-
}
|
| 271 |
-
|
| 272 |
-
# Add Size column if it exists
|
| 273 |
-
if 'Size' in portfolio.columns:
|
| 274 |
-
result_data['Size'] = portfolio_values[:, portfolio.columns.get_loc('Size')].astype('uint16')
|
| 275 |
-
|
| 276 |
-
# Add player columns back
|
| 277 |
-
for i, col_name in enumerate(portfolio.columns[:num_players]):
|
| 278 |
-
result_data[col_name] = portfolio_values[:, i]
|
| 279 |
-
|
| 280 |
-
return pd.DataFrame(result_data)
|
| 281 |
-
|
| 282 |
# Keep the original function for backward compatibility
|
| 283 |
-
def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, strength_var, sport_var):
|
| 284 |
-
player_columns = [col for col in portfolio.columns[:5] if col not in ['salary', 'median', 'Own']]
|
| 285 |
if strength_var == 'Weak':
|
| 286 |
dupes_multiplier = .75
|
| 287 |
percentile_multiplier = .90
|
|
@@ -292,22 +117,22 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 292 |
dupes_multiplier = 1.25
|
| 293 |
percentile_multiplier = 1.10
|
| 294 |
max_ownership = max(maps_dict['own_map'].values()) / 100
|
| 295 |
-
top_x_ownership_keys = heapq.nlargest(len(player_columns), maps_dict['own_map'], key=maps_dict['own_map'].get)
|
| 296 |
average_ownership = np.mean(list(maps_dict['own_map'].values())) / 100
|
| 297 |
if site_var == 'Fanduel':
|
| 298 |
if type_var == 'Showdown':
|
| 299 |
dup_count_columns = ['CPT_Own_percent_rank', 'FLEX1_Own_percent_rank', 'FLEX2_Own_percent_rank', 'FLEX3_Own_percent_rank', 'FLEX4_Own_percent_rank']
|
| 300 |
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own']
|
| 301 |
-
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', '
|
| 302 |
# Get the original player columns (first 5 columns excluding salary, median, Own)
|
| 303 |
player_columns = [col for col in portfolio.columns[:5] if col not in ['salary', 'median', 'Own']]
|
| 304 |
|
| 305 |
flex_ownerships = pd.concat([
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
|
| 309 |
-
|
| 310 |
-
|
|
|
|
| 311 |
flex_rank = flex_ownerships.rank(pct=True)
|
| 312 |
|
| 313 |
# Assign ranks back to individual columns using the same rank scale
|
|
@@ -325,31 +150,31 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 325 |
portfolio['FLEX4_Own'] = portfolio.iloc[:,4].map(maps_dict['own_map']).astype('float32') / 100
|
| 326 |
portfolio['FLEX5_Own'] = portfolio.iloc[:,5].map(maps_dict['own_map']).astype('float32') / 100
|
| 327 |
|
| 328 |
-
portfolio['own_product'] = (portfolio[own_columns].product(axis=1))
|
| 329 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 330 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 331 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
| 332 |
-
portfolio['own_rank_percentile'] = portfolio['Own'].rank(pct=True)
|
| 333 |
-
portfolio['top_x_presence'] = portfolio[player_columns].apply(
|
| 334 |
-
lambda row: sum(1 for player in row if player in top_x_ownership_keys), axis=1
|
| 335 |
-
)
|
| 336 |
|
| 337 |
# Calculate dupes formula
|
| 338 |
-
portfolio['dupes_calc'] = (portfolio['
|
| 339 |
-
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (
|
| 340 |
|
| 341 |
# Round and handle negative values
|
| 342 |
portfolio['Dupes'] = np.where(
|
| 343 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 344 |
0,
|
| 345 |
-
np.round(
|
| 346 |
)
|
| 347 |
-
|
| 348 |
elif type_var == 'Classic':
|
| 349 |
num_players = len([col for col in portfolio.columns if col not in ['salary', 'median', 'Own']])
|
| 350 |
dup_count_columns = [f'player_{i}_percent_rank' for i in range(1, num_players + 1)]
|
| 351 |
own_columns = [f'player_{i}_own' for i in range(1, num_players + 1)]
|
| 352 |
-
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', '
|
| 353 |
# Get the original player columns (first num_players columns excluding salary, median, Own)
|
| 354 |
player_columns = [col for col in portfolio.columns[:num_players] if col not in ['salary', 'median', 'Own']]
|
| 355 |
|
|
@@ -357,22 +182,23 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 357 |
portfolio[f'player_{i}_percent_rank'] = portfolio.iloc[:,i-1].map(maps_dict['own_percent_rank'])
|
| 358 |
portfolio[f'player_{i}_own'] = portfolio.iloc[:,i-1].map(maps_dict['own_map']).astype('float32') / 100
|
| 359 |
|
| 360 |
-
portfolio['own_product'] = (portfolio[own_columns].product(axis=1))
|
| 361 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 362 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 363 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
| 364 |
-
portfolio['own_rank_percentile'] = portfolio['Own'].rank(pct=True)
|
| 365 |
-
portfolio['top_x_presence'] = portfolio[player_columns].apply(
|
| 366 |
-
lambda row: sum(1 for player in row if player in top_x_ownership_keys), axis=1
|
| 367 |
-
)
|
| 368 |
|
| 369 |
-
portfolio['dupes_calc'] = (portfolio['
|
| 370 |
-
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (
|
| 371 |
# Round and handle negative values
|
| 372 |
portfolio['Dupes'] = np.where(
|
| 373 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 374 |
0,
|
| 375 |
-
np.round(
|
| 376 |
)
|
| 377 |
|
| 378 |
elif site_var == 'Draftkings':
|
|
@@ -383,7 +209,7 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 383 |
else:
|
| 384 |
dup_count_columns = ['CPT_Own_percent_rank', 'FLEX1_Own_percent_rank', 'FLEX2_Own_percent_rank', 'FLEX3_Own_percent_rank', 'FLEX4_Own_percent_rank', 'FLEX5_Own_percent_rank']
|
| 385 |
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own', 'FLEX5_Own']
|
| 386 |
-
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', '
|
| 387 |
# Get the original player columns (first 6 columns excluding salary, median, Own)
|
| 388 |
player_columns = [col for col in portfolio.columns[:6] if col not in ['salary', 'median', 'Own']]
|
| 389 |
if sport_var == 'GOLF':
|
|
@@ -435,30 +261,31 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 435 |
portfolio['FLEX4_Own'] = portfolio.iloc[:,4].map(maps_dict['own_map']).astype('float32') / 100
|
| 436 |
portfolio['FLEX5_Own'] = portfolio.iloc[:,5].map(maps_dict['own_map']).astype('float32') / 100
|
| 437 |
|
| 438 |
-
portfolio['own_product'] = (portfolio[own_columns].product(axis=1))
|
| 439 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 440 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 441 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
| 442 |
-
portfolio['own_rank_percentile'] = portfolio['Own'].rank(pct=True)
|
| 443 |
-
portfolio['top_x_presence'] = portfolio[player_columns].apply(
|
| 444 |
-
lambda row: sum(1 for player in row if player in top_x_ownership_keys), axis=1
|
| 445 |
-
)
|
| 446 |
|
| 447 |
# Calculate dupes formula
|
| 448 |
-
portfolio['dupes_calc'] = (portfolio['
|
| 449 |
-
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (
|
| 450 |
|
| 451 |
# Round and handle negative values
|
| 452 |
portfolio['Dupes'] = np.where(
|
| 453 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
0,
|
| 455 |
-
np.round(
|
| 456 |
)
|
| 457 |
elif type_var == 'Classic':
|
| 458 |
if sport_var == 'CS2':
|
| 459 |
dup_count_columns = ['CPT_Own_percent_rank', 'FLEX1_Own_percent_rank', 'FLEX2_Own_percent_rank', 'FLEX3_Own_percent_rank', 'FLEX4_Own_percent_rank', 'FLEX5_Own_percent_rank']
|
| 460 |
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own', 'FLEX5_Own']
|
| 461 |
-
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', '
|
| 462 |
# Get the original player columns (first 6 columns excluding salary, median, Own)
|
| 463 |
player_columns = [col for col in portfolio.columns[:6] if col not in ['salary', 'median', 'Own']]
|
| 464 |
|
|
@@ -486,29 +313,30 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 486 |
portfolio['FLEX4_Own'] = portfolio.iloc[:,4].map(maps_dict['own_map']).astype('float32') / 100
|
| 487 |
portfolio['FLEX5_Own'] = portfolio.iloc[:,5].map(maps_dict['own_map']).astype('float32') / 100
|
| 488 |
|
| 489 |
-
portfolio['own_product'] = (portfolio[own_columns].product(axis=1))
|
| 490 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 491 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 492 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
| 493 |
-
portfolio['own_rank_percentile'] = portfolio['Own'].rank(pct=True)
|
| 494 |
-
portfolio['top_x_presence'] = portfolio[player_columns].apply(
|
| 495 |
-
lambda row: sum(1 for player in row if player in top_x_ownership_keys), axis=1
|
| 496 |
-
)
|
| 497 |
|
| 498 |
# Calculate dupes formula
|
| 499 |
-
portfolio['dupes_calc'] = (portfolio['
|
| 500 |
-
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (
|
| 501 |
|
| 502 |
# Round and handle negative values
|
| 503 |
portfolio['Dupes'] = np.where(
|
| 504 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 505 |
0,
|
| 506 |
-
np.round(
|
| 507 |
)
|
| 508 |
if sport_var == 'LOL':
|
| 509 |
dup_count_columns = ['CPT_Own_percent_rank', 'TOP_Own_percent_rank', 'JNG_Own_percent_rank', 'MID_Own_percent_rank', 'ADC_Own_percent_rank', 'SUP_Own_percent_rank', 'Team_Own_percent_rank']
|
| 510 |
own_columns = ['CPT_Own', 'TOP_Own', 'JNG_Own', 'MID_Own', 'ADC_Own', 'SUP_Own', 'Team_Own']
|
| 511 |
-
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', '
|
| 512 |
# Get the original player columns (first 6 columns excluding salary, median, Own)
|
| 513 |
player_columns = [col for col in portfolio.columns[:7] if col not in ['salary', 'median', 'Own']]
|
| 514 |
|
|
@@ -539,30 +367,31 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 539 |
portfolio['SUP_Own'] = portfolio.iloc[:,5].map(maps_dict['own_map']).astype('float32') / 100
|
| 540 |
portfolio['Team_Own'] = portfolio.iloc[:,6].map(maps_dict['own_map']).astype('float32') / 100
|
| 541 |
|
| 542 |
-
portfolio['own_product'] = (portfolio[own_columns].product(axis=1))
|
| 543 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 544 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 545 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
| 546 |
-
|
| 547 |
-
portfolio['top_x_presence'] = portfolio[player_columns].apply(
|
| 548 |
-
lambda row: sum(1 for player in row if player in top_x_ownership_keys), axis=1
|
| 549 |
-
)
|
| 550 |
-
|
| 551 |
# Calculate dupes formula
|
| 552 |
-
portfolio['dupes_calc'] = (portfolio['
|
| 553 |
-
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (
|
| 554 |
|
| 555 |
# Round and handle negative values
|
| 556 |
portfolio['Dupes'] = np.where(
|
| 557 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 558 |
0,
|
| 559 |
-
np.round(
|
| 560 |
)
|
| 561 |
-
elif sport_var
|
| 562 |
num_players = len([col for col in portfolio.columns if col not in ['salary', 'median', 'Own']])
|
| 563 |
dup_count_columns = [f'player_{i}_percent_rank' for i in range(1, num_players + 1)]
|
| 564 |
own_columns = [f'player_{i}_own' for i in range(1, num_players + 1)]
|
| 565 |
-
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', '
|
| 566 |
# Get the original player columns (first num_players columns excluding salary, median, Own)
|
| 567 |
player_columns = [col for col in portfolio.columns[:num_players] if col not in ['salary', 'median', 'Own']]
|
| 568 |
|
|
@@ -570,23 +399,55 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 570 |
portfolio[f'player_{i}_percent_rank'] = portfolio.iloc[:,i-1].map(maps_dict['own_percent_rank'])
|
| 571 |
portfolio[f'player_{i}_own'] = portfolio.iloc[:,i-1].map(maps_dict['own_map']).astype('float32') / 100
|
| 572 |
|
| 573 |
-
portfolio['own_product'] = (portfolio[own_columns].product(axis=1))
|
| 574 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 575 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 576 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
| 577 |
-
|
| 578 |
-
portfolio['
|
| 579 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 581 |
|
| 582 |
-
|
| 583 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 584 |
# Round and handle negative values
|
| 585 |
portfolio['Dupes'] = np.where(
|
| 586 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 587 |
0,
|
| 588 |
-
np.round(
|
| 589 |
)
|
|
|
|
| 590 |
|
| 591 |
portfolio['Dupes'] = np.round(portfolio['Dupes'], 0)
|
| 592 |
portfolio['own_ratio'] = np.where(
|
|
@@ -594,7 +455,7 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 594 |
portfolio['own_sum'] / portfolio['own_average'],
|
| 595 |
(portfolio['own_sum'] - max_ownership) / portfolio['own_average']
|
| 596 |
)
|
| 597 |
-
percentile_cut_scalar = portfolio['median'].max()
|
| 598 |
if type_var == 'Classic':
|
| 599 |
if sport_var == 'CS2':
|
| 600 |
own_ratio_nerf = 2
|
|
@@ -633,8 +494,6 @@ def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, streng
|
|
| 633 |
|
| 634 |
# Calculate similarity score based on actual player selection
|
| 635 |
portfolio['Diversity'] = calculate_player_similarity_score_vectorized(portfolio, player_columns)
|
| 636 |
-
|
| 637 |
-
st.table(portfolio.sort_values(by='Dupes', ascending=False).head(10))
|
| 638 |
|
| 639 |
portfolio = portfolio.drop(columns=dup_count_columns)
|
| 640 |
portfolio = portfolio.drop(columns=own_columns)
|
|
|
|
| 4 |
import time
|
| 5 |
import math
|
| 6 |
from difflib import SequenceMatcher
|
|
|
|
| 7 |
|
| 8 |
def calculate_weighted_ownership_vectorized(ownership_array):
|
| 9 |
"""
|
|
|
|
| 105 |
|
| 106 |
return similarity_scores
|
| 107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
# Keep the original function for backward compatibility
|
| 109 |
+
def predict_dupes(portfolio, maps_dict, site_var, type_var, Contest_Size, strength_var, sport_var, max_salary):
|
|
|
|
| 110 |
if strength_var == 'Weak':
|
| 111 |
dupes_multiplier = .75
|
| 112 |
percentile_multiplier = .90
|
|
|
|
| 117 |
dupes_multiplier = 1.25
|
| 118 |
percentile_multiplier = 1.10
|
| 119 |
max_ownership = max(maps_dict['own_map'].values()) / 100
|
|
|
|
| 120 |
average_ownership = np.mean(list(maps_dict['own_map'].values())) / 100
|
| 121 |
if site_var == 'Fanduel':
|
| 122 |
if type_var == 'Showdown':
|
| 123 |
dup_count_columns = ['CPT_Own_percent_rank', 'FLEX1_Own_percent_rank', 'FLEX2_Own_percent_rank', 'FLEX3_Own_percent_rank', 'FLEX4_Own_percent_rank']
|
| 124 |
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own']
|
| 125 |
+
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', 'dupes_calc', 'low_own_count', 'own_ratio', 'Ref_Proj', 'Max_Proj', 'Min_Proj', 'Avg_Ref', 'own_ratio']
|
| 126 |
# Get the original player columns (first 5 columns excluding salary, median, Own)
|
| 127 |
player_columns = [col for col in portfolio.columns[:5] if col not in ['salary', 'median', 'Own']]
|
| 128 |
|
| 129 |
flex_ownerships = pd.concat([
|
| 130 |
+
portfolio.iloc[:,1].map(maps_dict['own_map']),
|
| 131 |
+
portfolio.iloc[:,2].map(maps_dict['own_map']),
|
| 132 |
+
portfolio.iloc[:,3].map(maps_dict['own_map']),
|
| 133 |
+
portfolio.iloc[:,4].map(maps_dict['own_map']),
|
| 134 |
+
portfolio.iloc[:,5].map(maps_dict['own_map'])
|
| 135 |
+
])
|
| 136 |
flex_rank = flex_ownerships.rank(pct=True)
|
| 137 |
|
| 138 |
# Assign ranks back to individual columns using the same rank scale
|
|
|
|
| 150 |
portfolio['FLEX4_Own'] = portfolio.iloc[:,4].map(maps_dict['own_map']).astype('float32') / 100
|
| 151 |
portfolio['FLEX5_Own'] = portfolio.iloc[:,5].map(maps_dict['own_map']).astype('float32') / 100
|
| 152 |
|
| 153 |
+
portfolio['own_product'] = (portfolio[own_columns].product(axis=1)) * max(Contest_Size / 10000, 1)
|
| 154 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 155 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 156 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
|
| 158 |
# Calculate dupes formula
|
| 159 |
+
portfolio['dupes_calc'] = (portfolio['own_product'] * portfolio['avg_own_rank']) * (portfolio['Own'] / 100) * Contest_Size + ((portfolio['salary'] - (max_salary - portfolio['Own'])) / 100) - ((max_salary - portfolio['salary']) / 100)
|
| 160 |
+
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (90 + (Contest_Size / 1000)))
|
| 161 |
|
| 162 |
# Round and handle negative values
|
| 163 |
portfolio['Dupes'] = np.where(
|
| 164 |
+
portfolio['salary'] == max_salary,
|
| 165 |
+
portfolio['dupes_calc'] + (portfolio['dupes_calc'] * .10),
|
| 166 |
+
portfolio['dupes_calc']
|
| 167 |
+
)
|
| 168 |
+
portfolio['Dupes'] = np.where(
|
| 169 |
+
np.round(portfolio['Dupes'], 0) <= 0,
|
| 170 |
0,
|
| 171 |
+
np.round(portfolio['Dupes'], 0) - 1
|
| 172 |
)
|
|
|
|
| 173 |
elif type_var == 'Classic':
|
| 174 |
num_players = len([col for col in portfolio.columns if col not in ['salary', 'median', 'Own']])
|
| 175 |
dup_count_columns = [f'player_{i}_percent_rank' for i in range(1, num_players + 1)]
|
| 176 |
own_columns = [f'player_{i}_own' for i in range(1, num_players + 1)]
|
| 177 |
+
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', 'dupes_calc', 'low_own_count', 'own_ratio', 'Ref_Proj', 'Max_Proj', 'Min_Proj', 'Avg_Ref', 'own_ratio']
|
| 178 |
# Get the original player columns (first num_players columns excluding salary, median, Own)
|
| 179 |
player_columns = [col for col in portfolio.columns[:num_players] if col not in ['salary', 'median', 'Own']]
|
| 180 |
|
|
|
|
| 182 |
portfolio[f'player_{i}_percent_rank'] = portfolio.iloc[:,i-1].map(maps_dict['own_percent_rank'])
|
| 183 |
portfolio[f'player_{i}_own'] = portfolio.iloc[:,i-1].map(maps_dict['own_map']).astype('float32') / 100
|
| 184 |
|
| 185 |
+
portfolio['own_product'] = (portfolio[own_columns].product(axis=1)) * max(Contest_Size / 10000, 1)
|
| 186 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 187 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 188 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 189 |
|
| 190 |
+
portfolio['dupes_calc'] = (portfolio['own_product'] * portfolio['avg_own_rank']) * Contest_Size + ((portfolio['salary'] - (max_salary - portfolio['Own'])) / 100) - ((max_salary - portfolio['salary']) / 100)
|
| 191 |
+
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (90 + (Contest_Size / 1000)))
|
| 192 |
# Round and handle negative values
|
| 193 |
portfolio['Dupes'] = np.where(
|
| 194 |
+
portfolio['salary'] == max_salary,
|
| 195 |
+
portfolio['dupes_calc'] + (portfolio['dupes_calc'] * .10),
|
| 196 |
+
portfolio['dupes_calc']
|
| 197 |
+
)
|
| 198 |
+
portfolio['Dupes'] = np.where(
|
| 199 |
+
np.round(portfolio['Dupes'], 0) <= 0,
|
| 200 |
0,
|
| 201 |
+
np.round(portfolio['Dupes'], 0) - 1
|
| 202 |
)
|
| 203 |
|
| 204 |
elif site_var == 'Draftkings':
|
|
|
|
| 209 |
else:
|
| 210 |
dup_count_columns = ['CPT_Own_percent_rank', 'FLEX1_Own_percent_rank', 'FLEX2_Own_percent_rank', 'FLEX3_Own_percent_rank', 'FLEX4_Own_percent_rank', 'FLEX5_Own_percent_rank']
|
| 211 |
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own', 'FLEX5_Own']
|
| 212 |
+
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', 'dupes_calc', 'low_own_count', 'Ref_Proj', 'Max_Proj', 'Min_Proj', 'Avg_Ref', 'own_ratio']
|
| 213 |
# Get the original player columns (first 6 columns excluding salary, median, Own)
|
| 214 |
player_columns = [col for col in portfolio.columns[:6] if col not in ['salary', 'median', 'Own']]
|
| 215 |
if sport_var == 'GOLF':
|
|
|
|
| 261 |
portfolio['FLEX4_Own'] = portfolio.iloc[:,4].map(maps_dict['own_map']).astype('float32') / 100
|
| 262 |
portfolio['FLEX5_Own'] = portfolio.iloc[:,5].map(maps_dict['own_map']).astype('float32') / 100
|
| 263 |
|
| 264 |
+
portfolio['own_product'] = (portfolio[own_columns].product(axis=1)) * max(Contest_Size / 10000, 1)
|
| 265 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 266 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 267 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
|
| 269 |
# Calculate dupes formula
|
| 270 |
+
portfolio['dupes_calc'] = (portfolio['own_product'] * portfolio['avg_own_rank']) * Contest_Size + ((portfolio['salary'] - (max_salary - portfolio['Own'])) / 100) - ((max_salary - portfolio['salary']) / 100)
|
| 271 |
+
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (90 + (Contest_Size / 1000)))
|
| 272 |
|
| 273 |
# Round and handle negative values
|
| 274 |
portfolio['Dupes'] = np.where(
|
| 275 |
+
portfolio['salary'] == max_salary,
|
| 276 |
+
portfolio['dupes_calc'] + (portfolio['dupes_calc'] * .10),
|
| 277 |
+
portfolio['dupes_calc']
|
| 278 |
+
)
|
| 279 |
+
portfolio['Dupes'] = np.where(
|
| 280 |
+
np.round(portfolio['Dupes'], 0) <= 0,
|
| 281 |
0,
|
| 282 |
+
np.round(portfolio['Dupes'], 0) - 1
|
| 283 |
)
|
| 284 |
elif type_var == 'Classic':
|
| 285 |
if sport_var == 'CS2':
|
| 286 |
dup_count_columns = ['CPT_Own_percent_rank', 'FLEX1_Own_percent_rank', 'FLEX2_Own_percent_rank', 'FLEX3_Own_percent_rank', 'FLEX4_Own_percent_rank', 'FLEX5_Own_percent_rank']
|
| 287 |
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own', 'FLEX5_Own']
|
| 288 |
+
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', 'dupes_calc', 'low_own_count', 'Ref_Proj', 'Max_Proj', 'Min_Proj', 'Avg_Ref', 'own_ratio']
|
| 289 |
# Get the original player columns (first 6 columns excluding salary, median, Own)
|
| 290 |
player_columns = [col for col in portfolio.columns[:6] if col not in ['salary', 'median', 'Own']]
|
| 291 |
|
|
|
|
| 313 |
portfolio['FLEX4_Own'] = portfolio.iloc[:,4].map(maps_dict['own_map']).astype('float32') / 100
|
| 314 |
portfolio['FLEX5_Own'] = portfolio.iloc[:,5].map(maps_dict['own_map']).astype('float32') / 100
|
| 315 |
|
| 316 |
+
portfolio['own_product'] = (portfolio[own_columns].product(axis=1)) * max(Contest_Size / 10000, 1)
|
| 317 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 318 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 319 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
|
| 321 |
# Calculate dupes formula
|
| 322 |
+
portfolio['dupes_calc'] = ((portfolio['own_product'] * 10) * portfolio['avg_own_rank']) * Contest_Size + ((portfolio['salary'] - (max_salary - portfolio['Own'])) / 50) - ((max_salary - portfolio['salary']) / 50)
|
| 323 |
+
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (90 + (Contest_Size / 1000)))
|
| 324 |
|
| 325 |
# Round and handle negative values
|
| 326 |
portfolio['Dupes'] = np.where(
|
| 327 |
+
portfolio['salary'] == max_salary,
|
| 328 |
+
portfolio['dupes_calc'] + (portfolio['dupes_calc'] * .10),
|
| 329 |
+
portfolio['dupes_calc']
|
| 330 |
+
)
|
| 331 |
+
portfolio['Dupes'] = np.where(
|
| 332 |
+
np.round(portfolio['Dupes'], 0) <= 0,
|
| 333 |
0,
|
| 334 |
+
np.round(portfolio['Dupes'], 0) - 1
|
| 335 |
)
|
| 336 |
if sport_var == 'LOL':
|
| 337 |
dup_count_columns = ['CPT_Own_percent_rank', 'TOP_Own_percent_rank', 'JNG_Own_percent_rank', 'MID_Own_percent_rank', 'ADC_Own_percent_rank', 'SUP_Own_percent_rank', 'Team_Own_percent_rank']
|
| 338 |
own_columns = ['CPT_Own', 'TOP_Own', 'JNG_Own', 'MID_Own', 'ADC_Own', 'SUP_Own', 'Team_Own']
|
| 339 |
+
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', 'dupes_calc', 'low_own_count', 'Ref_Proj', 'Max_Proj', 'Min_Proj', 'Avg_Ref', 'own_ratio']
|
| 340 |
# Get the original player columns (first 6 columns excluding salary, median, Own)
|
| 341 |
player_columns = [col for col in portfolio.columns[:7] if col not in ['salary', 'median', 'Own']]
|
| 342 |
|
|
|
|
| 367 |
portfolio['SUP_Own'] = portfolio.iloc[:,5].map(maps_dict['own_map']).astype('float32') / 100
|
| 368 |
portfolio['Team_Own'] = portfolio.iloc[:,6].map(maps_dict['own_map']).astype('float32') / 100
|
| 369 |
|
| 370 |
+
portfolio['own_product'] = (portfolio[own_columns].product(axis=1)) * max(Contest_Size / 10000, 1)
|
| 371 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 372 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 373 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
| 374 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
| 375 |
# Calculate dupes formula
|
| 376 |
+
portfolio['dupes_calc'] = ((portfolio['own_product'] * 10) * portfolio['avg_own_rank']) * Contest_Size + ((portfolio['salary'] - (max_salary - portfolio['Own'])) / 50) - ((max_salary - portfolio['salary']) / 50)
|
| 377 |
+
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (90 + (Contest_Size / 1000)))
|
| 378 |
|
| 379 |
# Round and handle negative values
|
| 380 |
portfolio['Dupes'] = np.where(
|
| 381 |
+
portfolio['salary'] == max_salary,
|
| 382 |
+
portfolio['dupes_calc'] + (portfolio['dupes_calc'] * .10),
|
| 383 |
+
portfolio['dupes_calc']
|
| 384 |
+
)
|
| 385 |
+
portfolio['Dupes'] = np.where(
|
| 386 |
+
np.round(portfolio['Dupes'], 0) <= 0,
|
| 387 |
0,
|
| 388 |
+
np.round(portfolio['Dupes'], 0) - 1
|
| 389 |
)
|
| 390 |
+
elif sport_var == 'GOLF':
|
| 391 |
num_players = len([col for col in portfolio.columns if col not in ['salary', 'median', 'Own']])
|
| 392 |
dup_count_columns = [f'player_{i}_percent_rank' for i in range(1, num_players + 1)]
|
| 393 |
own_columns = [f'player_{i}_own' for i in range(1, num_players + 1)]
|
| 394 |
+
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', 'dupes_calc', 'low_own_count', 'Ref_Proj', 'Max_Proj', 'Min_Proj', 'Avg_Ref', 'own_ratio']
|
| 395 |
# Get the original player columns (first num_players columns excluding salary, median, Own)
|
| 396 |
player_columns = [col for col in portfolio.columns[:num_players] if col not in ['salary', 'median', 'Own']]
|
| 397 |
|
|
|
|
| 399 |
portfolio[f'player_{i}_percent_rank'] = portfolio.iloc[:,i-1].map(maps_dict['own_percent_rank'])
|
| 400 |
portfolio[f'player_{i}_own'] = portfolio.iloc[:,i-1].map(maps_dict['own_map']).astype('float32') / 100
|
| 401 |
|
| 402 |
+
portfolio['own_product'] = (portfolio[own_columns].product(axis=1)) * max(Contest_Size / 10000, 1)
|
| 403 |
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 404 |
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 405 |
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
| 406 |
+
|
| 407 |
+
portfolio['dupes_calc'] = (portfolio['own_product'] * portfolio['avg_own_rank']) * Contest_Size + ((portfolio['salary'] - (max_salary - portfolio['Own'])) / 100) - ((max_salary - portfolio['salary']) / 100)
|
| 408 |
+
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (90 + (Contest_Size / 1000)))
|
| 409 |
+
# Round and handle negative values
|
| 410 |
+
portfolio['Dupes'] = np.where(
|
| 411 |
+
portfolio['salary'] == max_salary,
|
| 412 |
+
portfolio['dupes_calc'] + (portfolio['dupes_calc'] * .10),
|
| 413 |
+
portfolio['dupes_calc']
|
| 414 |
)
|
| 415 |
+
portfolio['Dupes'] = np.where(
|
| 416 |
+
np.round(portfolio['Dupes'], 0) <= 0,
|
| 417 |
+
0,
|
| 418 |
+
np.round(portfolio['Dupes'], 0) - 1
|
| 419 |
+
)
|
| 420 |
+
else:
|
| 421 |
+
num_players = len([col for col in portfolio.columns if col not in ['salary', 'median', 'Own']])
|
| 422 |
+
dup_count_columns = [f'player_{i}_percent_rank' for i in range(1, num_players + 1)]
|
| 423 |
+
own_columns = [f'player_{i}_own' for i in range(1, num_players + 1)]
|
| 424 |
+
calc_columns = ['own_product', 'own_average', 'own_sum', 'avg_own_rank', 'dupes_calc', 'low_own_count', 'Ref_Proj', 'Max_Proj', 'Min_Proj', 'Avg_Ref', 'own_ratio']
|
| 425 |
+
# Get the original player columns (first num_players columns excluding salary, median, Own)
|
| 426 |
+
player_columns = [col for col in portfolio.columns[:num_players] if col not in ['salary', 'median', 'Own']]
|
| 427 |
|
| 428 |
+
for i in range(1, num_players + 1):
|
| 429 |
+
portfolio[f'player_{i}_percent_rank'] = portfolio.iloc[:,i-1].map(maps_dict['own_percent_rank'])
|
| 430 |
+
portfolio[f'player_{i}_own'] = portfolio.iloc[:,i-1].map(maps_dict['own_map']).astype('float32') / 100
|
| 431 |
+
|
| 432 |
+
portfolio['own_product'] = (portfolio[own_columns].product(axis=1)) * max(Contest_Size / 10000, 1)
|
| 433 |
+
portfolio['own_average'] = (portfolio['Own'].max() * .33) / 100
|
| 434 |
+
portfolio['own_sum'] = portfolio[own_columns].sum(axis=1)
|
| 435 |
+
portfolio['avg_own_rank'] = portfolio[dup_count_columns].mean(axis=1)
|
| 436 |
+
|
| 437 |
+
portfolio['dupes_calc'] = (portfolio['own_product'] * portfolio['avg_own_rank']) * Contest_Size + ((portfolio['salary'] - (max_salary - portfolio['Own'])) / 100) - ((max_salary - portfolio['salary']) / 100)
|
| 438 |
+
portfolio['dupes_calc'] = portfolio['dupes_calc'] * dupes_multiplier * (portfolio['Own'] / (90 + (Contest_Size / 1000)))
|
| 439 |
# Round and handle negative values
|
| 440 |
portfolio['Dupes'] = np.where(
|
| 441 |
+
portfolio['salary'] == max_salary,
|
| 442 |
+
portfolio['dupes_calc'] + (portfolio['dupes_calc'] * .10),
|
| 443 |
+
portfolio['dupes_calc']
|
| 444 |
+
)
|
| 445 |
+
portfolio['Dupes'] = np.where(
|
| 446 |
+
np.round(portfolio['Dupes'], 0) <= 0,
|
| 447 |
0,
|
| 448 |
+
np.round(portfolio['Dupes'], 0) - 1
|
| 449 |
)
|
| 450 |
+
|
| 451 |
|
| 452 |
portfolio['Dupes'] = np.round(portfolio['Dupes'], 0)
|
| 453 |
portfolio['own_ratio'] = np.where(
|
|
|
|
| 455 |
portfolio['own_sum'] / portfolio['own_average'],
|
| 456 |
(portfolio['own_sum'] - max_ownership) / portfolio['own_average']
|
| 457 |
)
|
| 458 |
+
percentile_cut_scalar = portfolio['median'].max() # Get scalar value
|
| 459 |
if type_var == 'Classic':
|
| 460 |
if sport_var == 'CS2':
|
| 461 |
own_ratio_nerf = 2
|
|
|
|
| 494 |
|
| 495 |
# Calculate similarity score based on actual player selection
|
| 496 |
portfolio['Diversity'] = calculate_player_similarity_score_vectorized(portfolio, player_columns)
|
|
|
|
|
|
|
| 497 |
|
| 498 |
portfolio = portfolio.drop(columns=dup_count_columns)
|
| 499 |
portfolio = portfolio.drop(columns=own_columns)
|