Spaces:
Running
Running
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]
|