Spaces:
Running
Running
BraydenMoore
commited on
Commit
β’
fc2b782
1
Parent(s):
79347f6
Add results
Browse files- Source/Build/update.py +28 -0
- Source/Data/results.csv +3 -0
- Source/Predict/predict.py +41 -11
- Templates/index.html +65 -36
Source/Build/update.py
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
import nfl_data_py.nfl_data_py as nfl
|
2 |
import build
|
3 |
import datetime as dt
|
@@ -6,10 +7,20 @@ import pandas as pd
|
|
6 |
pd.set_option('chained_assignment',None)
|
7 |
pd.set_option('display.max_columns',None)
|
8 |
import os
|
|
|
9 |
|
10 |
current_directory = os.path.dirname(os.path.abspath(__file__))
|
11 |
parent_directory = os.path.dirname(current_directory)
|
12 |
data_directory = os.path.join(parent_directory, 'Data')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
# get current season
|
15 |
year = dt.datetime.now().year
|
@@ -20,3 +31,20 @@ current_season = year if month in [8,9,10,11,12] else year-1
|
|
20 |
build.build_gbg_data(get_seasons=[current_season])
|
21 |
build.add_odds_data()
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from operator import index
|
2 |
import nfl_data_py.nfl_data_py as nfl
|
3 |
import build
|
4 |
import datetime as dt
|
|
|
7 |
pd.set_option('chained_assignment',None)
|
8 |
pd.set_option('display.max_columns',None)
|
9 |
import os
|
10 |
+
import pickle as pkl
|
11 |
|
12 |
current_directory = os.path.dirname(os.path.abspath(__file__))
|
13 |
parent_directory = os.path.dirname(current_directory)
|
14 |
data_directory = os.path.join(parent_directory, 'Data')
|
15 |
+
pickle_directory = os.path.join(parent_directory, 'Pickles')
|
16 |
+
|
17 |
+
# get team abbreviations
|
18 |
+
file_path = os.path.join(pickle_directory, 'team_name_to_abbreviation.pkl')
|
19 |
+
with open(file_path, 'rb') as f:
|
20 |
+
team_name_to_abbreviation = pkl.load(f)
|
21 |
+
file_path = os.path.join(pickle_directory, 'team_abbreviation_to_name.pkl')
|
22 |
+
with open(file_path, 'rb') as f:
|
23 |
+
team_abbreviation_to_name = pkl.load(f)
|
24 |
|
25 |
# get current season
|
26 |
year = dt.datetime.now().year
|
|
|
31 |
build.build_gbg_data(get_seasons=[current_season])
|
32 |
build.add_odds_data()
|
33 |
|
34 |
+
# get winners
|
35 |
+
pbp = build.get_pbp_data([2023])
|
36 |
+
pbp = pbp.drop_duplicates(subset='game_id')
|
37 |
+
pbp[['season','week','away','home']] = pbp['game_id'].str.split('_', expand=True)
|
38 |
+
games = pbp[['game_id','away_score','home_score','season','week','away','home']]
|
39 |
+
games[['away_score','home_score','season','week']] = games[['away_score','home_score','season','week']].astype(int)
|
40 |
+
|
41 |
+
games['away_team'] = games['away'].map(team_abbreviation_to_name)
|
42 |
+
games['home_team'] = games['home'].map(team_abbreviation_to_name)
|
43 |
+
|
44 |
+
games['total'] = games['away_score'] + games['home_score']
|
45 |
+
games['winner'] = [a if a_s>h_s else h if h_s>a_s else 'Tie' for a,h,a_s,h_s in games[['away_team','home_team','away_score','home_score']].values]
|
46 |
+
|
47 |
+
file_path = os.path.join(data_directory, 'results.csv')
|
48 |
+
games[['game_id','total','winner']].to_csv(file_path, index=False)
|
49 |
+
|
50 |
+
|
Source/Data/results.csv
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:cba191ba24d4a23d9ebd2720203deb51546e3a121a335320bb50db8bcb6084b9
|
3 |
+
size 584
|
Source/Predict/predict.py
CHANGED
@@ -16,6 +16,9 @@ pickle_directory = os.path.join(parent_directory, 'Pickles')
|
|
16 |
file_path = os.path.join(data_directory, 'gbg_this_year.csv')
|
17 |
gbg = pd.read_csv(file_path, low_memory=False)
|
18 |
|
|
|
|
|
|
|
19 |
# get team abbreviations
|
20 |
file_path = os.path.join(pickle_directory, 'team_name_to_abbreviation.pkl')
|
21 |
with open(file_path, 'rb') as f:
|
@@ -77,41 +80,68 @@ def get_one_week(home,away,season,week):
|
|
77 |
|
78 |
def predict(home,away,season,week,total):
|
79 |
# finish preparing data
|
80 |
-
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
data = get_one_week(home_abbrev,away_abbrev,season,week)
|
83 |
data['Total Score Close'] = total
|
84 |
matrix = xgb.DMatrix(data.astype(float).values)
|
85 |
|
|
|
|
|
|
|
86 |
# moneyline
|
87 |
-
model = '
|
88 |
file_path = os.path.join(model_directory, f'{model}.json')
|
89 |
xgb_ml = xgb.Booster()
|
90 |
xgb_ml.load_model(file_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
try:
|
92 |
ml_predicted_proba = xgb_ml.predict(matrix)[0][1]
|
93 |
-
print(xgb_ml.predict(matrix))
|
94 |
winner_proba = max([ml_predicted_proba, 1-ml_predicted_proba]).item()
|
95 |
-
moneyline = {'Winner': [home if ml_predicted_proba>0.
|
96 |
-
'Probabilities':[winner_proba]
|
|
|
97 |
except:
|
98 |
moneyline = {'Winner': 'NA',
|
99 |
-
'Probabilities':['N/A']
|
|
|
100 |
|
101 |
# over/under
|
102 |
model = 'xgboost_OU_no_odds_60.8%'
|
103 |
file_path = os.path.join(model_directory, f'{model}.json')
|
104 |
xgb_ou = xgb.Booster()
|
105 |
xgb_ou.load_model(file_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
try:
|
107 |
ou_predicted_proba = xgb_ou.predict(matrix)[0][1]
|
108 |
ou_proba = max([ou_predicted_proba, 1-ou_predicted_proba]).item()
|
|
|
109 |
over_under = {'Over/Under': ['Over' if ou_predicted_proba>0.5 else 'Under'],
|
110 |
-
'Probability': [ou_proba]
|
|
|
111 |
except:
|
112 |
over_under = {'Over/Under': 'N/A',
|
113 |
-
'Probability': ['N/A']
|
|
|
114 |
|
115 |
-
|
116 |
-
game_id = str(season) + '_' + str(week) + '_' + away_abbrev + '_' + home_abbrev
|
117 |
return game_id, moneyline, over_under
|
|
|
16 |
file_path = os.path.join(data_directory, 'gbg_this_year.csv')
|
17 |
gbg = pd.read_csv(file_path, low_memory=False)
|
18 |
|
19 |
+
file_path = os.path.join(data_directory, 'results.csv')
|
20 |
+
results = pd.read_csv(file_path, low_memory=False)
|
21 |
+
|
22 |
# get team abbreviations
|
23 |
file_path = os.path.join(pickle_directory, 'team_name_to_abbreviation.pkl')
|
24 |
with open(file_path, 'rb') as f:
|
|
|
80 |
|
81 |
def predict(home,away,season,week,total):
|
82 |
# finish preparing data
|
83 |
+
if len(home)>4:
|
84 |
+
home_abbrev = team_name_to_abbreviation[home]
|
85 |
+
else:
|
86 |
+
home_abbrev = home
|
87 |
+
|
88 |
+
if len(away)>4:
|
89 |
+
away_abbrev = team_name_to_abbreviation[away]
|
90 |
+
else:
|
91 |
+
away_abbrev = away
|
92 |
+
|
93 |
data = get_one_week(home_abbrev,away_abbrev,season,week)
|
94 |
data['Total Score Close'] = total
|
95 |
matrix = xgb.DMatrix(data.astype(float).values)
|
96 |
|
97 |
+
# create game id
|
98 |
+
game_id = str(season) + '_0' + str(week) + '_' + away_abbrev + '_' + home_abbrev
|
99 |
+
|
100 |
# moneyline
|
101 |
+
model = 'xgboost_ML_no_odds_71.4%'
|
102 |
file_path = os.path.join(model_directory, f'{model}.json')
|
103 |
xgb_ml = xgb.Booster()
|
104 |
xgb_ml.load_model(file_path)
|
105 |
+
|
106 |
+
try:
|
107 |
+
moneyline_result = results.loc[results['game_id']==game_id, 'winner'].item()
|
108 |
+
except:
|
109 |
+
moneyline_result = 'N/A'
|
110 |
+
|
111 |
try:
|
112 |
ml_predicted_proba = xgb_ml.predict(matrix)[0][1]
|
|
|
113 |
winner_proba = max([ml_predicted_proba, 1-ml_predicted_proba]).item()
|
114 |
+
moneyline = {'Winner': [home if ml_predicted_proba>0.5 else away if ml_predicted_proba<0.5 else 'Toss-Up'],
|
115 |
+
'Probabilities':[winner_proba],
|
116 |
+
'Result': moneyline_result}
|
117 |
except:
|
118 |
moneyline = {'Winner': 'NA',
|
119 |
+
'Probabilities':['N/A'],
|
120 |
+
'Result': moneyline_result}
|
121 |
|
122 |
# over/under
|
123 |
model = 'xgboost_OU_no_odds_60.8%'
|
124 |
file_path = os.path.join(model_directory, f'{model}.json')
|
125 |
xgb_ou = xgb.Booster()
|
126 |
xgb_ou.load_model(file_path)
|
127 |
+
|
128 |
+
try:
|
129 |
+
result = results.loc[results['game_id']==game_id, 'total'].item()
|
130 |
+
over_under_result = 'Over' if float(result)>float(total) else 'Under'
|
131 |
+
except:
|
132 |
+
over_under_result = 'N/A'
|
133 |
+
|
134 |
try:
|
135 |
ou_predicted_proba = xgb_ou.predict(matrix)[0][1]
|
136 |
ou_proba = max([ou_predicted_proba, 1-ou_predicted_proba]).item()
|
137 |
+
|
138 |
over_under = {'Over/Under': ['Over' if ou_predicted_proba>0.5 else 'Under'],
|
139 |
+
'Probability': [ou_proba],
|
140 |
+
'Result': over_under_result}
|
141 |
except:
|
142 |
over_under = {'Over/Under': 'N/A',
|
143 |
+
'Probability': ['N/A'],
|
144 |
+
'Result': over_under_result}
|
145 |
|
146 |
+
print(moneyline)
|
|
|
147 |
return game_id, moneyline, over_under
|
Templates/index.html
CHANGED
@@ -82,11 +82,13 @@
|
|
82 |
position: relative;
|
83 |
width: 100%;
|
84 |
text-align: center;
|
|
|
|
|
|
|
85 |
}
|
86 |
.winner-image {
|
87 |
-
width: 50px;
|
88 |
height: auto;
|
89 |
-
margin:
|
90 |
transition: opacity 0.3s ease;
|
91 |
}
|
92 |
.overlay {
|
@@ -95,7 +97,7 @@
|
|
95 |
left: 0;
|
96 |
width: 100%;
|
97 |
height: 100%;
|
98 |
-
background-color: rgba(0, 0, 0, 0.
|
99 |
color: white;
|
100 |
display: flex;
|
101 |
justify-content: center;
|
@@ -117,23 +119,25 @@
|
|
117 |
}
|
118 |
.over-under-text {
|
119 |
display: inline-block;
|
120 |
-
margin:
|
|
|
|
|
121 |
}
|
122 |
.over {
|
123 |
-
|
124 |
}
|
125 |
.under {
|
126 |
-
|
127 |
}
|
128 |
.na {
|
129 |
-
|
130 |
}
|
131 |
.over-under-wrapper .overlay {
|
132 |
position: absolute;
|
133 |
top: 0;
|
134 |
left: 0;
|
135 |
width: 100%;
|
136 |
-
background-color: rgba(0, 0, 0, 0.
|
137 |
color: white;
|
138 |
display: flex;
|
139 |
justify-content: center;
|
@@ -259,36 +263,36 @@
|
|
259 |
|
260 |
<script>
|
261 |
async function fetchGames() {
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
|
|
289 |
}
|
290 |
-
|
291 |
-
});
|
292 |
}
|
293 |
|
294 |
fetchGames();
|
@@ -341,6 +345,18 @@
|
|
341 |
winnerImg.className = 'winner-image hidden';
|
342 |
wrapperDiv.appendChild(winnerImg);
|
343 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
setTimeout(() => {
|
345 |
winnerImg.classList.remove('hidden');
|
346 |
}, 10);
|
@@ -370,6 +386,18 @@
|
|
370 |
|
371 |
overUnderDiv.appendChild(textDiv);
|
372 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
373 |
setTimeout(() => {
|
374 |
overUnderDiv.classList.remove('hidden');
|
375 |
}, 10);
|
@@ -380,6 +408,7 @@
|
|
380 |
overUnderDiv.appendChild(overUnderOverlayDiv);
|
381 |
|
382 |
overUnderCell.appendChild(overUnderDiv);
|
|
|
383 |
});
|
384 |
}
|
385 |
});
|
|
|
82 |
position: relative;
|
83 |
width: 100%;
|
84 |
text-align: center;
|
85 |
+
display: flex;
|
86 |
+
justify-content: center;
|
87 |
+
align-items: center;
|
88 |
}
|
89 |
.winner-image {
|
|
|
90 |
height: auto;
|
91 |
+
margin: 0;
|
92 |
transition: opacity 0.3s ease;
|
93 |
}
|
94 |
.overlay {
|
|
|
97 |
left: 0;
|
98 |
width: 100%;
|
99 |
height: 100%;
|
100 |
+
background-color: rgba(0, 0, 0, 0.9);
|
101 |
color: white;
|
102 |
display: flex;
|
103 |
justify-content: center;
|
|
|
119 |
}
|
120 |
.over-under-text {
|
121 |
display: inline-block;
|
122 |
+
margin: 0;
|
123 |
+
margin-right: 2px;
|
124 |
+
font-weight: bold;
|
125 |
}
|
126 |
.over {
|
127 |
+
color: green;
|
128 |
}
|
129 |
.under {
|
130 |
+
color: red;
|
131 |
}
|
132 |
.na {
|
133 |
+
color: white;
|
134 |
}
|
135 |
.over-under-wrapper .overlay {
|
136 |
position: absolute;
|
137 |
top: 0;
|
138 |
left: 0;
|
139 |
width: 100%;
|
140 |
+
background-color: rgba(0, 0, 0, 0.9);
|
141 |
color: white;
|
142 |
display: flex;
|
143 |
justify-content: center;
|
|
|
263 |
|
264 |
<script>
|
265 |
async function fetchGames() {
|
266 |
+
const response = await fetch('/get_games');
|
267 |
+
const pulled_games = await response.json();
|
268 |
+
const table = document.getElementById('gameTable');
|
269 |
+
const columns = ['Date','Away Team', 'Home Team'];
|
270 |
+
|
271 |
+
pulled_games.forEach((game) => {
|
272 |
+
const row = table.insertRow(-1);
|
273 |
+
|
274 |
+
columns.forEach((column) => {
|
275 |
+
const cell = row.insertCell(-1);
|
276 |
+
if (column === 'Away Team' || column === 'Home Team') {
|
277 |
+
const img = document.createElement('img');
|
278 |
+
img.src = `/Static/${game[column]}.webp`;
|
279 |
+
img.alt = game[column];
|
280 |
+
img.width = 50;
|
281 |
+
cell.appendChild(img);
|
282 |
+
} else {
|
283 |
+
cell.textContent = game[column];
|
284 |
+
}
|
285 |
+
});
|
286 |
|
287 |
+
for (let i = 0; i < 3; i++) {
|
288 |
+
const cell = row.insertCell(-1);
|
289 |
+
if (i<1) {
|
290 |
+
const input = document.createElement('input');
|
291 |
+
input.type = 'text';
|
292 |
+
cell.appendChild(input);
|
293 |
+
}
|
294 |
}
|
295 |
+
});
|
|
|
296 |
}
|
297 |
|
298 |
fetchGames();
|
|
|
345 |
winnerImg.className = 'winner-image hidden';
|
346 |
wrapperDiv.appendChild(winnerImg);
|
347 |
|
348 |
+
const winnerEmojiDiv = document.createElement('div');
|
349 |
+
winnerEmojiDiv.className = 'emoji';
|
350 |
+
if (moneyline.Winner === moneyline.Result) {
|
351 |
+
winnerEmojiDiv.textContent = 'β
';
|
352 |
+
} else {
|
353 |
+
winnerEmojiDiv.textContent = 'β';
|
354 |
+
}
|
355 |
+
if (moneyline.Result === 'N/A') {
|
356 |
+
winnerEmojiDiv.textContent = '';
|
357 |
+
}
|
358 |
+
wrapperDiv.appendChild(winnerEmojiDiv);
|
359 |
+
|
360 |
setTimeout(() => {
|
361 |
winnerImg.classList.remove('hidden');
|
362 |
}, 10);
|
|
|
386 |
|
387 |
overUnderDiv.appendChild(textDiv);
|
388 |
|
389 |
+
const overEmojiDiv = document.createElement('div');
|
390 |
+
overEmojiDiv.className = 'emoji';
|
391 |
+
if (data.over_unders[index]['Over/Under'] === data.over_unders[index]['Result']) {
|
392 |
+
overEmojiDiv.textContent = 'β
';
|
393 |
+
} else {
|
394 |
+
overEmojiDiv.textContent = 'β';
|
395 |
+
}
|
396 |
+
if (data.over_unders[index]['Result'] === 'N/A') {
|
397 |
+
overEmojiDiv.textContent = '';
|
398 |
+
}
|
399 |
+
overUnderDiv.appendChild(overEmojiDiv);
|
400 |
+
|
401 |
setTimeout(() => {
|
402 |
overUnderDiv.classList.remove('hidden');
|
403 |
}, 10);
|
|
|
408 |
overUnderDiv.appendChild(overUnderOverlayDiv);
|
409 |
|
410 |
overUnderCell.appendChild(overUnderDiv);
|
411 |
+
|
412 |
});
|
413 |
}
|
414 |
});
|