James McCool
commited on
Commit
·
ceb1f25
1
Parent(s):
2b28c7d
Implement comprehensive contest simulation functionality with dynamic sport, site, and slate selection
Browse files
app.py
CHANGED
@@ -281,6 +281,389 @@ except:
|
|
281 |
dk_raw, fd_raw = init_baselines('NBA')
|
282 |
|
283 |
tab1, tab2 = st.tabs(['Contest Sims', 'Data Export'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
284 |
with tab2:
|
285 |
with st.expander("Info and Filters"):
|
286 |
if st.button("Load/Reset Data", key='reset1'):
|
@@ -440,389 +823,4 @@ with tab2:
|
|
440 |
|
441 |
with st.container():
|
442 |
if 'data_export_display' in st.session_state:
|
443 |
-
st.dataframe(st.session_state.data_export_display.style.format(freq_format, precision=2), use_container_width = True)
|
444 |
-
|
445 |
-
with tab1:
|
446 |
-
col1, col2 = st.columns([1, 7])
|
447 |
-
with col1:
|
448 |
-
if st.button("Load/Reset Data", key='reset2'):
|
449 |
-
st.cache_data.clear()
|
450 |
-
for key in st.session_state.keys():
|
451 |
-
del st.session_state[key]
|
452 |
-
dk_raw, fd_raw = init_baselines('NFL')
|
453 |
-
sim_sport_var1 = st.radio("What sport are you working with?", ('NBA', 'NFL'), key='sim_sport_var1')
|
454 |
-
dk_raw, fd_raw = init_baselines(sim_sport_var1)
|
455 |
-
sim_slate_var1 = st.radio("Which data are you loading?", ('Showdown', 'Secondary Showdown', 'Auxiliary Showdown'), key='sim_slate_var1')
|
456 |
-
sim_site_var1 = st.radio("What site are you working with?", ('Draftkings', 'Fanduel'), key='sim_site_var1')
|
457 |
-
if sim_site_var1 == 'Draftkings':
|
458 |
-
raw_baselines = dk_raw
|
459 |
-
column_names = dk_columns
|
460 |
-
elif sim_site_var1 == 'Fanduel':
|
461 |
-
raw_baselines = fd_raw
|
462 |
-
column_names = fd_columns
|
463 |
-
contest_var1 = st.selectbox("What contest size are you simulating?", ('Small', 'Medium', 'Large', 'Custom'))
|
464 |
-
if contest_var1 == 'Small':
|
465 |
-
Contest_Size = 1000
|
466 |
-
st.write("Small field size is 1,000 entrants.")
|
467 |
-
raw_baselines['Own'] = raw_baselines['Small_Field_Own']
|
468 |
-
raw_baselines['CPT_Own'] = raw_baselines['small_CPT_Own']
|
469 |
-
elif contest_var1 == 'Medium':
|
470 |
-
Contest_Size = 5000
|
471 |
-
st.write("Medium field size is 5,000 entrants.")
|
472 |
-
elif contest_var1 == 'Large':
|
473 |
-
Contest_Size = 10000
|
474 |
-
st.write("Large field size is 10,000 entrants.")
|
475 |
-
elif contest_var1 == 'Custom':
|
476 |
-
Contest_Size = st.number_input("Insert contest size", value=100, min_value=1, max_value=100000)
|
477 |
-
strength_var1 = st.selectbox("How sharp is the field in the contest?", ('Very', 'Above Average', 'Average', 'Below Average', 'Not Very'))
|
478 |
-
if strength_var1 == 'Not Very':
|
479 |
-
sharp_split = 500000
|
480 |
-
elif strength_var1 == 'Below Average':
|
481 |
-
sharp_split = 400000
|
482 |
-
elif strength_var1 == 'Average':
|
483 |
-
sharp_split = 300000
|
484 |
-
elif strength_var1 == 'Above Average':
|
485 |
-
sharp_split = 200000
|
486 |
-
elif strength_var1 == 'Very':
|
487 |
-
sharp_split = 100000
|
488 |
-
|
489 |
-
|
490 |
-
with col2:
|
491 |
-
if st.button("Run Contest Sim"):
|
492 |
-
if 'working_seed' in st.session_state:
|
493 |
-
maps_dict = {
|
494 |
-
'Projection_map':dict(zip(raw_baselines.Player,raw_baselines.Median)),
|
495 |
-
'cpt_projection_map':dict(zip(raw_baselines.Player,raw_baselines.cpt_Median)),
|
496 |
-
'Salary_map':dict(zip(raw_baselines.Player,raw_baselines.Salary)),
|
497 |
-
'Pos_map':dict(zip(raw_baselines.Player,raw_baselines.Position)),
|
498 |
-
'Own_map':dict(zip(raw_baselines.Player,raw_baselines['Own'])),
|
499 |
-
'cpt_Own_map':dict(zip(raw_baselines.Player,raw_baselines['CPT_Own'])),
|
500 |
-
'Team_map':dict(zip(raw_baselines.Player,raw_baselines.Team)),
|
501 |
-
'STDev_map':dict(zip(raw_baselines.Player,raw_baselines.STDev)),
|
502 |
-
'cpt_STDev_map':dict(zip(raw_baselines.Player,raw_baselines['CPT_STDev']))
|
503 |
-
}
|
504 |
-
Sim_Winners = sim_contest(1000, st.session_state.working_seed, maps_dict, Contest_Size)
|
505 |
-
Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners))
|
506 |
-
|
507 |
-
#st.table(Sim_Winner_Frame)
|
508 |
-
|
509 |
-
# Initial setup
|
510 |
-
Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners), columns=column_names + ['Fantasy'])
|
511 |
-
Sim_Winner_Frame['GPP_Proj'] = (Sim_Winner_Frame['proj'] + Sim_Winner_Frame['Fantasy']) / 2
|
512 |
-
Sim_Winner_Frame['unique_id'] = Sim_Winner_Frame['proj'].astype(str) + Sim_Winner_Frame['salary'].astype(str) + Sim_Winner_Frame['Team'].astype(str) + Sim_Winner_Frame['Secondary'].astype(str)
|
513 |
-
Sim_Winner_Frame = Sim_Winner_Frame.assign(win_count=Sim_Winner_Frame['unique_id'].map(Sim_Winner_Frame['unique_id'].value_counts()))
|
514 |
-
|
515 |
-
# Type Casting
|
516 |
-
type_cast_dict = {'salary': int, 'proj': np.float16, 'Fantasy': np.float16, 'GPP_Proj': np.float32, 'Own': np.float32}
|
517 |
-
Sim_Winner_Frame = Sim_Winner_Frame.astype(type_cast_dict)
|
518 |
-
|
519 |
-
# Sorting
|
520 |
-
st.session_state.Sim_Winner_Frame = Sim_Winner_Frame.sort_values(by=['win_count', 'GPP_Proj'], ascending= [False, False]).copy().drop_duplicates(subset='unique_id').head(100)
|
521 |
-
st.session_state.Sim_Winner_Frame.drop(columns='unique_id', inplace=True)
|
522 |
-
|
523 |
-
# Data Copying
|
524 |
-
st.session_state.Sim_Winner_Export = Sim_Winner_Frame.copy()
|
525 |
-
|
526 |
-
# Data Copying
|
527 |
-
st.session_state.Sim_Winner_Display = Sim_Winner_Frame.copy()
|
528 |
-
|
529 |
-
else:
|
530 |
-
if sim_site_var1 == 'Draftkings':
|
531 |
-
if sim_slate_var1 == 'Showdown':
|
532 |
-
st.session_state.working_seed = init_DK_seed_frames(sim_sport_var1, sharp_split_var)
|
533 |
-
if sport_var1 == 'NFL':
|
534 |
-
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
535 |
-
elif sport_var1 == 'NBA':
|
536 |
-
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
537 |
-
elif sim_slate_var1 == 'Secondary Showdown':
|
538 |
-
st.session_state.working_seed = init_DK_secondary_seed_frames(sim_sport_var1, sharp_split_var)
|
539 |
-
if sport_var1 == 'NFL':
|
540 |
-
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
541 |
-
elif sport_var1 == 'NBA':
|
542 |
-
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
543 |
-
elif sim_slate_var1 == 'Auxiliary Showdown':
|
544 |
-
st.session_state.working_seed = init_DK_auxiliary_seed_frames(sim_sport_var1, sharp_split_var)
|
545 |
-
if sport_var1 == 'NFL':
|
546 |
-
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
547 |
-
elif sport_var1 == 'NBA':
|
548 |
-
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
549 |
-
raw_baselines = dk_raw
|
550 |
-
column_names = dk_columns
|
551 |
-
elif sim_site_var1 == 'Fanduel':
|
552 |
-
if sim_slate_var1 == 'Showdown':
|
553 |
-
st.session_state.working_seed = init_FD_seed_frames(sim_sport_var1, sharp_split_var)
|
554 |
-
if sport_var1 == 'NFL':
|
555 |
-
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
556 |
-
elif sport_var1 == 'NBA':
|
557 |
-
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
558 |
-
elif sim_slate_var1 == 'Secondary Showdown':
|
559 |
-
st.session_state.working_seed = init_FD_secondary_seed_frames(sim_sport_var1, sharp_split_var)
|
560 |
-
if sport_var1 == 'NFL':
|
561 |
-
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
562 |
-
elif sport_var1 == 'NBA':
|
563 |
-
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
564 |
-
elif sim_slate_var1 == 'Auxiliary Showdown':
|
565 |
-
st.session_state.working_seed = init_FD_auxiliary_seed_frames(sim_sport_var1, sharp_split_var)
|
566 |
-
if sport_var1 == 'NFL':
|
567 |
-
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
568 |
-
elif sport_var1 == 'NBA':
|
569 |
-
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
570 |
-
raw_baselines = fd_raw
|
571 |
-
column_names = fd_columns
|
572 |
-
maps_dict = {
|
573 |
-
'Projection_map':dict(zip(raw_baselines.Player,raw_baselines.Median)),
|
574 |
-
'cpt_projection_map':dict(zip(raw_baselines.Player,raw_baselines.cpt_Median)),
|
575 |
-
'Salary_map':dict(zip(raw_baselines.Player,raw_baselines.Salary)),
|
576 |
-
'Pos_map':dict(zip(raw_baselines.Player,raw_baselines.Position)),
|
577 |
-
'Own_map':dict(zip(raw_baselines.Player,raw_baselines['Own'])),
|
578 |
-
'cpt_Own_map':dict(zip(raw_baselines.Player,raw_baselines['CPT_Own'])),
|
579 |
-
'Team_map':dict(zip(raw_baselines.Player,raw_baselines.Team)),
|
580 |
-
'STDev_map':dict(zip(raw_baselines.Player,raw_baselines.STDev)),
|
581 |
-
'cpt_STDev_map':dict(zip(raw_baselines.Player,raw_baselines['CPT_STDev']))
|
582 |
-
}
|
583 |
-
Sim_Winners = sim_contest(1000, st.session_state.working_seed, maps_dict, Contest_Size)
|
584 |
-
Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners))
|
585 |
-
|
586 |
-
#st.table(Sim_Winner_Frame)
|
587 |
-
|
588 |
-
# Initial setup
|
589 |
-
Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners), columns=column_names + ['Fantasy'])
|
590 |
-
Sim_Winner_Frame['GPP_Proj'] = (Sim_Winner_Frame['proj'] + Sim_Winner_Frame['Fantasy']) / 2
|
591 |
-
Sim_Winner_Frame['unique_id'] = Sim_Winner_Frame['proj'].astype(str) + Sim_Winner_Frame['salary'].astype(str) + Sim_Winner_Frame['Team'].astype(str) + Sim_Winner_Frame['Secondary'].astype(str)
|
592 |
-
# Add percent rank columns for ownership at each roster position
|
593 |
-
# Calculate Dupes column for Fanduel
|
594 |
-
if sim_site_var1 == 'Fanduel':
|
595 |
-
dup_count_columns = ['CPT_Own_percent_rank', 'FLEX1_Own_percent_rank', 'FLEX2_Own_percent_rank', 'FLEX3_Own_percent_rank', 'FLEX4_Own_percent_rank']
|
596 |
-
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own']
|
597 |
-
calc_columns = ['own_product', 'avg_own_rank', 'dupes_calc']
|
598 |
-
Sim_Winner_Frame['CPT_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,0].map(maps_dict['cpt_Own_map']).rank(pct=True)
|
599 |
-
Sim_Winner_Frame['FLEX1_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,1].map(maps_dict['Own_map']).rank(pct=True)
|
600 |
-
Sim_Winner_Frame['FLEX2_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,2].map(maps_dict['Own_map']).rank(pct=True)
|
601 |
-
Sim_Winner_Frame['FLEX3_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,3].map(maps_dict['Own_map']).rank(pct=True)
|
602 |
-
Sim_Winner_Frame['FLEX4_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,4].map(maps_dict['Own_map']).rank(pct=True)
|
603 |
-
Sim_Winner_Frame['CPT_Own'] = Sim_Winner_Frame.iloc[:,0].map(maps_dict['cpt_Own_map']) / 100
|
604 |
-
Sim_Winner_Frame['FLEX1_Own'] = Sim_Winner_Frame.iloc[:,1].map(maps_dict['Own_map']) / 100
|
605 |
-
Sim_Winner_Frame['FLEX2_Own'] = Sim_Winner_Frame.iloc[:,2].map(maps_dict['Own_map']) / 100
|
606 |
-
Sim_Winner_Frame['FLEX3_Own'] = Sim_Winner_Frame.iloc[:,3].map(maps_dict['Own_map']) / 100
|
607 |
-
Sim_Winner_Frame['FLEX4_Own'] = Sim_Winner_Frame.iloc[:,4].map(maps_dict['Own_map']) / 100
|
608 |
-
|
609 |
-
# Calculate ownership product and convert to probability
|
610 |
-
Sim_Winner_Frame['own_product'] = (Sim_Winner_Frame[own_columns].product(axis=1)) + 0.0001
|
611 |
-
|
612 |
-
# Calculate average of ownership percent rank columns
|
613 |
-
Sim_Winner_Frame['avg_own_rank'] = Sim_Winner_Frame[dup_count_columns].mean(axis=1)
|
614 |
-
|
615 |
-
# Calculate dupes formula
|
616 |
-
Sim_Winner_Frame['dupes_calc'] = ((Sim_Winner_Frame['own_product'] * Sim_Winner_Frame['avg_own_rank']) * (Contest_Size * 1.5)) + ((Sim_Winner_Frame['salary'] - 59800) / 100)
|
617 |
-
|
618 |
-
# Round and handle negative values
|
619 |
-
Sim_Winner_Frame['Dupes'] = np.where(
|
620 |
-
np.round(Sim_Winner_Frame['dupes_calc'], 0) <= 0,
|
621 |
-
0,
|
622 |
-
np.round(Sim_Winner_Frame['dupes_calc'], 0) - 1
|
623 |
-
)
|
624 |
-
Sim_Winner_Frame['Dupes'] = (Sim_Winner_Frame['Dupes'] * (500000 / sharp_split)) / 2
|
625 |
-
elif sim_site_var1 == 'Draftkings':
|
626 |
-
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']
|
627 |
-
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own', 'FLEX5_Own']
|
628 |
-
calc_columns = ['own_product', 'avg_own_rank', 'dupes_calc']
|
629 |
-
Sim_Winner_Frame['CPT_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,0].map(maps_dict['cpt_Own_map']).rank(pct=True)
|
630 |
-
Sim_Winner_Frame['FLEX1_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,1].map(maps_dict['Own_map']).rank(pct=True)
|
631 |
-
Sim_Winner_Frame['FLEX2_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,2].map(maps_dict['Own_map']).rank(pct=True)
|
632 |
-
Sim_Winner_Frame['FLEX3_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,3].map(maps_dict['Own_map']).rank(pct=True)
|
633 |
-
Sim_Winner_Frame['FLEX4_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,4].map(maps_dict['Own_map']).rank(pct=True)
|
634 |
-
Sim_Winner_Frame['FLEX5_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,5].map(maps_dict['Own_map']).rank(pct=True)
|
635 |
-
Sim_Winner_Frame['CPT_Own'] = Sim_Winner_Frame.iloc[:,0].map(maps_dict['cpt_Own_map']) / 100
|
636 |
-
Sim_Winner_Frame['FLEX1_Own'] = Sim_Winner_Frame.iloc[:,1].map(maps_dict['Own_map']) / 100
|
637 |
-
Sim_Winner_Frame['FLEX2_Own'] = Sim_Winner_Frame.iloc[:,2].map(maps_dict['Own_map']) / 100
|
638 |
-
Sim_Winner_Frame['FLEX3_Own'] = Sim_Winner_Frame.iloc[:,3].map(maps_dict['Own_map']) / 100
|
639 |
-
Sim_Winner_Frame['FLEX4_Own'] = Sim_Winner_Frame.iloc[:,4].map(maps_dict['Own_map']) / 100
|
640 |
-
Sim_Winner_Frame['FLEX5_Own'] = Sim_Winner_Frame.iloc[:,5].map(maps_dict['Own_map']) / 100
|
641 |
-
|
642 |
-
# Calculate ownership product and convert to probability
|
643 |
-
Sim_Winner_Frame['own_product'] = (Sim_Winner_Frame[own_columns].product(axis=1))
|
644 |
-
|
645 |
-
# Calculate average of ownership percent rank columns
|
646 |
-
Sim_Winner_Frame['avg_own_rank'] = Sim_Winner_Frame[dup_count_columns].mean(axis=1)
|
647 |
-
|
648 |
-
# Calculate dupes formula
|
649 |
-
Sim_Winner_Frame['dupes_calc'] = ((Sim_Winner_Frame['own_product'] * Sim_Winner_Frame['avg_own_rank']) * (Contest_Size * 1.5)) + ((Sim_Winner_Frame['salary'] - 49800) / 100)
|
650 |
-
|
651 |
-
# Round and handle negative values
|
652 |
-
Sim_Winner_Frame['Dupes'] = np.where(
|
653 |
-
np.round(Sim_Winner_Frame['dupes_calc'], 0) <= 0,
|
654 |
-
0,
|
655 |
-
np.round(Sim_Winner_Frame['dupes_calc'], 0) - 1
|
656 |
-
)
|
657 |
-
Sim_Winner_Frame['Dupes'] = (Sim_Winner_Frame['Dupes'] * (500000 / sharp_split)) / 2
|
658 |
-
Sim_Winner_Frame['Dupes'] = np.round(Sim_Winner_Frame['Dupes'], 0)
|
659 |
-
Sim_Winner_Frame['Dupes'] = np.where(
|
660 |
-
np.round(Sim_Winner_Frame['dupes_calc'], 0) <= 0,
|
661 |
-
0,
|
662 |
-
np.round(Sim_Winner_Frame['dupes_calc'], 0)
|
663 |
-
)
|
664 |
-
Sim_Winner_Frame = Sim_Winner_Frame.drop(columns=dup_count_columns)
|
665 |
-
Sim_Winner_Frame = Sim_Winner_Frame.drop(columns=own_columns)
|
666 |
-
Sim_Winner_Frame = Sim_Winner_Frame.drop(columns=calc_columns)
|
667 |
-
|
668 |
-
Sim_Winner_Frame = Sim_Winner_Frame.assign(win_count=Sim_Winner_Frame['unique_id'].map(Sim_Winner_Frame['unique_id'].value_counts()))
|
669 |
-
|
670 |
-
# Type Casting
|
671 |
-
type_cast_dict = {'salary': int, 'proj': np.float16, 'Fantasy': np.float16, 'GPP_Proj': np.float32, 'Own': np.float32, 'Dupes': int}
|
672 |
-
Sim_Winner_Frame = Sim_Winner_Frame.astype(type_cast_dict)
|
673 |
-
|
674 |
-
# Sorting
|
675 |
-
st.session_state.Sim_Winner_Frame = Sim_Winner_Frame.sort_values(by=['win_count', 'GPP_Proj'], ascending= [False, False]).copy().drop_duplicates(subset='unique_id').head(100)
|
676 |
-
st.session_state.Sim_Winner_Frame.drop(columns='unique_id', inplace=True)
|
677 |
-
|
678 |
-
# Data Copying
|
679 |
-
st.session_state.Sim_Winner_Export = Sim_Winner_Frame.copy()
|
680 |
-
st.session_state.Sim_Winner_Export.iloc[:, 0:6] = st.session_state.Sim_Winner_Export.iloc[:, 0:6].apply(lambda x: x.map(export_id_dict))
|
681 |
-
|
682 |
-
# Data Copying
|
683 |
-
st.session_state.Sim_Winner_Display = Sim_Winner_Frame.copy()
|
684 |
-
freq_copy = st.session_state.Sim_Winner_Display
|
685 |
-
|
686 |
-
if sim_site_var1 == 'Draftkings':
|
687 |
-
freq_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,0:6].values, return_counts=True)),
|
688 |
-
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
689 |
-
elif sim_site_var1 == 'Fanduel':
|
690 |
-
freq_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,0:5].values, return_counts=True)),
|
691 |
-
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
692 |
-
freq_working['Freq'] = freq_working['Freq'].astype(int)
|
693 |
-
freq_working['Position'] = freq_working['Player'].map(maps_dict['Pos_map'])
|
694 |
-
if sim_site_var1 == 'Draftkings':
|
695 |
-
if sim_sport_var1 == 'NFL':
|
696 |
-
freq_working['Salary'] = freq_working['Player'].map(maps_dict['Salary_map']) / 1.5
|
697 |
-
elif sim_sport_var1 == 'NBA':
|
698 |
-
freq_working['Salary'] = freq_working['Player'].map(maps_dict['Salary_map'])
|
699 |
-
elif sim_site_var1 == 'Fanduel':
|
700 |
-
freq_working['Salary'] = freq_working['Player'].map(maps_dict['Salary_map'])
|
701 |
-
freq_working['Proj Own'] = freq_working['Player'].map(maps_dict['Own_map']) / 100
|
702 |
-
freq_working['Exposure'] = freq_working['Freq']/(1000)
|
703 |
-
freq_working['Edge'] = freq_working['Exposure'] - freq_working['Proj Own']
|
704 |
-
freq_working['Team'] = freq_working['Player'].map(maps_dict['Team_map'])
|
705 |
-
st.session_state.player_freq = freq_working.copy()
|
706 |
-
|
707 |
-
if sim_site_var1 == 'Draftkings':
|
708 |
-
cpt_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,0:1].values, return_counts=True)),
|
709 |
-
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
710 |
-
elif sim_site_var1 == 'Fanduel':
|
711 |
-
cpt_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,0:1].values, return_counts=True)),
|
712 |
-
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
713 |
-
cpt_working['Freq'] = cpt_working['Freq'].astype(int)
|
714 |
-
cpt_working['Position'] = cpt_working['Player'].map(maps_dict['Pos_map'])
|
715 |
-
if sim_sport_var1 == 'NFL':
|
716 |
-
cpt_working['Salary'] = cpt_working['Player'].map(maps_dict['Salary_map'])
|
717 |
-
elif sim_sport_var1 == 'NBA':
|
718 |
-
cpt_working['Salary'] = cpt_working['Player'].map(maps_dict['Salary_map']) * 1.5
|
719 |
-
cpt_working['Proj Own'] = cpt_working['Player'].map(maps_dict['cpt_Own_map']) / 100
|
720 |
-
cpt_working['Exposure'] = cpt_working['Freq']/(1000)
|
721 |
-
cpt_working['Edge'] = cpt_working['Exposure'] - cpt_working['Proj Own']
|
722 |
-
cpt_working['Team'] = cpt_working['Player'].map(maps_dict['Team_map'])
|
723 |
-
st.session_state.sp_freq = cpt_working.copy()
|
724 |
-
|
725 |
-
if sim_site_var1 == 'Draftkings':
|
726 |
-
flex_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,1:6].values, return_counts=True)),
|
727 |
-
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
728 |
-
cpt_own_div = 600
|
729 |
-
elif sim_site_var1 == 'Fanduel':
|
730 |
-
flex_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,1:5].values, return_counts=True)),
|
731 |
-
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
732 |
-
cpt_own_div = 500
|
733 |
-
flex_working['Freq'] = flex_working['Freq'].astype(int)
|
734 |
-
flex_working['Position'] = flex_working['Player'].map(maps_dict['Pos_map'])
|
735 |
-
if sim_site_var1 == 'Draftkings':
|
736 |
-
if sim_sport_var1 == 'NFL':
|
737 |
-
flex_working['Salary'] = flex_working['Player'].map(maps_dict['Salary_map']) / 1.5
|
738 |
-
elif sim_sport_var1 == 'NBA':
|
739 |
-
flex_working['Salary'] = flex_working['Player'].map(maps_dict['Salary_map'])
|
740 |
-
elif sim_site_var1 == 'Fanduel':
|
741 |
-
flex_working['Salary'] = flex_working['Player'].map(maps_dict['Salary_map'])
|
742 |
-
flex_working['Proj Own'] = (flex_working['Player'].map(maps_dict['Own_map']) / 100) - (flex_working['Player'].map(maps_dict['cpt_Own_map']) / 100)
|
743 |
-
flex_working['Exposure'] = flex_working['Freq']/(1000)
|
744 |
-
flex_working['Edge'] = flex_working['Exposure'] - flex_working['Proj Own']
|
745 |
-
flex_working['Team'] = flex_working['Player'].map(maps_dict['Team_map'])
|
746 |
-
st.session_state.flex_freq = flex_working.copy()
|
747 |
-
|
748 |
-
if sim_site_var1 == 'Draftkings':
|
749 |
-
team_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,8:9].values, return_counts=True)),
|
750 |
-
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
751 |
-
elif sim_site_var1 == 'Fanduel':
|
752 |
-
team_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,7:8].values, return_counts=True)),
|
753 |
-
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
754 |
-
team_working['Freq'] = team_working['Freq'].astype(int)
|
755 |
-
team_working['Exposure'] = team_working['Freq']/(1000)
|
756 |
-
st.session_state.team_freq = team_working.copy()
|
757 |
-
|
758 |
-
with st.container():
|
759 |
-
if st.button("Reset Sim", key='reset_sim'):
|
760 |
-
for key in st.session_state.keys():
|
761 |
-
del st.session_state[key]
|
762 |
-
if 'player_freq' in st.session_state:
|
763 |
-
player_split_var2 = st.radio("Are you wanting to isolate any lineups with specific players?", ('Full Players', 'Specific Players'), key='player_split_var2')
|
764 |
-
if player_split_var2 == 'Specific Players':
|
765 |
-
find_var2 = st.multiselect('Which players must be included in the lineups?', options = st.session_state.player_freq['Player'].unique())
|
766 |
-
elif player_split_var2 == 'Full Players':
|
767 |
-
find_var2 = st.session_state.player_freq.Player.values.tolist()
|
768 |
-
|
769 |
-
if player_split_var2 == 'Specific Players':
|
770 |
-
st.session_state.Sim_Winner_Display = st.session_state.Sim_Winner_Frame[np.equal.outer(st.session_state.Sim_Winner_Frame.to_numpy(), find_var2).any(axis=1).all(axis=1)]
|
771 |
-
if player_split_var2 == 'Full Players':
|
772 |
-
st.session_state.Sim_Winner_Display = st.session_state.Sim_Winner_Frame
|
773 |
-
if 'Sim_Winner_Display' in st.session_state:
|
774 |
-
st.dataframe(st.session_state.Sim_Winner_Display.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
|
775 |
-
if 'Sim_Winner_Export' in st.session_state:
|
776 |
-
st.download_button(
|
777 |
-
label="Export Full Frame",
|
778 |
-
data=st.session_state.Sim_Winner_Export.to_csv().encode('utf-8'),
|
779 |
-
file_name='NFL_SD_consim_export.csv',
|
780 |
-
mime='text/csv',
|
781 |
-
)
|
782 |
-
|
783 |
-
with st.container():
|
784 |
-
tab1, tab2, tab3, tab4 = st.tabs(['Overall Exposures', 'CPT Exposures', 'FLEX Exposures', 'Team Exposures'])
|
785 |
-
with tab1:
|
786 |
-
if 'player_freq' in st.session_state:
|
787 |
-
|
788 |
-
st.dataframe(st.session_state.player_freq.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(freq_format, precision=2), use_container_width = True)
|
789 |
-
st.download_button(
|
790 |
-
label="Export Exposures",
|
791 |
-
data=st.session_state.player_freq.to_csv().encode('utf-8'),
|
792 |
-
file_name='player_freq_export.csv',
|
793 |
-
mime='text/csv',
|
794 |
-
key='overall'
|
795 |
-
)
|
796 |
-
with tab2:
|
797 |
-
if 'sp_freq' in st.session_state:
|
798 |
-
|
799 |
-
st.dataframe(st.session_state.sp_freq.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(freq_format, precision=2), use_container_width = True)
|
800 |
-
st.download_button(
|
801 |
-
label="Export Exposures",
|
802 |
-
data=st.session_state.sp_freq.to_csv().encode('utf-8'),
|
803 |
-
file_name='cpt_freq.csv',
|
804 |
-
mime='text/csv',
|
805 |
-
key='sp'
|
806 |
-
)
|
807 |
-
with tab3:
|
808 |
-
if 'flex_freq' in st.session_state:
|
809 |
-
|
810 |
-
st.dataframe(st.session_state.flex_freq.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(freq_format, precision=2), use_container_width = True)
|
811 |
-
st.download_button(
|
812 |
-
label="Export Exposures",
|
813 |
-
data=st.session_state.flex_freq.to_csv().encode('utf-8'),
|
814 |
-
file_name='flex_freq.csv',
|
815 |
-
mime='text/csv',
|
816 |
-
key='flex'
|
817 |
-
)
|
818 |
-
with tab4:
|
819 |
-
if 'team_freq' in st.session_state:
|
820 |
-
|
821 |
-
st.dataframe(st.session_state.team_freq.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(percentages_format, precision=2), use_container_width = True)
|
822 |
-
st.download_button(
|
823 |
-
label="Export Exposures",
|
824 |
-
data=st.session_state.team_freq.to_csv().encode('utf-8'),
|
825 |
-
file_name='team_freq.csv',
|
826 |
-
mime='text/csv',
|
827 |
-
key='team'
|
828 |
-
)
|
|
|
281 |
dk_raw, fd_raw = init_baselines('NBA')
|
282 |
|
283 |
tab1, tab2 = st.tabs(['Contest Sims', 'Data Export'])
|
284 |
+
|
285 |
+
with tab1:
|
286 |
+
with st.expander("Info and Filters"):
|
287 |
+
if st.button("Load/Reset Data", key='reset2'):
|
288 |
+
st.cache_data.clear()
|
289 |
+
for key in st.session_state.keys():
|
290 |
+
del st.session_state[key]
|
291 |
+
dk_raw, fd_raw = init_baselines('NFL')
|
292 |
+
sim_sport_var1 = st.radio("What sport are you working with?", ('NBA', 'NFL'), key='sim_sport_var1')
|
293 |
+
dk_raw, fd_raw = init_baselines(sim_sport_var1)
|
294 |
+
sim_slate_var1 = st.radio("Which data are you loading?", ('Showdown', 'Secondary Showdown', 'Auxiliary Showdown'), key='sim_slate_var1')
|
295 |
+
sim_site_var1 = st.radio("What site are you working with?", ('Draftkings', 'Fanduel'), key='sim_site_var1')
|
296 |
+
if sim_site_var1 == 'Draftkings':
|
297 |
+
raw_baselines = dk_raw
|
298 |
+
column_names = dk_columns
|
299 |
+
elif sim_site_var1 == 'Fanduel':
|
300 |
+
raw_baselines = fd_raw
|
301 |
+
column_names = fd_columns
|
302 |
+
contest_var1 = st.selectbox("What contest size are you simulating?", ('Small', 'Medium', 'Large', 'Custom'))
|
303 |
+
if contest_var1 == 'Small':
|
304 |
+
Contest_Size = 1000
|
305 |
+
st.write("Small field size is 1,000 entrants.")
|
306 |
+
raw_baselines['Own'] = raw_baselines['Small_Field_Own']
|
307 |
+
raw_baselines['CPT_Own'] = raw_baselines['small_CPT_Own']
|
308 |
+
elif contest_var1 == 'Medium':
|
309 |
+
Contest_Size = 5000
|
310 |
+
st.write("Medium field size is 5,000 entrants.")
|
311 |
+
elif contest_var1 == 'Large':
|
312 |
+
Contest_Size = 10000
|
313 |
+
st.write("Large field size is 10,000 entrants.")
|
314 |
+
elif contest_var1 == 'Custom':
|
315 |
+
Contest_Size = st.number_input("Insert contest size", value=100, min_value=1, max_value=100000)
|
316 |
+
strength_var1 = st.selectbox("How sharp is the field in the contest?", ('Very', 'Above Average', 'Average', 'Below Average', 'Not Very'))
|
317 |
+
if strength_var1 == 'Not Very':
|
318 |
+
sharp_split = 500000
|
319 |
+
elif strength_var1 == 'Below Average':
|
320 |
+
sharp_split = 400000
|
321 |
+
elif strength_var1 == 'Average':
|
322 |
+
sharp_split = 300000
|
323 |
+
elif strength_var1 == 'Above Average':
|
324 |
+
sharp_split = 200000
|
325 |
+
elif strength_var1 == 'Very':
|
326 |
+
sharp_split = 100000
|
327 |
+
|
328 |
+
if st.button("Run Contest Sim"):
|
329 |
+
if 'working_seed' in st.session_state:
|
330 |
+
maps_dict = {
|
331 |
+
'Projection_map':dict(zip(raw_baselines.Player,raw_baselines.Median)),
|
332 |
+
'cpt_projection_map':dict(zip(raw_baselines.Player,raw_baselines.cpt_Median)),
|
333 |
+
'Salary_map':dict(zip(raw_baselines.Player,raw_baselines.Salary)),
|
334 |
+
'Pos_map':dict(zip(raw_baselines.Player,raw_baselines.Position)),
|
335 |
+
'Own_map':dict(zip(raw_baselines.Player,raw_baselines['Own'])),
|
336 |
+
'cpt_Own_map':dict(zip(raw_baselines.Player,raw_baselines['CPT_Own'])),
|
337 |
+
'Team_map':dict(zip(raw_baselines.Player,raw_baselines.Team)),
|
338 |
+
'STDev_map':dict(zip(raw_baselines.Player,raw_baselines.STDev)),
|
339 |
+
'cpt_STDev_map':dict(zip(raw_baselines.Player,raw_baselines['CPT_STDev']))
|
340 |
+
}
|
341 |
+
Sim_Winners = sim_contest(1000, st.session_state.working_seed, maps_dict, Contest_Size)
|
342 |
+
Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners))
|
343 |
+
|
344 |
+
#st.table(Sim_Winner_Frame)
|
345 |
+
|
346 |
+
# Initial setup
|
347 |
+
Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners), columns=column_names + ['Fantasy'])
|
348 |
+
Sim_Winner_Frame['GPP_Proj'] = (Sim_Winner_Frame['proj'] + Sim_Winner_Frame['Fantasy']) / 2
|
349 |
+
Sim_Winner_Frame['unique_id'] = Sim_Winner_Frame['proj'].astype(str) + Sim_Winner_Frame['salary'].astype(str) + Sim_Winner_Frame['Team'].astype(str) + Sim_Winner_Frame['Secondary'].astype(str)
|
350 |
+
Sim_Winner_Frame = Sim_Winner_Frame.assign(win_count=Sim_Winner_Frame['unique_id'].map(Sim_Winner_Frame['unique_id'].value_counts()))
|
351 |
+
|
352 |
+
# Type Casting
|
353 |
+
type_cast_dict = {'salary': int, 'proj': np.float16, 'Fantasy': np.float16, 'GPP_Proj': np.float32, 'Own': np.float32}
|
354 |
+
Sim_Winner_Frame = Sim_Winner_Frame.astype(type_cast_dict)
|
355 |
+
|
356 |
+
# Sorting
|
357 |
+
st.session_state.Sim_Winner_Frame = Sim_Winner_Frame.sort_values(by=['win_count', 'GPP_Proj'], ascending= [False, False]).copy().drop_duplicates(subset='unique_id').head(100)
|
358 |
+
st.session_state.Sim_Winner_Frame.drop(columns='unique_id', inplace=True)
|
359 |
+
|
360 |
+
# Data Copying
|
361 |
+
st.session_state.Sim_Winner_Export = Sim_Winner_Frame.copy()
|
362 |
+
|
363 |
+
# Data Copying
|
364 |
+
st.session_state.Sim_Winner_Display = Sim_Winner_Frame.copy()
|
365 |
+
|
366 |
+
else:
|
367 |
+
if sim_site_var1 == 'Draftkings':
|
368 |
+
if sim_slate_var1 == 'Showdown':
|
369 |
+
st.session_state.working_seed = init_DK_seed_frames(sim_sport_var1, sharp_split_var)
|
370 |
+
if sport_var1 == 'NFL':
|
371 |
+
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
372 |
+
elif sport_var1 == 'NBA':
|
373 |
+
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
374 |
+
elif sim_slate_var1 == 'Secondary Showdown':
|
375 |
+
st.session_state.working_seed = init_DK_secondary_seed_frames(sim_sport_var1, sharp_split_var)
|
376 |
+
if sport_var1 == 'NFL':
|
377 |
+
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
378 |
+
elif sport_var1 == 'NBA':
|
379 |
+
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
380 |
+
elif sim_slate_var1 == 'Auxiliary Showdown':
|
381 |
+
st.session_state.working_seed = init_DK_auxiliary_seed_frames(sim_sport_var1, sharp_split_var)
|
382 |
+
if sport_var1 == 'NFL':
|
383 |
+
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
384 |
+
elif sport_var1 == 'NBA':
|
385 |
+
export_id_dict = dict(zip(dk_raw['Player'], dk_raw['player_id']))
|
386 |
+
raw_baselines = dk_raw
|
387 |
+
column_names = dk_columns
|
388 |
+
elif sim_site_var1 == 'Fanduel':
|
389 |
+
if sim_slate_var1 == 'Showdown':
|
390 |
+
st.session_state.working_seed = init_FD_seed_frames(sim_sport_var1, sharp_split_var)
|
391 |
+
if sport_var1 == 'NFL':
|
392 |
+
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
393 |
+
elif sport_var1 == 'NBA':
|
394 |
+
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
395 |
+
elif sim_slate_var1 == 'Secondary Showdown':
|
396 |
+
st.session_state.working_seed = init_FD_secondary_seed_frames(sim_sport_var1, sharp_split_var)
|
397 |
+
if sport_var1 == 'NFL':
|
398 |
+
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
399 |
+
elif sport_var1 == 'NBA':
|
400 |
+
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
401 |
+
elif sim_slate_var1 == 'Auxiliary Showdown':
|
402 |
+
st.session_state.working_seed = init_FD_auxiliary_seed_frames(sim_sport_var1, sharp_split_var)
|
403 |
+
if sport_var1 == 'NFL':
|
404 |
+
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
405 |
+
elif sport_var1 == 'NBA':
|
406 |
+
export_id_dict = dict(zip(fd_raw['Player'], fd_raw['player_id']))
|
407 |
+
raw_baselines = fd_raw
|
408 |
+
column_names = fd_columns
|
409 |
+
maps_dict = {
|
410 |
+
'Projection_map':dict(zip(raw_baselines.Player,raw_baselines.Median)),
|
411 |
+
'cpt_projection_map':dict(zip(raw_baselines.Player,raw_baselines.cpt_Median)),
|
412 |
+
'Salary_map':dict(zip(raw_baselines.Player,raw_baselines.Salary)),
|
413 |
+
'Pos_map':dict(zip(raw_baselines.Player,raw_baselines.Position)),
|
414 |
+
'Own_map':dict(zip(raw_baselines.Player,raw_baselines['Own'])),
|
415 |
+
'cpt_Own_map':dict(zip(raw_baselines.Player,raw_baselines['CPT_Own'])),
|
416 |
+
'Team_map':dict(zip(raw_baselines.Player,raw_baselines.Team)),
|
417 |
+
'STDev_map':dict(zip(raw_baselines.Player,raw_baselines.STDev)),
|
418 |
+
'cpt_STDev_map':dict(zip(raw_baselines.Player,raw_baselines['CPT_STDev']))
|
419 |
+
}
|
420 |
+
Sim_Winners = sim_contest(1000, st.session_state.working_seed, maps_dict, Contest_Size)
|
421 |
+
Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners))
|
422 |
+
|
423 |
+
#st.table(Sim_Winner_Frame)
|
424 |
+
|
425 |
+
# Initial setup
|
426 |
+
Sim_Winner_Frame = pd.DataFrame(np.concatenate(Sim_Winners), columns=column_names + ['Fantasy'])
|
427 |
+
Sim_Winner_Frame['GPP_Proj'] = (Sim_Winner_Frame['proj'] + Sim_Winner_Frame['Fantasy']) / 2
|
428 |
+
Sim_Winner_Frame['unique_id'] = Sim_Winner_Frame['proj'].astype(str) + Sim_Winner_Frame['salary'].astype(str) + Sim_Winner_Frame['Team'].astype(str) + Sim_Winner_Frame['Secondary'].astype(str)
|
429 |
+
# Add percent rank columns for ownership at each roster position
|
430 |
+
# Calculate Dupes column for Fanduel
|
431 |
+
if sim_site_var1 == 'Fanduel':
|
432 |
+
dup_count_columns = ['CPT_Own_percent_rank', 'FLEX1_Own_percent_rank', 'FLEX2_Own_percent_rank', 'FLEX3_Own_percent_rank', 'FLEX4_Own_percent_rank']
|
433 |
+
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own']
|
434 |
+
calc_columns = ['own_product', 'avg_own_rank', 'dupes_calc']
|
435 |
+
Sim_Winner_Frame['CPT_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,0].map(maps_dict['cpt_Own_map']).rank(pct=True)
|
436 |
+
Sim_Winner_Frame['FLEX1_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,1].map(maps_dict['Own_map']).rank(pct=True)
|
437 |
+
Sim_Winner_Frame['FLEX2_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,2].map(maps_dict['Own_map']).rank(pct=True)
|
438 |
+
Sim_Winner_Frame['FLEX3_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,3].map(maps_dict['Own_map']).rank(pct=True)
|
439 |
+
Sim_Winner_Frame['FLEX4_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,4].map(maps_dict['Own_map']).rank(pct=True)
|
440 |
+
Sim_Winner_Frame['CPT_Own'] = Sim_Winner_Frame.iloc[:,0].map(maps_dict['cpt_Own_map']) / 100
|
441 |
+
Sim_Winner_Frame['FLEX1_Own'] = Sim_Winner_Frame.iloc[:,1].map(maps_dict['Own_map']) / 100
|
442 |
+
Sim_Winner_Frame['FLEX2_Own'] = Sim_Winner_Frame.iloc[:,2].map(maps_dict['Own_map']) / 100
|
443 |
+
Sim_Winner_Frame['FLEX3_Own'] = Sim_Winner_Frame.iloc[:,3].map(maps_dict['Own_map']) / 100
|
444 |
+
Sim_Winner_Frame['FLEX4_Own'] = Sim_Winner_Frame.iloc[:,4].map(maps_dict['Own_map']) / 100
|
445 |
+
|
446 |
+
# Calculate ownership product and convert to probability
|
447 |
+
Sim_Winner_Frame['own_product'] = (Sim_Winner_Frame[own_columns].product(axis=1)) + 0.0001
|
448 |
+
|
449 |
+
# Calculate average of ownership percent rank columns
|
450 |
+
Sim_Winner_Frame['avg_own_rank'] = Sim_Winner_Frame[dup_count_columns].mean(axis=1)
|
451 |
+
|
452 |
+
# Calculate dupes formula
|
453 |
+
Sim_Winner_Frame['dupes_calc'] = ((Sim_Winner_Frame['own_product'] * Sim_Winner_Frame['avg_own_rank']) * (Contest_Size * 1.5)) + ((Sim_Winner_Frame['salary'] - 59800) / 100)
|
454 |
+
|
455 |
+
# Round and handle negative values
|
456 |
+
Sim_Winner_Frame['Dupes'] = np.where(
|
457 |
+
np.round(Sim_Winner_Frame['dupes_calc'], 0) <= 0,
|
458 |
+
0,
|
459 |
+
np.round(Sim_Winner_Frame['dupes_calc'], 0) - 1
|
460 |
+
)
|
461 |
+
Sim_Winner_Frame['Dupes'] = (Sim_Winner_Frame['Dupes'] * (500000 / sharp_split)) / 2
|
462 |
+
elif sim_site_var1 == 'Draftkings':
|
463 |
+
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']
|
464 |
+
own_columns = ['CPT_Own', 'FLEX1_Own', 'FLEX2_Own', 'FLEX3_Own', 'FLEX4_Own', 'FLEX5_Own']
|
465 |
+
calc_columns = ['own_product', 'avg_own_rank', 'dupes_calc']
|
466 |
+
Sim_Winner_Frame['CPT_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,0].map(maps_dict['cpt_Own_map']).rank(pct=True)
|
467 |
+
Sim_Winner_Frame['FLEX1_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,1].map(maps_dict['Own_map']).rank(pct=True)
|
468 |
+
Sim_Winner_Frame['FLEX2_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,2].map(maps_dict['Own_map']).rank(pct=True)
|
469 |
+
Sim_Winner_Frame['FLEX3_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,3].map(maps_dict['Own_map']).rank(pct=True)
|
470 |
+
Sim_Winner_Frame['FLEX4_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,4].map(maps_dict['Own_map']).rank(pct=True)
|
471 |
+
Sim_Winner_Frame['FLEX5_Own_percent_rank'] = Sim_Winner_Frame.iloc[:,5].map(maps_dict['Own_map']).rank(pct=True)
|
472 |
+
Sim_Winner_Frame['CPT_Own'] = Sim_Winner_Frame.iloc[:,0].map(maps_dict['cpt_Own_map']) / 100
|
473 |
+
Sim_Winner_Frame['FLEX1_Own'] = Sim_Winner_Frame.iloc[:,1].map(maps_dict['Own_map']) / 100
|
474 |
+
Sim_Winner_Frame['FLEX2_Own'] = Sim_Winner_Frame.iloc[:,2].map(maps_dict['Own_map']) / 100
|
475 |
+
Sim_Winner_Frame['FLEX3_Own'] = Sim_Winner_Frame.iloc[:,3].map(maps_dict['Own_map']) / 100
|
476 |
+
Sim_Winner_Frame['FLEX4_Own'] = Sim_Winner_Frame.iloc[:,4].map(maps_dict['Own_map']) / 100
|
477 |
+
Sim_Winner_Frame['FLEX5_Own'] = Sim_Winner_Frame.iloc[:,5].map(maps_dict['Own_map']) / 100
|
478 |
+
|
479 |
+
# Calculate ownership product and convert to probability
|
480 |
+
Sim_Winner_Frame['own_product'] = (Sim_Winner_Frame[own_columns].product(axis=1))
|
481 |
+
|
482 |
+
# Calculate average of ownership percent rank columns
|
483 |
+
Sim_Winner_Frame['avg_own_rank'] = Sim_Winner_Frame[dup_count_columns].mean(axis=1)
|
484 |
+
|
485 |
+
# Calculate dupes formula
|
486 |
+
Sim_Winner_Frame['dupes_calc'] = ((Sim_Winner_Frame['own_product'] * Sim_Winner_Frame['avg_own_rank']) * (Contest_Size * 1.5)) + ((Sim_Winner_Frame['salary'] - 49800) / 100)
|
487 |
+
|
488 |
+
# Round and handle negative values
|
489 |
+
Sim_Winner_Frame['Dupes'] = np.where(
|
490 |
+
np.round(Sim_Winner_Frame['dupes_calc'], 0) <= 0,
|
491 |
+
0,
|
492 |
+
np.round(Sim_Winner_Frame['dupes_calc'], 0) - 1
|
493 |
+
)
|
494 |
+
Sim_Winner_Frame['Dupes'] = (Sim_Winner_Frame['Dupes'] * (500000 / sharp_split)) / 2
|
495 |
+
Sim_Winner_Frame['Dupes'] = np.round(Sim_Winner_Frame['Dupes'], 0)
|
496 |
+
Sim_Winner_Frame['Dupes'] = np.where(
|
497 |
+
np.round(Sim_Winner_Frame['dupes_calc'], 0) <= 0,
|
498 |
+
0,
|
499 |
+
np.round(Sim_Winner_Frame['dupes_calc'], 0)
|
500 |
+
)
|
501 |
+
Sim_Winner_Frame = Sim_Winner_Frame.drop(columns=dup_count_columns)
|
502 |
+
Sim_Winner_Frame = Sim_Winner_Frame.drop(columns=own_columns)
|
503 |
+
Sim_Winner_Frame = Sim_Winner_Frame.drop(columns=calc_columns)
|
504 |
+
|
505 |
+
Sim_Winner_Frame = Sim_Winner_Frame.assign(win_count=Sim_Winner_Frame['unique_id'].map(Sim_Winner_Frame['unique_id'].value_counts()))
|
506 |
+
|
507 |
+
# Type Casting
|
508 |
+
type_cast_dict = {'salary': int, 'proj': np.float16, 'Fantasy': np.float16, 'GPP_Proj': np.float32, 'Own': np.float32, 'Dupes': int}
|
509 |
+
Sim_Winner_Frame = Sim_Winner_Frame.astype(type_cast_dict)
|
510 |
+
|
511 |
+
# Sorting
|
512 |
+
st.session_state.Sim_Winner_Frame = Sim_Winner_Frame.sort_values(by=['win_count', 'GPP_Proj'], ascending= [False, False]).copy().drop_duplicates(subset='unique_id').head(100)
|
513 |
+
st.session_state.Sim_Winner_Frame.drop(columns='unique_id', inplace=True)
|
514 |
+
|
515 |
+
# Data Copying
|
516 |
+
st.session_state.Sim_Winner_Export = Sim_Winner_Frame.copy()
|
517 |
+
st.session_state.Sim_Winner_Export.iloc[:, 0:6] = st.session_state.Sim_Winner_Export.iloc[:, 0:6].apply(lambda x: x.map(export_id_dict))
|
518 |
+
|
519 |
+
# Data Copying
|
520 |
+
st.session_state.Sim_Winner_Display = Sim_Winner_Frame.copy()
|
521 |
+
freq_copy = st.session_state.Sim_Winner_Display
|
522 |
+
|
523 |
+
if sim_site_var1 == 'Draftkings':
|
524 |
+
freq_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,0:6].values, return_counts=True)),
|
525 |
+
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
526 |
+
elif sim_site_var1 == 'Fanduel':
|
527 |
+
freq_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,0:5].values, return_counts=True)),
|
528 |
+
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
529 |
+
freq_working['Freq'] = freq_working['Freq'].astype(int)
|
530 |
+
freq_working['Position'] = freq_working['Player'].map(maps_dict['Pos_map'])
|
531 |
+
if sim_site_var1 == 'Draftkings':
|
532 |
+
if sim_sport_var1 == 'NFL':
|
533 |
+
freq_working['Salary'] = freq_working['Player'].map(maps_dict['Salary_map']) / 1.5
|
534 |
+
elif sim_sport_var1 == 'NBA':
|
535 |
+
freq_working['Salary'] = freq_working['Player'].map(maps_dict['Salary_map'])
|
536 |
+
elif sim_site_var1 == 'Fanduel':
|
537 |
+
freq_working['Salary'] = freq_working['Player'].map(maps_dict['Salary_map'])
|
538 |
+
freq_working['Proj Own'] = freq_working['Player'].map(maps_dict['Own_map']) / 100
|
539 |
+
freq_working['Exposure'] = freq_working['Freq']/(1000)
|
540 |
+
freq_working['Edge'] = freq_working['Exposure'] - freq_working['Proj Own']
|
541 |
+
freq_working['Team'] = freq_working['Player'].map(maps_dict['Team_map'])
|
542 |
+
st.session_state.player_freq = freq_working.copy()
|
543 |
+
|
544 |
+
if sim_site_var1 == 'Draftkings':
|
545 |
+
cpt_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,0:1].values, return_counts=True)),
|
546 |
+
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
547 |
+
elif sim_site_var1 == 'Fanduel':
|
548 |
+
cpt_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,0:1].values, return_counts=True)),
|
549 |
+
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
550 |
+
cpt_working['Freq'] = cpt_working['Freq'].astype(int)
|
551 |
+
cpt_working['Position'] = cpt_working['Player'].map(maps_dict['Pos_map'])
|
552 |
+
if sim_sport_var1 == 'NFL':
|
553 |
+
cpt_working['Salary'] = cpt_working['Player'].map(maps_dict['Salary_map'])
|
554 |
+
elif sim_sport_var1 == 'NBA':
|
555 |
+
cpt_working['Salary'] = cpt_working['Player'].map(maps_dict['Salary_map']) * 1.5
|
556 |
+
cpt_working['Proj Own'] = cpt_working['Player'].map(maps_dict['cpt_Own_map']) / 100
|
557 |
+
cpt_working['Exposure'] = cpt_working['Freq']/(1000)
|
558 |
+
cpt_working['Edge'] = cpt_working['Exposure'] - cpt_working['Proj Own']
|
559 |
+
cpt_working['Team'] = cpt_working['Player'].map(maps_dict['Team_map'])
|
560 |
+
st.session_state.sp_freq = cpt_working.copy()
|
561 |
+
|
562 |
+
if sim_site_var1 == 'Draftkings':
|
563 |
+
flex_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,1:6].values, return_counts=True)),
|
564 |
+
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
565 |
+
cpt_own_div = 600
|
566 |
+
elif sim_site_var1 == 'Fanduel':
|
567 |
+
flex_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,1:5].values, return_counts=True)),
|
568 |
+
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
569 |
+
cpt_own_div = 500
|
570 |
+
flex_working['Freq'] = flex_working['Freq'].astype(int)
|
571 |
+
flex_working['Position'] = flex_working['Player'].map(maps_dict['Pos_map'])
|
572 |
+
if sim_site_var1 == 'Draftkings':
|
573 |
+
if sim_sport_var1 == 'NFL':
|
574 |
+
flex_working['Salary'] = flex_working['Player'].map(maps_dict['Salary_map']) / 1.5
|
575 |
+
elif sim_sport_var1 == 'NBA':
|
576 |
+
flex_working['Salary'] = flex_working['Player'].map(maps_dict['Salary_map'])
|
577 |
+
elif sim_site_var1 == 'Fanduel':
|
578 |
+
flex_working['Salary'] = flex_working['Player'].map(maps_dict['Salary_map'])
|
579 |
+
flex_working['Proj Own'] = (flex_working['Player'].map(maps_dict['Own_map']) / 100) - (flex_working['Player'].map(maps_dict['cpt_Own_map']) / 100)
|
580 |
+
flex_working['Exposure'] = flex_working['Freq']/(1000)
|
581 |
+
flex_working['Edge'] = flex_working['Exposure'] - flex_working['Proj Own']
|
582 |
+
flex_working['Team'] = flex_working['Player'].map(maps_dict['Team_map'])
|
583 |
+
st.session_state.flex_freq = flex_working.copy()
|
584 |
+
|
585 |
+
if sim_site_var1 == 'Draftkings':
|
586 |
+
team_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,8:9].values, return_counts=True)),
|
587 |
+
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
588 |
+
elif sim_site_var1 == 'Fanduel':
|
589 |
+
team_working = pd.DataFrame(np.column_stack(np.unique(freq_copy.iloc[:,7:8].values, return_counts=True)),
|
590 |
+
columns=['Player','Freq']).sort_values('Freq', ascending=False).reset_index(drop=True)
|
591 |
+
team_working['Freq'] = team_working['Freq'].astype(int)
|
592 |
+
team_working['Exposure'] = team_working['Freq']/(1000)
|
593 |
+
st.session_state.team_freq = team_working.copy()
|
594 |
+
|
595 |
+
with st.container():
|
596 |
+
if st.button("Reset Sim", key='reset_sim'):
|
597 |
+
for key in st.session_state.keys():
|
598 |
+
del st.session_state[key]
|
599 |
+
if 'player_freq' in st.session_state:
|
600 |
+
player_split_var2 = st.radio("Are you wanting to isolate any lineups with specific players?", ('Full Players', 'Specific Players'), key='player_split_var2')
|
601 |
+
if player_split_var2 == 'Specific Players':
|
602 |
+
find_var2 = st.multiselect('Which players must be included in the lineups?', options = st.session_state.player_freq['Player'].unique())
|
603 |
+
elif player_split_var2 == 'Full Players':
|
604 |
+
find_var2 = st.session_state.player_freq.Player.values.tolist()
|
605 |
+
|
606 |
+
if player_split_var2 == 'Specific Players':
|
607 |
+
st.session_state.Sim_Winner_Display = st.session_state.Sim_Winner_Frame[np.equal.outer(st.session_state.Sim_Winner_Frame.to_numpy(), find_var2).any(axis=1).all(axis=1)]
|
608 |
+
if player_split_var2 == 'Full Players':
|
609 |
+
st.session_state.Sim_Winner_Display = st.session_state.Sim_Winner_Frame
|
610 |
+
if 'Sim_Winner_Display' in st.session_state:
|
611 |
+
st.dataframe(st.session_state.Sim_Winner_Display.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
|
612 |
+
if 'Sim_Winner_Export' in st.session_state:
|
613 |
+
st.download_button(
|
614 |
+
label="Export Full Frame",
|
615 |
+
data=st.session_state.Sim_Winner_Export.to_csv().encode('utf-8'),
|
616 |
+
file_name='NFL_SD_consim_export.csv',
|
617 |
+
mime='text/csv',
|
618 |
+
)
|
619 |
+
|
620 |
+
with st.container():
|
621 |
+
tab1, tab2, tab3, tab4 = st.tabs(['Overall Exposures', 'CPT Exposures', 'FLEX Exposures', 'Team Exposures'])
|
622 |
+
with tab1:
|
623 |
+
if 'player_freq' in st.session_state:
|
624 |
+
|
625 |
+
st.dataframe(st.session_state.player_freq.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(freq_format, precision=2), use_container_width = True)
|
626 |
+
st.download_button(
|
627 |
+
label="Export Exposures",
|
628 |
+
data=st.session_state.player_freq.to_csv().encode('utf-8'),
|
629 |
+
file_name='player_freq_export.csv',
|
630 |
+
mime='text/csv',
|
631 |
+
key='overall'
|
632 |
+
)
|
633 |
+
with tab2:
|
634 |
+
if 'sp_freq' in st.session_state:
|
635 |
+
|
636 |
+
st.dataframe(st.session_state.sp_freq.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(freq_format, precision=2), use_container_width = True)
|
637 |
+
st.download_button(
|
638 |
+
label="Export Exposures",
|
639 |
+
data=st.session_state.sp_freq.to_csv().encode('utf-8'),
|
640 |
+
file_name='cpt_freq.csv',
|
641 |
+
mime='text/csv',
|
642 |
+
key='sp'
|
643 |
+
)
|
644 |
+
with tab3:
|
645 |
+
if 'flex_freq' in st.session_state:
|
646 |
+
|
647 |
+
st.dataframe(st.session_state.flex_freq.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(freq_format, precision=2), use_container_width = True)
|
648 |
+
st.download_button(
|
649 |
+
label="Export Exposures",
|
650 |
+
data=st.session_state.flex_freq.to_csv().encode('utf-8'),
|
651 |
+
file_name='flex_freq.csv',
|
652 |
+
mime='text/csv',
|
653 |
+
key='flex'
|
654 |
+
)
|
655 |
+
with tab4:
|
656 |
+
if 'team_freq' in st.session_state:
|
657 |
+
|
658 |
+
st.dataframe(st.session_state.team_freq.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(percentages_format, precision=2), use_container_width = True)
|
659 |
+
st.download_button(
|
660 |
+
label="Export Exposures",
|
661 |
+
data=st.session_state.team_freq.to_csv().encode('utf-8'),
|
662 |
+
file_name='team_freq.csv',
|
663 |
+
mime='text/csv',
|
664 |
+
key='team'
|
665 |
+
)
|
666 |
+
|
667 |
with tab2:
|
668 |
with st.expander("Info and Filters"):
|
669 |
if st.button("Load/Reset Data", key='reset1'):
|
|
|
823 |
|
824 |
with st.container():
|
825 |
if 'data_export_display' in st.session_state:
|
826 |
+
st.dataframe(st.session_state.data_export_display.style.format(freq_format, precision=2), use_container_width = True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|