Spaces:
Sleeping
Sleeping
James McCool
commited on
Commit
·
9594423
1
Parent(s):
f32fab3
added poisson math to stat sims
Browse files
app.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
import numpy as np
|
|
|
|
| 3 |
import pandas as pd
|
| 4 |
import gspread
|
| 5 |
import plotly.express as px
|
|
|
|
| 6 |
st.set_page_config(layout="wide")
|
| 7 |
|
| 8 |
@st.cache_resource
|
|
@@ -47,6 +49,13 @@ gcservice_account, gcservice_account2, NFL_Data = init_conn()
|
|
| 47 |
game_format = {'Win%': '{:.2%}', 'Vegas': '{:.2%}', 'Win% Diff': '{:.2%}'}
|
| 48 |
american_format = {'First Inning Lead Percentage': '{:.2%}', 'Fifth Inning Lead Percentage': '{:.2%}'}
|
| 49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
@st.cache_resource(ttl=600)
|
| 51 |
def init_baselines():
|
| 52 |
sh = gcservice_account.open_by_url(NFL_Data)
|
|
@@ -83,7 +92,9 @@ def init_baselines():
|
|
| 83 |
|
| 84 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 85 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
|
|
|
| 86 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
|
|
|
| 87 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 88 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 89 |
|
|
@@ -107,7 +118,9 @@ with tab1:
|
|
| 107 |
st.cache_data.clear()
|
| 108 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 109 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
|
|
|
| 110 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
|
|
|
| 111 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 112 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 113 |
line_var1 = st.radio('How would you like to display odds?', options = ['Percentage', 'American'], key='line_var1')
|
|
@@ -166,7 +179,9 @@ with tab3:
|
|
| 166 |
st.cache_data.clear()
|
| 167 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 168 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
|
|
|
| 169 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
|
|
|
| 170 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 171 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 172 |
split_var2 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var2')
|
|
@@ -192,7 +207,9 @@ with tab4:
|
|
| 192 |
st.cache_data.clear()
|
| 193 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 194 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
|
|
|
| 195 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
|
|
|
| 196 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 197 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 198 |
split_var5 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var5')
|
|
@@ -221,7 +238,9 @@ with tab5:
|
|
| 221 |
st.cache_data.clear()
|
| 222 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 223 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
|
|
|
| 224 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
|
|
|
| 225 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 226 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 227 |
col1, col2 = st.columns([1, 5])
|
|
@@ -317,12 +336,14 @@ with tab5:
|
|
| 317 |
player_outcomes = pd.merge(players_only, overall_file, left_index=True, right_index=True)
|
| 318 |
|
| 319 |
players_only['Mean_Outcome'] = overall_file.mean(axis=1)
|
|
|
|
|
|
|
| 320 |
players_only['10%'] = overall_file.quantile(0.1, axis=1)
|
| 321 |
players_only['90%'] = overall_file.quantile(0.9, axis=1)
|
| 322 |
if ou_var == 'Over':
|
| 323 |
-
players_only['beat_prop'] = overall_file[overall_file > prop_var].count(axis=1)/float(total_sims)
|
| 324 |
elif ou_var == 'Under':
|
| 325 |
-
players_only['beat_prop'] = (overall_file[overall_file < prop_var].count(axis=1)/float(total_sims))
|
| 326 |
|
| 327 |
players_only['implied_odds'] = np.where(line_var <= 0, (-(line_var)/((-(line_var))+100)), 100/(line_var+100))
|
| 328 |
|
|
@@ -368,7 +389,9 @@ with tab6:
|
|
| 368 |
st.cache_data.clear()
|
| 369 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 370 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
|
|
|
| 371 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
|
|
|
| 372 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 373 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 374 |
col1, col2 = st.columns([1, 5])
|
|
@@ -499,16 +522,17 @@ with tab6:
|
|
| 499 |
prop_check = (overall_file - prop_file)
|
| 500 |
|
| 501 |
players_only['Mean_Outcome'] = overall_file.mean(axis=1)
|
|
|
|
|
|
|
|
|
|
| 502 |
players_only['10%'] = overall_file.quantile(0.1, axis=1)
|
| 503 |
players_only['90%'] = overall_file.quantile(0.9, axis=1)
|
| 504 |
-
players_only['Over'] = prop_check[prop_check > 0].count(axis=1)/float(total_sims)
|
| 505 |
players_only['Imp Over'] = players_only['Player'].map(over_dict)
|
| 506 |
players_only['Over%'] = players_only[["Over", "Imp Over"]].mean(axis=1)
|
| 507 |
-
players_only['Under'] = prop_check[prop_check < 0].count(axis=1)/float(total_sims)
|
| 508 |
players_only['Imp Under'] = players_only['Player'].map(under_dict)
|
| 509 |
players_only['Under%'] = players_only[["Under", "Imp Under"]].mean(axis=1)
|
| 510 |
-
players_only['Prop'] = players_only['Player'].map(prop_dict)
|
| 511 |
-
players_only['Book'] = players_only['Player'].map(book_dict)
|
| 512 |
players_only['Prop_avg'] = players_only['Prop'].mean() / 100
|
| 513 |
players_only['prop_threshold'] = .10
|
| 514 |
players_only = players_only[players_only['Mean_Outcome'] > 0]
|
|
@@ -652,16 +676,17 @@ with tab6:
|
|
| 652 |
prop_check = (overall_file - prop_file)
|
| 653 |
|
| 654 |
players_only['Mean_Outcome'] = overall_file.mean(axis=1)
|
|
|
|
|
|
|
|
|
|
| 655 |
players_only['10%'] = overall_file.quantile(0.1, axis=1)
|
| 656 |
players_only['90%'] = overall_file.quantile(0.9, axis=1)
|
| 657 |
-
players_only['Over'] = prop_check[prop_check > 0].count(axis=1)/float(total_sims)
|
| 658 |
players_only['Imp Over'] = players_only['Player'].map(over_dict)
|
| 659 |
players_only['Over%'] = players_only[["Over", "Imp Over"]].mean(axis=1)
|
| 660 |
-
players_only['Under'] = prop_check[prop_check < 0].count(axis=1)/float(total_sims)
|
| 661 |
players_only['Imp Under'] = players_only['Player'].map(under_dict)
|
| 662 |
players_only['Under%'] = players_only[["Under", "Imp Under"]].mean(axis=1)
|
| 663 |
-
players_only['Book'] = players_only['Player'].map(book_dict)
|
| 664 |
-
players_only['Prop'] = players_only['Player'].map(prop_dict)
|
| 665 |
players_only['Prop_avg'] = players_only['Prop'].mean() / 100
|
| 666 |
players_only['prop_threshold'] = .10
|
| 667 |
players_only = players_only[players_only['Mean_Outcome'] > 0]
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
import numpy as np
|
| 3 |
+
from numpy import where as np_where
|
| 4 |
import pandas as pd
|
| 5 |
import gspread
|
| 6 |
import plotly.express as px
|
| 7 |
+
import scipy.stats as stats
|
| 8 |
st.set_page_config(layout="wide")
|
| 9 |
|
| 10 |
@st.cache_resource
|
|
|
|
| 49 |
game_format = {'Win%': '{:.2%}', 'Vegas': '{:.2%}', 'Win% Diff': '{:.2%}'}
|
| 50 |
american_format = {'First Inning Lead Percentage': '{:.2%}', 'Fifth Inning Lead Percentage': '{:.2%}'}
|
| 51 |
|
| 52 |
+
def calculate_poisson(row):
|
| 53 |
+
mean_val = row['Mean_Outcome']
|
| 54 |
+
threshold = row['Prop']
|
| 55 |
+
cdf_value = stats.poisson.cdf(threshold, mean_val)
|
| 56 |
+
probability = 1 - cdf_value
|
| 57 |
+
return probability
|
| 58 |
+
|
| 59 |
@st.cache_resource(ttl=600)
|
| 60 |
def init_baselines():
|
| 61 |
sh = gcservice_account.open_by_url(NFL_Data)
|
|
|
|
| 92 |
|
| 93 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 94 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
| 95 |
+
qb_stats = qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 96 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
| 97 |
+
non_qb_stats = non_qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 98 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 99 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 100 |
|
|
|
|
| 118 |
st.cache_data.clear()
|
| 119 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 120 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
| 121 |
+
qb_stats = qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 122 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
| 123 |
+
non_qb_stats = non_qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 124 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 125 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 126 |
line_var1 = st.radio('How would you like to display odds?', options = ['Percentage', 'American'], key='line_var1')
|
|
|
|
| 179 |
st.cache_data.clear()
|
| 180 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 181 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
| 182 |
+
qb_stats = qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 183 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
| 184 |
+
non_qb_stats = non_qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 185 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 186 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 187 |
split_var2 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var2')
|
|
|
|
| 207 |
st.cache_data.clear()
|
| 208 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 209 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
| 210 |
+
qb_stats = qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 211 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
| 212 |
+
non_qb_stats = non_qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 213 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 214 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 215 |
split_var5 = st.radio("Would you like to view all teams or specific ones?", ('All', 'Specific Teams'), key='split_var5')
|
|
|
|
| 238 |
st.cache_data.clear()
|
| 239 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 240 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
| 241 |
+
qb_stats = qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 242 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
| 243 |
+
non_qb_stats = non_qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 244 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 245 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 246 |
col1, col2 = st.columns([1, 5])
|
|
|
|
| 336 |
player_outcomes = pd.merge(players_only, overall_file, left_index=True, right_index=True)
|
| 337 |
|
| 338 |
players_only['Mean_Outcome'] = overall_file.mean(axis=1)
|
| 339 |
+
players_only['Prop'] = prop_var
|
| 340 |
+
players_only['poisson_var'] = players_only.apply(calculate_poisson, axis=1)
|
| 341 |
players_only['10%'] = overall_file.quantile(0.1, axis=1)
|
| 342 |
players_only['90%'] = overall_file.quantile(0.9, axis=1)
|
| 343 |
if ou_var == 'Over':
|
| 344 |
+
players_only['beat_prop'] = np.where(players_only['Prop'] <= 3, players_only['poisson_var'], overall_file[overall_file > prop_var].count(axis=1)/float(total_sims))
|
| 345 |
elif ou_var == 'Under':
|
| 346 |
+
players_only['beat_prop'] = np.where(players_only['Prop'] <= 3, 1 - players_only['poisson_var'], (overall_file[overall_file < prop_var].count(axis=1)/float(total_sims)))
|
| 347 |
|
| 348 |
players_only['implied_odds'] = np.where(line_var <= 0, (-(line_var)/((-(line_var))+100)), 100/(line_var+100))
|
| 349 |
|
|
|
|
| 389 |
st.cache_data.clear()
|
| 390 |
game_model, overall_stats, timestamp, prop_frame, prop_trends, pick_frame = init_baselines()
|
| 391 |
qb_stats = overall_stats[overall_stats['Position'] == 'QB']
|
| 392 |
+
qb_stats = qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 393 |
non_qb_stats = overall_stats[overall_stats['Position'] != 'QB']
|
| 394 |
+
non_qb_stats = non_qb_stats.drop_duplicates(subset=['Player', 'Position'])
|
| 395 |
team_dict = dict(zip(prop_frame['Player'], prop_frame['Team']))
|
| 396 |
t_stamp = f"Last Update: " + str(timestamp) + f" CST"
|
| 397 |
col1, col2 = st.columns([1, 5])
|
|
|
|
| 522 |
prop_check = (overall_file - prop_file)
|
| 523 |
|
| 524 |
players_only['Mean_Outcome'] = overall_file.mean(axis=1)
|
| 525 |
+
players_only['Book'] = players_only['Player'].map(book_dict)
|
| 526 |
+
players_only['Prop'] = players_only['Player'].map(prop_dict)
|
| 527 |
+
players_only['poisson_var'] = players_only.apply(calculate_poisson, axis=1)
|
| 528 |
players_only['10%'] = overall_file.quantile(0.1, axis=1)
|
| 529 |
players_only['90%'] = overall_file.quantile(0.9, axis=1)
|
| 530 |
+
players_only['Over'] = np_where(players_only['Prop'] <= 3, players_only['poisson_var'], prop_check[prop_check > 0].count(axis=1)/float(total_sims))
|
| 531 |
players_only['Imp Over'] = players_only['Player'].map(over_dict)
|
| 532 |
players_only['Over%'] = players_only[["Over", "Imp Over"]].mean(axis=1)
|
| 533 |
+
players_only['Under'] = np_where(players_only['Prop'] <= 3, 1 - players_only['poisson_var'], prop_check[prop_check < 0].count(axis=1)/float(total_sims))
|
| 534 |
players_only['Imp Under'] = players_only['Player'].map(under_dict)
|
| 535 |
players_only['Under%'] = players_only[["Under", "Imp Under"]].mean(axis=1)
|
|
|
|
|
|
|
| 536 |
players_only['Prop_avg'] = players_only['Prop'].mean() / 100
|
| 537 |
players_only['prop_threshold'] = .10
|
| 538 |
players_only = players_only[players_only['Mean_Outcome'] > 0]
|
|
|
|
| 676 |
prop_check = (overall_file - prop_file)
|
| 677 |
|
| 678 |
players_only['Mean_Outcome'] = overall_file.mean(axis=1)
|
| 679 |
+
players_only['Book'] = players_only['Player'].map(book_dict)
|
| 680 |
+
players_only['Prop'] = players_only['Player'].map(prop_dict)
|
| 681 |
+
players_only['poisson_var'] = players_only.apply(calculate_poisson, axis=1)
|
| 682 |
players_only['10%'] = overall_file.quantile(0.1, axis=1)
|
| 683 |
players_only['90%'] = overall_file.quantile(0.9, axis=1)
|
| 684 |
+
players_only['Over'] = np_where(players_only['Prop'] <= 3, players_only['poisson_var'], prop_check[prop_check > 0].count(axis=1)/float(total_sims))
|
| 685 |
players_only['Imp Over'] = players_only['Player'].map(over_dict)
|
| 686 |
players_only['Over%'] = players_only[["Over", "Imp Over"]].mean(axis=1)
|
| 687 |
+
players_only['Under'] = np_where(players_only['Prop'] <= 3, 1 - players_only['poisson_var'], prop_check[prop_check < 0].count(axis=1)/float(total_sims))
|
| 688 |
players_only['Imp Under'] = players_only['Player'].map(under_dict)
|
| 689 |
players_only['Under%'] = players_only[["Under", "Imp Under"]].mean(axis=1)
|
|
|
|
|
|
|
| 690 |
players_only['Prop_avg'] = players_only['Prop'].mean() / 100
|
| 691 |
players_only['prop_threshold'] = .10
|
| 692 |
players_only = players_only[players_only['Mean_Outcome'] > 0]
|