James McCool commited on
Commit
163393f
·
1 Parent(s): 029a42d

A lot of changes. Added loop for stat sim was the biggest change.

Browse files
Files changed (1) hide show
  1. app.py +229 -239
app.py CHANGED
@@ -98,7 +98,7 @@ def init_baselines():
98
  worksheet = sh.worksheet('DK_Build_Up')
99
  raw_display = pd.DataFrame(worksheet.get_all_records())
100
  raw_display.replace('', np.nan, inplace=True)
101
- raw_display.rename(columns={"Name": "Player"}, inplace = True)
102
 
103
  raw_baselines = raw_display[['Player', 'Position', 'Team', 'Opp', 'Minutes', 'FGM', 'FGA', 'FG2M', 'FG2A', 'Threes', 'FG3A', 'FTM', 'FTA', 'TRB', 'AST', 'STL', 'BLK', 'TOV']]
104
  raw_baselines = raw_baselines[raw_baselines['Minutes'] > 0]
@@ -119,14 +119,15 @@ def init_baselines():
119
  worksheet = sh.worksheet('Prop_Frame')
120
  raw_display = pd.DataFrame(worksheet.get_all_records())
121
  raw_display.replace('', np.nan, inplace=True)
122
- prop_frame = raw_display.dropna(subset='Name')
 
123
 
124
  worksheet = sh.worksheet('Pick6_ingest')
125
  raw_display = pd.DataFrame(worksheet.get_all_records())
126
  raw_display.replace('', np.nan, inplace=True)
127
  pick_frame = raw_display.dropna(subset='Player')
128
 
129
- prop_frame['Name'].replace(['Jaren Jackson', 'Nic Claxton', 'Jabari Smith', 'Lu Dort', 'Moe Wagner', 'Kyle Kuzma', 'Trey Murphy', 'Cameron Thomas'],
130
  ['Jaren Jackson Jr.', 'Nicolas Claxton', 'Jabari Smith Jr.', 'Luguentz Dort', 'Moritz Wagner', 'Kyle Kuzma Jr.',
131
  'Trey Murphy III', 'Cam Thomas'], inplace=True)
132
  pick_frame['Player'].replace(['Jaren Jackson', 'Nic Claxton', 'Jabari Smith', 'Lu Dort', 'Moe Wagner', 'Kyle Kuzma', 'Trey Murphy', 'Cameron Thomas'],
@@ -203,13 +204,13 @@ with tab3:
203
  team_var5 = player_stats.Team.values.tolist()
204
  book_split5 = st.radio("Would you like to view all books or specific ones?", ('All', 'Specific Books'), key='book_split5')
205
  if book_split5 == 'Specific Books':
206
- book_var5 = st.multiselect('Which books would you like to include in the tables?', options = prop_frame['OddsType'].unique(), key='book_var5')
207
  elif book_split5 == 'All':
208
- book_var5 = prop_frame.OddsType.values.tolist()
209
  prop_type_var2 = st.selectbox('Select type of prop are you wanting to view', options = prop_table_options)
210
  prop_frame_disp = prop_frame[prop_frame['Team'].isin(team_var5)]
211
- prop_frame_disp = prop_frame_disp[prop_frame_disp['OddsType'].isin(book_var5)]
212
- prop_frame_disp = prop_frame_disp[prop_frame_disp['PropType'] == prop_type_var2]
213
  prop_frame_disp = prop_frame_disp.sort_values(by='Trending Over', ascending=False)
214
  st.dataframe(prop_frame_disp.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(prop_format, precision=2), use_container_width = True)
215
  st.download_button(
@@ -365,9 +366,8 @@ with tab4:
365
 
366
  with tab5:
367
  st.info(t_stamp)
368
- st.info('The Over and Under percentages are a composite percentage based on simulations, historical performance, and implied probabilities, and may be different than you would expect based purely on the median projection. Likewise, the Edge of a bet is not the only indicator of if you should make the bet or not as the suggestion is using a base acceptable threshold to determine how much edge you should have for each stat category.')
369
- st.warning('This model is currently down for maintence and will be back up soon! use the Player Prop Simulations if you wish to check on specific props.')
370
- if st.button("Reset Data/Load Data", key='reset5'):
371
  st.cache_data.clear()
372
  game_model, raw_baselines, player_stats, prop_frame, pick_frame, timestamp = init_baselines()
373
  t_stamp = f"Last Update: " + str(timestamp) + f" CST"
@@ -380,11 +380,11 @@ with tab5:
380
  export_container = st.empty()
381
 
382
  with col1:
383
- game_select_var = st.selectbox('Select prop source', options = ['Draftkings', 'Pick6'])
384
- if game_select_var == 'Draftkings':
385
- prop_df = prop_frame[['Player', 'over_prop', 'over_line', 'under_line', 'prop_type']]
386
  elif game_select_var == 'Pick6':
387
- prop_df = pick_frame[['Full_name', 'over_prop', 'over_line', 'under_line', 'prop_type']]
388
  prop_df.rename(columns={"Full_name": "Player"}, inplace = True)
389
  st.download_button(
390
  label="Download Prop Source",
@@ -393,62 +393,235 @@ with tab5:
393
  mime='text/csv',
394
  key='prop_source',
395
  )
396
- prop_type_var = st.selectbox('Select prop category', options = ['All Props', 'points', 'rebounds', 'assists', 'threes', 'PRA', 'points+rebounds',
397
- 'points+assists', 'rebounds+assists'])
398
- if prop_type_var == 'All Props':
399
- st.info('please note that the All Props run can take some time, you will see progress as tables show up in the sim area to the right')
400
 
401
  if st.button('Simulate Prop Category'):
402
  with col2:
 
403
  with df_hold_container.container():
404
  if prop_type_var == 'All Props':
405
  for prop in all_sim_vars:
406
 
407
- if game_select_var == 'Draftkings':
408
- prop_df = prop_frame[['Player', 'over_prop', 'over_line', 'under_line', 'prop_type']]
409
  elif game_select_var == 'Pick6':
410
- prop_df = pick_frame[['Full_name', 'over_prop', 'over_line', 'under_line', 'prop_type']]
411
- prop_df.rename(columns={"Full_name": "Player"}, inplace = True)
412
- prop_df = prop_df.loc[prop_df['prop_type'] == prop]
413
- prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
414
- prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
415
- prop_df = prop_df.loc[prop_df['Prop'] != 0]
416
- st.table(prop_df)
417
- prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
418
- prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
419
- df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
 
421
  prop_dict = dict(zip(df.Player, df.Prop))
 
422
  over_dict = dict(zip(df.Player, df.Over))
 
423
  under_dict = dict(zip(df.Player, df.Under))
424
 
425
- total_sims = 5000
426
 
427
  df.replace("", 0, inplace=True)
428
-
429
- if prop == 'points':
430
  df['Median'] = df['Points']
431
- elif prop == 'rebounds':
432
  df['Median'] = df['Rebounds']
433
- elif prop == 'assists':
434
  df['Median'] = df['Assists']
435
- elif prop == 'threes':
436
  df['Median'] = df['3P']
437
- elif prop == 'PRA':
438
- df['Median'] = df['Points'] + df['Rebounds'] + df['Assists']
439
- elif prop == 'points+rebounds':
440
  df['Median'] = df['Points'] + df['Rebounds']
441
- elif prop == 'points+assists':
442
  df['Median'] = df['Points'] + df['Assists']
443
- elif prop == 'rebounds+assists':
444
- df['Median'] = df['Assists'] + df['Rebounds']
445
-
446
  flex_file = df
447
- flex_file['Floor'] = (flex_file['Median'] * .25) + (flex_file['Minutes'] * .25)
448
- flex_file['Ceiling'] = flex_file['Median'] + 10 + (flex_file['Minutes'] * .25)
449
- flex_file['STD'] = (flex_file['Median']/4)
450
  flex_file['Prop'] = flex_file['Player'].map(prop_dict)
451
- flex_file = flex_file[['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD']]
452
 
453
  hold_file = flex_file
454
  overall_file = flex_file
@@ -459,12 +632,12 @@ with tab5:
459
  for x in range(0,total_sims):
460
  prop_file[x] = prop_file['Prop']
461
 
462
- prop_file = prop_file.drop(['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
463
 
464
  for x in range(0,total_sims):
465
  overall_file[x] = np.random.normal(overall_file['Median'],overall_file['STD'])
466
 
467
- overall_file=overall_file.drop(['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
468
 
469
  players_only = hold_file[['Player']]
470
 
@@ -481,6 +654,7 @@ with tab5:
481
  players_only['Under'] = prop_check[prop_check < 0].count(axis=1)/float(total_sims)
482
  players_only['Imp Under'] = players_only['Player'].map(under_dict)
483
  players_only['Under%'] = players_only[["Under", "Imp Under"]].mean(axis=1)
 
484
  players_only['Prop'] = players_only['Player'].map(prop_dict)
485
  players_only['Prop_avg'] = players_only['Prop'].mean() / 100
486
  players_only['prop_threshold'] = .10
@@ -491,174 +665,17 @@ with tab5:
491
  players_only['Bet_suggest'] = np.where(players_only['Over_diff'] > players_only['Under_diff'], "Over" , "Under")
492
  players_only['Bet?'] = np.where(players_only['Bet_check'] >= players_only['prop_threshold'], players_only['Bet_suggest'], "No Bet")
493
  players_only['Edge'] = players_only['Bet_check']
494
- players_only['Prop type'] = prop
495
 
496
  players_only['Player'] = hold_file[['Player']]
 
497
 
498
- leg_outcomes = players_only[['Player', 'Prop type', 'Prop', 'Mean_Outcome', 'Imp Over', 'Over%', 'Imp Under', 'Under%', 'Bet?', 'Edge']]
499
-
500
  sim_all_hold = pd.concat([sim_all_hold, leg_outcomes], ignore_index=True)
501
 
502
  final_outcomes = sim_all_hold
503
-
504
- elif prop_type_var != 'All Props':
505
- if game_select_var == 'Draftkings':
506
- prop_df = prop_frame[['Player', 'over_prop', 'over_line', 'under_line', 'prop_type']]
507
- elif game_select_var == 'Pick6':
508
- prop_df = pick_frame[['Full_name', 'over_prop', 'over_line', 'under_line', 'prop_type']]
509
- prop_df.rename(columns={"Full_name": "Player"}, inplace = True)
510
- if prop_type_var == "points":
511
- prop_df = prop_df.loc[prop_df['prop_type'] == 'points']
512
- prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
513
- prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
514
- prop_df = prop_df.loc[prop_df['Prop'] != 0]
515
- st.table(prop_df)
516
- prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
517
- prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
518
- df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
519
- elif prop_type_var == "rebounds":
520
- prop_df = prop_df.loc[prop_df['prop_type'] == 'rebounds']
521
- prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
522
- prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
523
- prop_df = prop_df.loc[prop_df['Prop'] != 0]
524
- st.table(prop_df)
525
- prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
526
- prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
527
- df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
528
- elif prop_type_var == "assists":
529
- prop_df = prop_df.loc[prop_df['prop_type'] == 'assists']
530
- prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
531
- prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
532
- prop_df = prop_df.loc[prop_df['Prop'] != 0]
533
- st.table(prop_df)
534
- prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
535
- prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
536
- df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
537
- elif prop_type_var == "threes":
538
- prop_df = prop_df.loc[prop_df['prop_type'] == 'threes']
539
- prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
540
- prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
541
- prop_df = prop_df.loc[prop_df['Prop'] != 0]
542
- st.table(prop_df)
543
- prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
544
- prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
545
- df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
546
- elif prop_type_var == "PRA":
547
- prop_df = prop_df.loc[prop_df['prop_type'] == 'PRA']
548
- prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
549
- prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
550
- prop_df = prop_df.loc[prop_df['Prop'] != 0]
551
- st.table(prop_df)
552
- prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
553
- prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
554
- df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
555
- elif prop_type_var == "points+rebounds":
556
- prop_df = prop_df.loc[prop_df['prop_type'] == 'points+rebounds']
557
- prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
558
- prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
559
- prop_df = prop_df.loc[prop_df['Prop'] != 0]
560
- st.table(prop_df)
561
- prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
562
- prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
563
- df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
564
- elif prop_type_var == "points+assists":
565
- prop_df = prop_df.loc[prop_df['prop_type'] == 'points+assists']
566
- prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
567
- prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
568
- prop_df = prop_df.loc[prop_df['Prop'] != 0]
569
- st.table(prop_df)
570
- prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
571
- prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
572
- df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
573
- elif prop_type_var == "rebounds+assists":
574
- prop_df = prop_df.loc[prop_df['prop_type'] == 'rebounds+assists']
575
- prop_df = prop_df[['Player', 'over_prop', 'over_line', 'under_line']]
576
- prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
577
- prop_df = prop_df.loc[prop_df['Prop'] != 0]
578
- st.table(prop_df)
579
- prop_df['Over'] = np.where(prop_df['over_line'] < 0, (-(prop_df['over_line'])/((-(prop_df['over_line']))+101)), 101/(prop_df['over_line']+101))
580
- prop_df['Under'] = np.where(prop_df['under_line'] < 0, (-(prop_df['under_line'])/((-(prop_df['under_line']))+101)), 101/(prop_df['under_line']+101))
581
- df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
582
-
583
- prop_dict = dict(zip(df.Player, df.Prop))
584
- over_dict = dict(zip(df.Player, df.Over))
585
- under_dict = dict(zip(df.Player, df.Under))
586
-
587
- total_sims = 5000
588
-
589
- df.replace("", 0, inplace=True)
590
-
591
- if prop_type_var == 'points':
592
- df['Median'] = df['Points']
593
- elif prop_type_var == 'rebounds':
594
- df['Median'] = df['Rebounds']
595
- elif prop_type_var == 'assists':
596
- df['Median'] = df['Assists']
597
- elif prop_type_var == 'threes':
598
- df['Median'] = df['3P']
599
- elif prop_type_var == 'PRA':
600
- df['Median'] = df['Points'] + df['Rebounds'] + df['Assists']
601
- elif prop_type_var == 'points+rebounds':
602
- df['Median'] = df['Points'] + df['Rebounds']
603
- elif prop_type_var == 'points+assists':
604
- df['Median'] = df['Points'] + df['Assists']
605
- elif prop_type_var == 'rebounds+assists':
606
- df['Median'] = df['Assists'] + df['Rebounds']
607
-
608
- flex_file = df
609
- flex_file['Floor'] = (flex_file['Median'] * .25) + (flex_file['Minutes'] * .25)
610
- flex_file['Ceiling'] = flex_file['Median'] + 10 + (flex_file['Minutes'] * .25)
611
- flex_file['STD'] = (flex_file['Median']/4)
612
- flex_file['Prop'] = flex_file['Player'].map(prop_dict)
613
- flex_file = flex_file[['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD']]
614
-
615
- hold_file = flex_file
616
- overall_file = flex_file
617
- prop_file = flex_file
618
-
619
- overall_players = overall_file[['Player']]
620
-
621
- for x in range(0,total_sims):
622
- prop_file[x] = prop_file['Prop']
623
-
624
- prop_file = prop_file.drop(['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
625
-
626
- for x in range(0,total_sims):
627
- overall_file[x] = np.random.normal(overall_file['Median'],overall_file['STD'])
628
-
629
- overall_file=overall_file.drop(['Player', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
630
-
631
- players_only = hold_file[['Player']]
632
-
633
- player_outcomes = pd.merge(players_only, overall_file, left_index=True, right_index=True)
634
-
635
- prop_check = (overall_file - prop_file)
636
-
637
- players_only['Mean_Outcome'] = overall_file.mean(axis=1)
638
- players_only['10%'] = overall_file.quantile(0.1, axis=1)
639
- players_only['90%'] = overall_file.quantile(0.9, axis=1)
640
- players_only['Over'] = prop_check[prop_check > 0].count(axis=1)/float(total_sims)
641
- players_only['Imp Over'] = players_only['Player'].map(over_dict)
642
- players_only['Over%'] = players_only[["Over", "Imp Over"]].mean(axis=1)
643
- players_only['Under'] = prop_check[prop_check < 0].count(axis=1)/float(total_sims)
644
- players_only['Imp Under'] = players_only['Player'].map(under_dict)
645
- players_only['Under%'] = players_only[["Under", "Imp Under"]].mean(axis=1)
646
- players_only['Prop'] = players_only['Player'].map(prop_dict)
647
- players_only['Prop_avg'] = players_only['Prop'].mean() / 100
648
- players_only['prop_threshold'] = .10
649
- players_only = players_only.loc[players_only['Mean_Outcome'] > 0]
650
- players_only['Over_diff'] = players_only['Over%'] - players_only['Imp Over']
651
- players_only['Under_diff'] = players_only['Under%'] - players_only['Imp Under']
652
- players_only['Bet_check'] = np.where(players_only['Over_diff'] > players_only['Under_diff'], players_only['Over_diff'] , players_only['Under_diff'])
653
- players_only['Bet_suggest'] = np.where(players_only['Over_diff'] > players_only['Under_diff'], "Over" , "Under")
654
- players_only['Bet?'] = np.where(players_only['Bet_check'] >= players_only['prop_threshold'], players_only['Bet_suggest'], "No Bet")
655
- players_only['Edge'] = players_only['Bet_check']
656
-
657
- players_only['Player'] = hold_file[['Player']]
658
-
659
- final_outcomes = players_only[['Player', 'Prop', 'Mean_Outcome', 'Imp Over', 'Over%', 'Imp Under', 'Under%', 'Bet?', 'Edge']]
660
 
661
- final_outcomes = final_outcomes[final_outcomes['Prop'] > 0]
662
  final_outcomes = final_outcomes.sort_values(by='Edge', ascending=False)
663
 
664
  with df_hold_container:
@@ -669,34 +686,7 @@ with tab5:
669
  st.download_button(
670
  label="Export Projections",
671
  data=convert_df_to_csv(final_outcomes),
672
- file_name='Nba_prop_proj.csv',
673
  mime='text/csv',
674
  key='prop_proj',
675
- )
676
- with tab6:
677
- st.info(t_stamp)
678
- if st.button("Reset Data", key='reset6'):
679
- st.cache_data.clear()
680
- game_model, raw_baselines, player_stats, prop_frame, pick_frame, timestamp = init_baselines()
681
- t_stamp = f"Last Update: " + str(timestamp) + f" CST"
682
- split_var6 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var6')
683
- if split_var6 == 'Specific Teams':
684
- team_var6 = st.multiselect('Which teams would you like to include in the tables?', options = player_stats['Team'].unique(), key='team_var6')
685
- elif split_var6 == 'All':
686
- team_var6 = player_stats.Team.values.tolist()
687
- raw_stats_disp = raw_baselines[raw_baselines['Team'].isin(team_var6)]
688
- st.header("Baselines to adjust")
689
- editable_df = st.data_editor(
690
- raw_stats_disp,
691
- key="data",
692
- hide_index=True,
693
- use_container_width = True
694
- )
695
- st.header("Customized Projections")
696
- st.dataframe(add_column(editable_df).style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(precision=2), use_container_width = True)
697
- st.download_button(
698
- label="Export Customizable Model",
699
- data=convert_df_to_csv(player_stats),
700
- file_name='NBA_stats_export.csv',
701
- mime='text/csv',
702
- )
 
98
  worksheet = sh.worksheet('DK_Build_Up')
99
  raw_display = pd.DataFrame(worksheet.get_all_records())
100
  raw_display.replace('', np.nan, inplace=True)
101
+ raw_display = raw_display.rename(columns={"Name": "Player"})
102
 
103
  raw_baselines = raw_display[['Player', 'Position', 'Team', 'Opp', 'Minutes', 'FGM', 'FGA', 'FG2M', 'FG2A', 'Threes', 'FG3A', 'FTM', 'FTA', 'TRB', 'AST', 'STL', 'BLK', 'TOV']]
104
  raw_baselines = raw_baselines[raw_baselines['Minutes'] > 0]
 
119
  worksheet = sh.worksheet('Prop_Frame')
120
  raw_display = pd.DataFrame(worksheet.get_all_records())
121
  raw_display.replace('', np.nan, inplace=True)
122
+ raw_display = raw_display.rename(columns={"Name": "Player", "OddsType": "book", "PropType": "prop_type"})
123
+ prop_frame = prop_frame.dropna(subset='Player')
124
 
125
  worksheet = sh.worksheet('Pick6_ingest')
126
  raw_display = pd.DataFrame(worksheet.get_all_records())
127
  raw_display.replace('', np.nan, inplace=True)
128
  pick_frame = raw_display.dropna(subset='Player')
129
 
130
+ prop_frame['Player'].replace(['Jaren Jackson', 'Nic Claxton', 'Jabari Smith', 'Lu Dort', 'Moe Wagner', 'Kyle Kuzma', 'Trey Murphy', 'Cameron Thomas'],
131
  ['Jaren Jackson Jr.', 'Nicolas Claxton', 'Jabari Smith Jr.', 'Luguentz Dort', 'Moritz Wagner', 'Kyle Kuzma Jr.',
132
  'Trey Murphy III', 'Cam Thomas'], inplace=True)
133
  pick_frame['Player'].replace(['Jaren Jackson', 'Nic Claxton', 'Jabari Smith', 'Lu Dort', 'Moe Wagner', 'Kyle Kuzma', 'Trey Murphy', 'Cameron Thomas'],
 
204
  team_var5 = player_stats.Team.values.tolist()
205
  book_split5 = st.radio("Would you like to view all books or specific ones?", ('All', 'Specific Books'), key='book_split5')
206
  if book_split5 == 'Specific Books':
207
+ book_var5 = st.multiselect('Which books would you like to include in the tables?', options = prop_frame['book'].unique(), key='book_var5')
208
  elif book_split5 == 'All':
209
+ book_var5 = prop_frame.book.values.tolist()
210
  prop_type_var2 = st.selectbox('Select type of prop are you wanting to view', options = prop_table_options)
211
  prop_frame_disp = prop_frame[prop_frame['Team'].isin(team_var5)]
212
+ prop_frame_disp = prop_frame_disp[prop_frame_disp['book'].isin(book_var5)]
213
+ prop_frame_disp = prop_frame_disp[prop_frame_disp['prop_type'] == prop_type_var2]
214
  prop_frame_disp = prop_frame_disp.sort_values(by='Trending Over', ascending=False)
215
  st.dataframe(prop_frame_disp.style.background_gradient(axis=0).background_gradient(cmap='RdYlGn').format(prop_format, precision=2), use_container_width = True)
216
  st.download_button(
 
366
 
367
  with tab5:
368
  st.info(t_stamp)
369
+ st.info('The Over and Under percentages are a compositve percentage based on simulations, historical performance, and implied probabilities, and may be different than you would expect based purely on the median projection. Likewise, the Edge of a bet is not the only indicator of if you should make the bet or not as the suggestion is using a base acceptable threshold to determine how much edge you should have for each stat category.')
370
+ if st.button("Reset Data/Load Data", key='reset6'):
 
371
  st.cache_data.clear()
372
  game_model, raw_baselines, player_stats, prop_frame, pick_frame, timestamp = init_baselines()
373
  t_stamp = f"Last Update: " + str(timestamp) + f" CST"
 
380
  export_container = st.empty()
381
 
382
  with col1:
383
+ game_select_var = st.selectbox('Select prop source', options = ['Aggregate', 'Pick6'])
384
+ if game_select_var == 'Aggregate':
385
+ prop_df = prop_frame[['Player', 'book', 'over_prop', 'over_line', 'under_line', 'prop_type']]
386
  elif game_select_var == 'Pick6':
387
+ prop_df = pick_frame[['Full_name', 'book', 'over_prop', 'over_line', 'under_line', 'prop_type']]
388
  prop_df.rename(columns={"Full_name": "Player"}, inplace = True)
389
  st.download_button(
390
  label="Download Prop Source",
 
393
  mime='text/csv',
394
  key='prop_source',
395
  )
396
+ prop_type_var = st.selectbox('Select prop category', options = ['All Props', 'NBA_GAME_PLAYER_POINTS', 'NBA_GAME_PLAYER_REBOUNDS', 'NBA_GAME_PLAYER_ASSISTS', 'NBA_GAME_PLAYER_3_POINTERS_MADE', 'NBA_GAME_PLAYER_POINTS_REBOUNDS_ASSISTS', 'NBA_GAME_PLAYER_POINTS_REBOUNDS', 'NBA_GAME_PLAYER_POINTS_ASSISTS', 'NBA_GAME_PLAYER_REBOUNDS_ASSISTS'])
 
 
 
397
 
398
  if st.button('Simulate Prop Category'):
399
  with col2:
400
+
401
  with df_hold_container.container():
402
  if prop_type_var == 'All Props':
403
  for prop in all_sim_vars:
404
 
405
+ if game_select_var == 'Aggregate':
406
+ prop_df_raw = prop_frame[['Player', 'book', 'over_prop', 'over_line', 'under_line', 'prop_type']]
407
  elif game_select_var == 'Pick6':
408
+ prop_df_raw = pick_frame[['Full_name', 'book', 'over_prop', 'over_line', 'under_line', 'prop_type']]
409
+ prop_df_raw.rename(columns={"Full_name": "Player"}, inplace = True)
410
+
411
+ for books in ['FANDUEL', 'DRAFTKINGS', 'BET365', 'CONSENSUS']:
412
+ prop_df = prop_df_raw.loc[prop_df_raw['book'] == books]
413
+ prop_df = prop_df.loc[prop_df['prop_type'] == prop]
414
+ prop_df = prop_df[['Player', 'book', 'over_prop', 'over_line', 'under_line']]
415
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
416
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
417
+ st.table(prop_df)
418
+ prop_df['Over'] = 1 / prop_df['over_line']
419
+ prop_df['Under'] = 1 / prop_df['under_line']
420
+ df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
421
+
422
+ prop_dict = dict(zip(df.Player, df.Prop))
423
+ team_dict = dict(zip(df.Player, df.Team))
424
+ book_dict = dict(zip(df.Player, df.book))
425
+ over_dict = dict(zip(df.Player, df.Over))
426
+ under_dict = dict(zip(df.Player, df.Under))
427
+
428
+ total_sims = 1000
429
+
430
+ df.replace("", 0, inplace=True)
431
+
432
+ if prop == "NBA_GAME_PLAYER_POINTS":
433
+ df['Median'] = df['Points']
434
+ elif prop == "NBA_GAME_PLAYER_REBOUNDS":
435
+ df['Median'] = df['Rebounds']
436
+ elif prop == "NBA_GAME_PLAYER_ASSISTS":
437
+ df['Median'] = df['Assists']
438
+ elif prop == "NBA_GAME_PLAYER_3_POINTERS_MADE":
439
+ df['Median'] = df['3P']
440
+ elif prop == "NBA_GAME_PLAYER_POINTS_REBOUNDS_ASSISTS":
441
+ df['Median'] = df['PRA']
442
+ elif prop == "NBA_GAME_PLAYER_POINTS_REBOUNDS":
443
+ df['Median'] = df['Points'] + df['Rebounds']
444
+ elif prop == "NBA_GAME_PLAYER_POINTS_ASSISTS":
445
+ df['Median'] = df['Points'] + df['Assists']
446
+ elif prop == "NBA_GAME_PLAYER_REBOUNDS_ASSISTS":
447
+ df['Median'] = df['Rebounds'] + df['Assists']
448
+
449
+ flex_file = df
450
+ flex_file['Floor'] = flex_file['Median'] * .25
451
+ flex_file['Ceiling'] = flex_file['Median'] + (flex_file['Median'] * 1.75)
452
+ flex_file['STD'] = flex_file['Median'] / 4
453
+ flex_file['Prop'] = flex_file['Player'].map(prop_dict)
454
+ flex_file = flex_file[['Player', 'book', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD']]
455
+
456
+ hold_file = flex_file
457
+ overall_file = flex_file
458
+ prop_file = flex_file
459
+
460
+ overall_players = overall_file[['Player']]
461
+
462
+ for x in range(0,total_sims):
463
+ prop_file[x] = prop_file['Prop']
464
+
465
+ prop_file = prop_file.drop(['Player', 'book', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
466
+
467
+ for x in range(0,total_sims):
468
+ overall_file[x] = np.random.normal(overall_file['Median'],overall_file['STD'])
469
+
470
+ overall_file=overall_file.drop(['Player', 'book', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
471
+
472
+ players_only = hold_file[['Player']]
473
+
474
+ player_outcomes = pd.merge(players_only, overall_file, left_index=True, right_index=True)
475
+
476
+ prop_check = (overall_file - prop_file)
477
+
478
+ players_only['Mean_Outcome'] = overall_file.mean(axis=1)
479
+ players_only['10%'] = overall_file.quantile(0.1, axis=1)
480
+ players_only['90%'] = overall_file.quantile(0.9, axis=1)
481
+ players_only['Over'] = prop_check[prop_check > 0].count(axis=1)/float(total_sims)
482
+ players_only['Imp Over'] = players_only['Player'].map(over_dict)
483
+ players_only['Over%'] = players_only[["Over", "Imp Over"]].mean(axis=1)
484
+ players_only['Under'] = prop_check[prop_check < 0].count(axis=1)/float(total_sims)
485
+ players_only['Imp Under'] = players_only['Player'].map(under_dict)
486
+ players_only['Under%'] = players_only[["Under", "Imp Under"]].mean(axis=1)
487
+ players_only['Prop'] = players_only['Player'].map(prop_dict)
488
+ players_only['Book'] = players_only['Player'].map(book_dict)
489
+ players_only['Prop_avg'] = players_only['Prop'].mean() / 100
490
+ players_only['prop_threshold'] = .10
491
+ players_only = players_only.loc[players_only['Mean_Outcome'] > 0]
492
+ players_only['Over_diff'] = players_only['Over%'] - players_only['Imp Over']
493
+ players_only['Under_diff'] = players_only['Under%'] - players_only['Imp Under']
494
+ players_only['Bet_check'] = np.where(players_only['Over_diff'] > players_only['Under_diff'], players_only['Over_diff'] , players_only['Under_diff'])
495
+ players_only['Bet_suggest'] = np.where(players_only['Over_diff'] > players_only['Under_diff'], "Over" , "Under")
496
+ players_only['Bet?'] = np.where(players_only['Bet_check'] >= players_only['prop_threshold'], players_only['Bet_suggest'], "No Bet")
497
+ players_only['Edge'] = players_only['Bet_check']
498
+ players_only['Prop Type'] = prop
499
+
500
+ players_only['Player'] = hold_file[['Player']]
501
+ players_only['Team'] = players_only['Player'].map(team_dict)
502
+
503
+ leg_outcomes = players_only[['Player', 'Team', 'Book', 'Prop Type', 'Prop', 'Mean_Outcome', 'Imp Over', 'Over%', 'Imp Under', 'Under%', 'Bet?', 'Edge']]
504
+ sim_all_hold = pd.concat([sim_all_hold, leg_outcomes], ignore_index=True)
505
+
506
+ final_outcomes = sim_all_hold
507
+
508
+ elif prop_type_var != 'All Props':
509
+
510
+
511
+ if game_select_var == 'Aggregate':
512
+ prop_df_raw = prop_frame[['Player', 'book', 'over_prop', 'over_line', 'under_line', 'prop_type']]
513
+ elif game_select_var == 'Pick6':
514
+ prop_df_raw = pick_frame[['Full_name', 'book', 'over_prop', 'over_line', 'under_line', 'prop_type']]
515
+ prop_df_raw.rename(columns={"Full_name": "Player"}, inplace = True)
516
+
517
+ for books in ['FANDUEL', 'DRAFTKINGS', 'BET365', 'CONSENSUS']:
518
+ prop_df = prop_df_raw.loc[prop_df_raw['book'] == books]
519
+ if prop_type_var == "NBA_GAME_PLAYER_POINTS":
520
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'NBA_GAME_PLAYER_POINTS']
521
+ prop_df = prop_df[['Player', 'book', 'over_prop', 'over_line', 'under_line']]
522
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
523
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
524
+ st.table(prop_df)
525
+ prop_df['Over'] = 1 / prop_df['over_line']
526
+ prop_df['Under'] = 1 / prop_df['under_line']
527
+ df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
528
+ elif prop_type_var == "NBA_GAME_PLAYER_REBOUNDS":
529
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'NBA_GAME_PLAYER_REBOUNDS']
530
+ prop_df = prop_df[['Player', 'book', 'over_prop', 'over_line', 'under_line']]
531
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
532
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
533
+ st.table(prop_df)
534
+ prop_df['Over'] = 1 / prop_df['over_line']
535
+ prop_df['Under'] = 1 / prop_df['under_line']
536
+ df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
537
+ elif prop_type_var == "NBA_GAME_PLAYER_ASSISTS":
538
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'NBA_GAME_PLAYER_ASSISTS']
539
+ prop_df = prop_df[['Player', 'book', 'over_prop', 'over_line', 'under_line']]
540
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
541
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
542
+ st.table(prop_df)
543
+ prop_df['Over'] = 1 / prop_df['over_line']
544
+ prop_df['Under'] = 1 / prop_df['under_line']
545
+ df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
546
+ elif prop_type_var == "NBA_GAME_PLAYER_3_POINTERS_MADE":
547
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'NBA_GAME_PLAYER_3_POINTERS_MADE']
548
+ prop_df = prop_df[['Player', 'book', 'over_prop', 'over_line', 'under_line']]
549
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
550
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
551
+ st.table(prop_df)
552
+ prop_df['Over'] = 1 / prop_df['over_line']
553
+ prop_df['Under'] = 1 / prop_df['under_line']
554
+ df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
555
+ elif prop_type_var == "NBA_GAME_PLAYER_POINTS_REBOUNDS_ASSISTS":
556
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'NBA_GAME_PLAYER_POINTS_REBOUNDS_ASSISTS']
557
+ prop_df = prop_df[['Player', 'book', 'over_prop', 'over_line', 'under_line']]
558
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
559
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
560
+ st.table(prop_df)
561
+ prop_df['Over'] = 1 / prop_df['over_line']
562
+ prop_df['Under'] = 1 / prop_df['under_line']
563
+ df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
564
+ elif prop_type_var == "NBA_GAME_PLAYER_POINTS_REBOUNDS":
565
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'NBA_GAME_PLAYER_POINTS_REBOUNDS']
566
+ prop_df = prop_df[['Player', 'book', 'over_prop', 'over_line', 'under_line']]
567
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
568
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
569
+ st.table(prop_df)
570
+ prop_df['Over'] = 1 / prop_df['over_line']
571
+ prop_df['Under'] = 1 / prop_df['under_line']
572
+ df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
573
+ elif prop_type_var == "NBA_GAME_PLAYER_POINTS_ASSISTS":
574
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'NBA_GAME_PLAYER_POINTS_ASSISTS']
575
+ prop_df = prop_df[['Player', 'book', 'over_prop', 'over_line', 'under_line']]
576
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
577
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
578
+ st.table(prop_df)
579
+ prop_df['Over'] = 1 / prop_df['over_line']
580
+ prop_df['Under'] = 1 / prop_df['under_line']
581
+ df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
582
+ elif prop_type_var == "NBA_GAME_PLAYER_REBOUNDS_ASSISTS":
583
+ prop_df = prop_df.loc[prop_df['prop_type'] == 'NBA_GAME_PLAYER_REBOUNDS_ASSISTS']
584
+ prop_df = prop_df[['Player', 'book', 'over_prop', 'over_line', 'under_line']]
585
+ prop_df.rename(columns={"over_prop": "Prop"}, inplace = True)
586
+ prop_df = prop_df.loc[prop_df['Prop'] != 0]
587
+ st.table(prop_df)
588
+ prop_df['Over'] = 1 / prop_df['over_line']
589
+ prop_df['Under'] = 1 / prop_df['under_line']
590
+ df = pd.merge(player_stats, prop_df, how='left', left_on=['Player'], right_on = ['Player'])
591
 
592
  prop_dict = dict(zip(df.Player, df.Prop))
593
+ book_dict = dict(zip(df.Player, df.book))
594
  over_dict = dict(zip(df.Player, df.Over))
595
+ team_dict = dict(zip(df.Player, df.Team))
596
  under_dict = dict(zip(df.Player, df.Under))
597
 
598
+ total_sims = 1000
599
 
600
  df.replace("", 0, inplace=True)
601
+
602
+ if prop_type_var == "NBA_GAME_PLAYER_POINTS":
603
  df['Median'] = df['Points']
604
+ elif prop_type_var == "NBA_GAME_PLAYER_REBOUNDS":
605
  df['Median'] = df['Rebounds']
606
+ elif prop_type_var == "NBA_GAME_PLAYER_ASSISTS":
607
  df['Median'] = df['Assists']
608
+ elif prop_type_var == "NBA_GAME_PLAYER_3_POINTERS_MADE":
609
  df['Median'] = df['3P']
610
+ elif prop_type_var == "NBA_GAME_PLAYER_POINTS_REBOUNDS_ASSISTS":
611
+ df['Median'] = df['PRA']
612
+ elif prop_type_var == "NBA_GAME_PLAYER_POINTS_REBOUNDS":
613
  df['Median'] = df['Points'] + df['Rebounds']
614
+ elif prop_type_var == "NBA_GAME_PLAYER_POINTS_ASSISTS":
615
  df['Median'] = df['Points'] + df['Assists']
616
+ elif prop_type_var == "NBA_GAME_PLAYER_REBOUNDS_ASSISTS":
617
+ df['Median'] = df['Rebounds'] + df['Assists']
618
+
619
  flex_file = df
620
+ flex_file['Floor'] = flex_file['Median'] * .25
621
+ flex_file['Ceiling'] = flex_file['Median'] + (flex_file['Median'] * 1.75)
622
+ flex_file['STD'] = flex_file['Median'] / 4
623
  flex_file['Prop'] = flex_file['Player'].map(prop_dict)
624
+ flex_file = flex_file[['Player', 'book', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD']]
625
 
626
  hold_file = flex_file
627
  overall_file = flex_file
 
632
  for x in range(0,total_sims):
633
  prop_file[x] = prop_file['Prop']
634
 
635
+ prop_file = prop_file.drop(['Player', 'book', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
636
 
637
  for x in range(0,total_sims):
638
  overall_file[x] = np.random.normal(overall_file['Median'],overall_file['STD'])
639
 
640
+ overall_file=overall_file.drop(['Player', 'book', 'Prop', 'Floor', 'Median', 'Ceiling', 'STD'], axis=1)
641
 
642
  players_only = hold_file[['Player']]
643
 
 
654
  players_only['Under'] = prop_check[prop_check < 0].count(axis=1)/float(total_sims)
655
  players_only['Imp Under'] = players_only['Player'].map(under_dict)
656
  players_only['Under%'] = players_only[["Under", "Imp Under"]].mean(axis=1)
657
+ players_only['Book'] = players_only['Player'].map(book_dict)
658
  players_only['Prop'] = players_only['Player'].map(prop_dict)
659
  players_only['Prop_avg'] = players_only['Prop'].mean() / 100
660
  players_only['prop_threshold'] = .10
 
665
  players_only['Bet_suggest'] = np.where(players_only['Over_diff'] > players_only['Under_diff'], "Over" , "Under")
666
  players_only['Bet?'] = np.where(players_only['Bet_check'] >= players_only['prop_threshold'], players_only['Bet_suggest'], "No Bet")
667
  players_only['Edge'] = players_only['Bet_check']
668
+ players_only['Prop Type'] = prop_type_var
669
 
670
  players_only['Player'] = hold_file[['Player']]
671
+ players_only['Team'] = players_only['Player'].map(team_dict)
672
 
673
+ leg_outcomes = players_only[['Player', 'Team', 'Book', 'Prop Type', 'Prop', 'Mean_Outcome', 'Imp Over', 'Over%', 'Imp Under', 'Under%', 'Bet?', 'Edge']]
 
674
  sim_all_hold = pd.concat([sim_all_hold, leg_outcomes], ignore_index=True)
675
 
676
  final_outcomes = sim_all_hold
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
677
 
678
+ final_outcomes = final_outcomes.dropna()
679
  final_outcomes = final_outcomes.sort_values(by='Edge', ascending=False)
680
 
681
  with df_hold_container:
 
686
  st.download_button(
687
  label="Export Projections",
688
  data=convert_df_to_csv(final_outcomes),
689
+ file_name='NBA_prop_proj.csv',
690
  mime='text/csv',
691
  key='prop_proj',
692
+ )