@@ -35,7 +35,7 @@ load_betting_lines = function(year, season_type = c('regular', 'postseason')) {
3535 ) | >
3636 list_rbind() | >
3737 as_tibble() | >
38- standardize_start_date()
38+ standardize_start_date()
3939
4040}
4141
@@ -54,20 +54,20 @@ prepare_games_for_model = function(data, estimates, season_week) {
5454 prepare_game_info() | >
5555 add_game_weeks() | >
5656 prepare_fcs_teams() | >
57- select(season ,
58- season_type ,
59- season_week ,
60- week ,
61- week_date ,
62- start_date ,
63- game_id ,
64- completed ,
57+ select(season ,
58+ season_type ,
59+ season_week ,
60+ week ,
61+ week_date ,
62+ start_date ,
63+ game_id ,
64+ completed ,
6565 neutral_site ,
6666 home_id ,
6767 away_id ,
6868 home_team ,
6969 away_team ,
70- home ,
70+ home ,
7171 away ) | >
7272 join_team_estimates(estimates = estimates , season_week = season_week )
7373
@@ -127,8 +127,8 @@ slice_estimates = function(data) {
127127 slice_max(week_date , n = 1 ) | >
128128 ungroup() | >
129129 select(
130- season ,
131- week_date ,
130+ season ,
131+ week_date ,
132132 team ,
133133 overall = postgame_overall ,
134134 offense = postgame_offense ,
@@ -219,15 +219,15 @@ create_semifinal = function(winners) {
219219 semi_2 = winners [3 : 4 ,] | > arrange(seed )
220220
221221
222- matchup_1 =
222+ matchup_1 =
223223 tibble(
224224 home_seed = semi_1 [1 ,]$ seed ,
225225 home_team = semi_1 [1 ,]$ team ,
226226 away_seed = semi_1 [2 ,]$ seed ,
227227 away_team = semi_1 [2 ,]$ team
228228 )
229229
230- matchup_2 =
230+ matchup_2 =
231231 tibble(
232232 home_seed = semi_2 [1 ,]$ seed ,
233233 home_team = semi_2 [1 ,]$ team ,
@@ -256,11 +256,11 @@ create_championship = function(winners) {
256256
257257simulate_playoff = function (playoff_teams , estimates , model ) {
258258
259- playoff_seeds =
259+ playoff_seeds =
260260 playoff_teams | >
261261 create_seeds()
262262
263- round1_matchups =
263+ round1_matchups =
264264 playoff_teams | >
265265 create_seeds() | >
266266 create_initial_matchups() | >
@@ -270,7 +270,7 @@ simulate_playoff = function(playoff_teams, estimates, model) {
270270 round1_matchups | >
271271 simulate_outcome(model = model , ndraws = 1 , seed = NULL )
272272
273- round1_winners =
273+ round1_winners =
274274 round1 | >
275275 select(team = winner ,
276276 seed = winner_seed )
@@ -279,46 +279,46 @@ simulate_playoff = function(playoff_teams, estimates, model) {
279279 playoff_seeds | >
280280 filter(seed < = 4 )
281281
282- quarterfinal_matchups =
282+ quarterfinal_matchups =
283283 create_quarterfinal(
284284 round1_byes ,
285285 round1_winners
286286 ) | >
287287 add_team_estimates(estimates = estimates )
288288
289- quarterfinals =
289+ quarterfinals =
290290 quarterfinal_matchups | >
291291 simulate_outcome(model = model , ndraws = 1 , seed = NULL )
292292
293- quarterfinal_winners =
293+ quarterfinal_winners =
294294 quarterfinals | >
295295 select(team = winner , seed = winner_seed )
296296
297- semifinal_matchups =
297+ semifinal_matchups =
298298 create_semifinal(
299299 quarterfinal_winners
300300 ) | >
301301 add_team_estimates(estimates = estimates )
302302
303- semifinals =
303+ semifinals =
304304 semifinal_matchups | >
305- simulate_outcome(model = model , ndraws = 1 , seed = NULL )
305+ simulate_outcome(model = model , ndraws = 1 , seed = NULL )
306306
307307 championship_matchup =
308308 semifinals | >
309309 select(team = winner , seed = winner_seed ) | >
310310 create_championship() | >
311311 add_team_estimates(estimates = estimates )
312312
313- championship =
313+ championship =
314314 championship_matchup | >
315315 simulate_outcome(model = model , ndraws = 1 , seed = NULL )
316316
317317 championship_winner =
318318 championship | >
319319 select(team = winner , seed = winner_seed )
320320
321- games =
321+ games =
322322 bind_rows(
323323 round1 | >
324324 mutate(round = ' round_1' ),
@@ -340,28 +340,107 @@ simulate_playoff = function(playoff_teams, estimates, model) {
340340
341341}
342342
343+ simulate_playoff_after_round_1 =
344+ function (
345+ playoff_teams ,
346+ round_1_teams ,
347+ estimates ,
348+ model ) {
349+
350+ playoff_seeds =
351+ playoff_teams | >
352+ create_seeds()
353+
354+ round1_winners =
355+ playoff_seeds | >
356+ filter(team %in% round_1_teams ) | >
357+ select(team , seed )
358+
359+ round1_byes =
360+ playoff_seeds | >
361+ filter(seed < = 4 )
362+
363+ quarterfinal_matchups =
364+ create_quarterfinal(
365+ round1_byes ,
366+ round1_winners
367+ ) | >
368+ add_team_estimates(estimates = estimates )
369+
370+ quarterfinals =
371+ quarterfinal_matchups | >
372+ simulate_outcome(model = model , ndraws = 1 , seed = NULL )
373+
374+ quarterfinal_winners =
375+ quarterfinals | >
376+ select(team = winner , seed = winner_seed )
377+
378+ semifinal_matchups =
379+ create_semifinal(
380+ quarterfinal_winners
381+ ) | >
382+ add_team_estimates(estimates = estimates )
383+
384+ semifinals =
385+ semifinal_matchups | >
386+ simulate_outcome(model = model , ndraws = 1 , seed = NULL )
387+
388+ championship_matchup =
389+ semifinals | >
390+ select(team = winner , seed = winner_seed ) | >
391+ create_championship() | >
392+ add_team_estimates(estimates = estimates )
393+
394+ championship =
395+ championship_matchup | >
396+ simulate_outcome(model = model , ndraws = 1 , seed = NULL )
397+
398+ championship_winner =
399+ championship | >
400+ select(team = winner , seed = winner_seed )
401+
402+ games =
403+ bind_rows(
404+ quarterfinals | >
405+ mutate(round = ' quarterfinal' ),
406+ semifinals | >
407+ mutate(round = ' semifinal' ),
408+ championship | >
409+ mutate(round = ' championship' )
410+ ) | >
411+ select(round , everything()) | >
412+ group_by(round ) | >
413+ mutate(round_game = row_number()) | >
414+ select(starts_with(" round" ), everything()) | >
415+ ungroup() | >
416+ mutate(round = factor (round , levels = c(" round_1" , " quarterfinal" , " semifinal" , " championship" )))
417+
418+ return (games )
419+
420+ }
421+
343422longer_playoffs = function (data ) {
344423
345- home =
424+ home =
346425 data | >
347426 mutate(
348427 round ,
349428 round_game ,
350429 .draw ,
351- team = home_team ,
430+ team = home_team ,
352431 opponent = away_team ,
353432 win = case_when(home_win == ' yes' ~ ' yes' , TRUE ~ ' no' ),
354433 .keep = ' none'
355434 ) | >
356435 ungroup()
357436
358- away =
437+ away =
359438 data | >
360439 mutate(
361440 round ,
362441 round_game ,
363442 .draw ,
364- team = away_team ,
443+ team = away_team ,
365444 opponent = home_team ,
366445 win = case_when(home_win == ' yes' ~ ' no' , TRUE ~ ' yes' ),
367446 .keep = ' none'
@@ -383,7 +462,7 @@ summarize_wins_by_round = function(data) {
383462add_playoff_game_number = function (data , start ) {
384463
385464 data | >
386- mutate(playoff_game_number =
465+ mutate(playoff_game_number =
387466 case_when(
388467 round == ' round_1' & round_game == 4 ~ 7.5 ,
389468 round == ' round_1' & round_game == 3 ~ 1.5 ,
@@ -481,12 +560,12 @@ gt_playoff_probs = function(data, ratings) {
481560 data | >
482561 summarize_wins_by_round() | >
483562 pivot_wider(names_from = c(" round" ), values_from = c(" n" ), values_fill = 0 ) | >
484- mutate(round_1 = case_when(round_1 == 0 ~ n_sims ,
485- TRUE ~ round_1 )) | >
563+ mutate(
564+ across(any_of(c(" round_1" , " quarterfinal" , " semifinal" , " championship" )), ~ case_when(.x == 0 ~ n_sims ,
565+ TRUE ~ .x ))) | >
486566 mutate(across(where(is.numeric ), ~ .x / n_sims )) | >
487567 select(logo = winner , team = winner , round_1 , quarterfinal , semifinal , championship ) | >
488568 arrange(desc(championship )) | >
489- mutate(round_1 = case_when(round_1 == 0 ~ n_sims , TRUE ~ round_1 )) | >
490569 inner_join(
491570 ratings
492571 ) | >
@@ -517,7 +596,7 @@ plot_matchups = function(data) {
517596
518597plot_bracket = function (data ) {
519598
520- plot_data =
599+ plot_data =
521600 data | >
522601 add_playoff_game_number() | >
523602 group_by(playoff_game_number ) | >
@@ -526,8 +605,8 @@ plot_bracket = function(data) {
526605 mutate(playoff_game_number_team = playoff_game_number + rank ) | >
527606 mutate(round = factor (round , levels = c(" round_1" , " quarterfinal" , " semifinal" , ' championship' )))
528607
529- bracket =
530- bracket =
608+ bracket =
609+ bracket =
531610 plot_data | >
532611 ggplot(aes(x = round , y = playoff_game_number_team , label = paste(team , prop_label ), color = team ))+
533612 geom_text(hjust = 1 , position = position_nudge(x = 0.25 ))+
@@ -695,3 +774,83 @@ betting_lines_tbl = function(data) {
695774 page_size_default = 25
696775 )
697776}
777+
778+ gt_quarterfinal_probs = function (data , ratings ) {
779+
780+ gt_playoff_probs_table = function (data ) {
781+
782+ data | >
783+ gt :: gt() | >
784+ gt :: cols_hide(columns = c(" score" , " special" , " season" )) | >
785+ gt :: fmt_number(columns = everything(), decimals = 3 ) | >
786+ gtExtras :: gt_theme_espn() | >
787+ gt :: opt_row_striping(row_striping = F ) | >
788+ gt :: cols_label(
789+ " round_1" ~ html(" Round 1" ),
790+ " quarterfinal" ~ html(" Quarterfinal" ),
791+ " semifinal" ~ html(" Semi-Final" ),
792+ " championship" ~ html(" Championship" )
793+ ) | >
794+ gt :: cols_width(
795+ logo ~ px(75 ),
796+ team ~ px(100 ),
797+ offense ~ px(90 ),
798+ defense ~ px(90 ),
799+ round_1 ~ px(125 ),
800+ quarterfinal ~ px(125 ),
801+ semifinal ~ px(125 ),
802+ championship ~ px(125 )
803+ ) | >
804+ gt :: cols_align(columns = - c(" team" ), align = " center" ) | >
805+ gt :: data_color(columns = c(" round_1" , " quarterfinal" , " semifinal" , " championship" ),
806+ domain = c(0 , .9 ),
807+ na_color = " deepskyblue1" ,
808+ palette = c(" white" , " deepskyblue1" )) | >
809+ cfbplotR :: gt_fmt_cfb_logo(" logo" ) | >
810+ gt :: tab_spanner(
811+ columns = c(" round_1" , " quarterfinal" , " semifinal" , " championship" ),
812+ label = " win probability"
813+ ) | >
814+ gt :: tab_spanner(
815+ columns = c(" offense" , " defense" ),
816+ label = " team rating"
817+ ) | >
818+ gt :: data_color(
819+ columns = c(" offense" , " defense" , " special" ),
820+ palette = c(" orange" , " white" , " navy" ),
821+ domain = c(- .25 , .4 )
822+ ) | >
823+ gt :: tab_style(
824+ style = cell_borders(
825+ sides = " left" ,
826+ color = " white"
827+ ),
828+ locations = cells_body(
829+ columns = c(" round_1" )
830+ )
831+ ) | >
832+ gt :: sub_values(
833+ values = " 1" ,
834+ replacement = " ✓"
835+ ) | >
836+ gtExtras :: gt_theme_nytimes()
837+
838+
839+ }
840+
841+ n_sims = max(data $ .draw )
842+
843+ data | >
844+ summarize_wins_by_round() | >
845+ pivot_wider(names_from = c(" round" ), values_from = c(" n" ), values_fill = 0 ) | >
846+ mutate(across(where(is.numeric ), ~ .x / n_sims )) | >
847+ mutate(round_1 = 1 ) | >
848+ select(logo = winner , team = winner , round_1 , quarterfinal , semifinal , championship ) | >
849+ arrange(desc(championship )) | >
850+ inner_join(
851+ ratings
852+ ) | >
853+ select(logo , team , score , offense , defense , special , everything()) | >
854+ gt_playoff_probs_table()
855+
856+ }
0 commit comments