├── Data ├── Playoff_seeds.csv ├── team_conf.csv └── playoff_games.csv ├── NFLPlayoff_probs_2019.csv ├── LICENSE ├── README.Rmd ├── README.md ├── R Script ├── Simulate NFL Playoffs.Rmd └── NFL Playoff Monte Carlo.R └── NFL Playoff Monte Carlo.R /Data/Playoff_seeds.csv: -------------------------------------------------------------------------------- 1 | Conference,Seed,Team,Wins,Losses,Percent 2 | AFC,1,Chiefs,12,4,75.00% 3 | AFC,2,Patriots,11,5,68.75% 4 | AFC,3,Texans,11,5,68.75% 5 | AFC,4,Ravens,10,6,62.50% 6 | AFC,5,Chargers,12,4,75.00% 7 | AFC,6,Colts,10,6,62.50% 8 | NFC,1,Saints,13,3,81.25% 9 | NFC,2,Rams,13,3,81.25% 10 | NFC,3,Bears,12,4,75.00% 11 | NFC,4,Cowboys,10,6,62.50% 12 | NFC,5,Seahawks,10,6,62.50% 13 | NFC,6,Eagles,9,7,56.25% -------------------------------------------------------------------------------- /NFLPlayoff_probs_2019.csv: -------------------------------------------------------------------------------- 1 | "team","Divisional","Conference","Superbowl","Champion" 2 | "KC","0%","66.36%","44.88%","27.13%" 3 | "NO","0%","58.41%","32.96%","17.74%" 4 | "LAR","0%","59.6%","31.67%","15.43%" 5 | "NE","0%","64.13%","27.34%","14.29%" 6 | "CHI","65.25%","28.13%","13.89%","5.45%" 7 | "SEA","57.82%","25.36%","11.94%","4.71%" 8 | "LAC","47.66%","18.16%","9.34%","4.5%" 9 | "BAL","52.34%","15.48%","6.89%","3.16%" 10 | "HOU","56.79%","20.73%","6.7%","3%" 11 | "IND","43.21%","15.14%","4.85%","2.12%" 12 | "DAL","42.18%","16.22%","5.14%","1.29%" 13 | "PHI","34.75%","12.26%","4.4%","1.16%" 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jason Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "NFL Playoff Simulation" 3 | output: github_document 4 | --- 5 | 6 | ```{r setup, include=FALSE} 7 | knitr::opts_chunk$set(echo = TRUE) 8 | ``` 9 | 10 | ## This repository will simulate the 2019 NFL Playoffs. 11 | 12 | ##### This is the code from my blog post for [A.I. Sports](https://aisportsfirm.com/predicting-nfl-playoffs/). 13 | 14 | 15 | 1,000,001 simulations takes some time to run. If you lower the num_sims it will be quicker to play around with on your own. 16 | 17 | ```{r eval=FALSE} 18 | set.seed(1234) 19 | while (i <= num_sims) { 20 | 21 | ##### Wild Card Weekend 22 | # AFC 23 | wc.1.afc <- simulate.game(afc.3, afc.6) 24 | wc.2.afc <- simulate.game(afc.4, afc.5) 25 | 26 | # NFC 27 | wc.1.nfc <- simulate.game(nfc.3, nfc.6) 28 | wc.2.nfc <- simulate.game(nfc.4, nfc.5) 29 | 30 | ##### Divisional Weekend 31 | # AFC 32 | dw.1.afc <- simulate.game(afc.1, wc.2.afc) 33 | dw.2.afc <- simulate.game(afc.2, wc.1.afc) 34 | 35 | # NFC 36 | dw.1.nfc <- simulate.game(nfc.1, wc.2.nfc) 37 | dw.2.nfc <- simulate.game(nfc.2, wc.1.nfc) 38 | 39 | ##### Championship Weekend 40 | # AFC 41 | cw.1.afc <- simulate.game(dw.1.afc, dw.2.afc) 42 | 43 | # NFC 44 | cw.1.nfc <- simulate.game(dw.1.nfc, dw.2.nfc) 45 | 46 | ##### Superbowl 47 | champ <- simulate.game(cw.1.afc, cw.1.nfc) 48 | 49 | #print(paste0("This is the winner ",champ)) 50 | 51 | results.all <- c( 52 | i, 53 | wc.1.afc, 54 | wc.2.afc, 55 | wc.1.nfc, 56 | wc.2.nfc, 57 | dw.1.afc, 58 | dw.2.afc, 59 | dw.1.nfc, 60 | dw.2.nfc, 61 | cw.1.afc, 62 | cw.1.nfc, 63 | champ 64 | ) 65 | 66 | simulation.results <- c(simulation.results, results.all) 67 | 68 | i <- i + 1 69 | } 70 | ``` 71 | 72 | ## View Results 73 | 74 | 75 | 76 | ```{r, eval=FALSE} 77 | # View results 78 | kable(all.chances.df) 79 | ``` 80 | 81 | 82 | # The Chiefs have the best chance of winning it all! 83 | 84 | Remember probabilities are just that... probabilities... It doesn't mean that they WILL win. But they have the best chance to win. I love the playoffs! Anything can happen! Let's see how this plays out! 85 | 86 | *** 87 | 88 | Feel free to play around with the percentages in the "playoff_games.csv" file to see how it affects the simulation. -------------------------------------------------------------------------------- /Data/team_conf.csv: -------------------------------------------------------------------------------- 1 | "team","abbr","primary","secondary","tertiary","quaternary","division","conference" 2 | "Arizona Cardinals","ARZ","#97233f","#000000","#ffb612","#a5acaf","NFC West","NFC" 3 | "Atlanta Falcons","ATL","#a71930","#000000","#a5acaf","#a30d2d","NFC South","NFC" 4 | "Baltimore Ravens","BAL","#241773","#000000","#9e7c0c","#c60c30","AFC North","AFC" 5 | "Buffalo Bills","BUF","#00338d","#c60c30","#0c2e82","#d50a0a","AFC East","AFC" 6 | "Carolina Panthers","CAR","#0085ca","#000000","#bfc0bf","#0085ca","NFC South","NFC" 7 | "Chicago Bears","CHI","#0b162a","#c83803","#0b162a","#c83803","NFC North","NFC" 8 | "Cincinnati Bengals","CIN","#000000","#fb4f14","#000000","#d32f1e","AFC North","AFC" 9 | "Cleveland Browns","CLE","#fb4f14","#22150c","#a5acaf","#d32f1e","AFC North","AFC" 10 | "Dallas Cowboys","DAL","#002244","#b0b7bc","#acc0c6","#a5acaf","NFC East","NFC" 11 | "Denver Broncos","DEN","#002244","#fb4f14","#00234c","#ff5200","AFC West","AFC" 12 | "Detroit Lions","DET","#005a8b","#b0b7bc","#000000","#004e89","NFC North","NFC" 13 | "Green Bay Packers","GB","#203731","#ffb612","#1c2d25","#eead1e","NFC North","NFC" 14 | "Houston Texans","HOU","#03202f","#a71930","#00071c","#a30d2d","AFC South","AFC" 15 | "Indianapolis Colts","IND","#002c5f","#a5acaf","#013369","#9ba1a2","AFC South","AFC" 16 | "Jacksonville Jaguars","JAX","#000000","#006778","#9f792c","#d7a22a","AFC South","AFC" 17 | "Kansas City Chiefs","KC","#e31837","#ffb612","#000000","#e31837","AFC West","AFC" 18 | "Los Angeles Chargers","LAC","#002244","#0073cf","#ffb612","#001532","AFC West","AFC" 19 | "Los Angeles Rams","LAR","#002244","#b3995d","#001532","#af925d","NFC West","NFC" 20 | "Miami Dolphins","MIA","#008e97","#f58220","#005778","#008e97","AFC East","AFC" 21 | "Minnesota Vikings","MIN","#4f2683","#ffc62f","#e9bf9b","#000000","NFC North","NFC" 22 | "New England Patriots","NE","#002244","#c60c30","#b0b7bc","#001532","AFC East","AFC" 23 | "New Orleans Saints","NO","#9f8958","#000000","#9f8958","#000000","NFC South","NFC" 24 | "New York Giants","NYG","#0b2265","#a71930","#a5acaf","#012352","NFC East","NFC" 25 | "New York Jets","NYJ","#203731","#1c2d25",NA,NA,"AFC East","AFC" 26 | "Oakland Raiders","OAK","#a5acaf","#000000","#a6aeb0","#000000","AFC West","AFC" 27 | "Philadelphia Eagles","PHI","#004953","#a5acaf","#acc0c6","#000000","NFC East","NFC" 28 | "Pittsburgh Steelers","PIT","#000000","#ffb612","#c60c30","#00539b","AFC North","AFC" 29 | "Seattle Seahawks","SEA","#002244","#69be28","#a5acaf","#001532","NFC West","NFC" 30 | "San Francisco 49ers","SF","#aa0000","#b3995d","#000000","#a5acaf","NFC West","NFC" 31 | "Tampa Bay Buccaneers","TB","#d50a0a","#34302b","#000000","#ff7900","NFC South","NFC" 32 | "Tennessee Titans","TEN","#002244","#4b92db","#c60c30","#a5acaf","AFC South","AFC" 33 | "Washington Redskins","WAS","#773141","#ffb612","#000000","#5b2b2f","NFC East","NFC" 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NFL Playoff Simulation 2 | ================ 3 | 4 | This repository will simulate the 2019 NFL Playoffs. 5 | ---------------------------------------------------- 6 | 7 | ##### This is the code from my blog post for [A.I. Sports](https://aisportsfirm.com/predicting-nfl-playoffs/). 8 | 9 | 1,000,001 simulations takes some time to run. If you lower the num\_sims it will be quicker to play around with on your own. 10 | 11 | ``` r 12 | set.seed(1234) 13 | while (i <= num_sims) { 14 | 15 | ##### Wild Card Weekend 16 | # AFC 17 | wc.1.afc <- simulate.game(afc.3, afc.6) 18 | wc.2.afc <- simulate.game(afc.4, afc.5) 19 | 20 | # NFC 21 | wc.1.nfc <- simulate.game(nfc.3, nfc.6) 22 | wc.2.nfc <- simulate.game(nfc.4, nfc.5) 23 | 24 | ##### Divisional Weekend 25 | # AFC 26 | dw.1.afc <- simulate.game(afc.1, wc.2.afc) 27 | dw.2.afc <- simulate.game(afc.2, wc.1.afc) 28 | 29 | # NFC 30 | dw.1.nfc <- simulate.game(nfc.1, wc.2.nfc) 31 | dw.2.nfc <- simulate.game(nfc.2, wc.1.nfc) 32 | 33 | ##### Championship Weekend 34 | # AFC 35 | cw.1.afc <- simulate.game(dw.1.afc, dw.2.afc) 36 | 37 | # NFC 38 | cw.1.nfc <- simulate.game(dw.1.nfc, dw.2.nfc) 39 | 40 | ##### Superbowl 41 | champ <- simulate.game(cw.1.afc, cw.1.nfc) 42 | 43 | #print(paste0("This is the winner ",champ)) 44 | 45 | results.all <- c( 46 | i, 47 | wc.1.afc, 48 | wc.2.afc, 49 | wc.1.nfc, 50 | wc.2.nfc, 51 | dw.1.afc, 52 | dw.2.afc, 53 | dw.1.nfc, 54 | dw.2.nfc, 55 | cw.1.afc, 56 | cw.1.nfc, 57 | champ 58 | ) 59 | 60 | simulation.results <- c(simulation.results, results.all) 61 | 62 | i <- i + 1 63 | } 64 | ``` 65 | 66 | View Results 67 | ------------ 68 | 69 | ``` r 70 | # View results 71 | kable(all.chances.df) 72 | ``` 73 | 74 | |team |Divisional |Conference |Superbowl |Champion | 75 | |:----|:----------|:----------|:---------|:--------| 76 | |KC |0% |66.36% |44.88% |27.13% | 77 | |NO |0% |58.41% |32.96% |17.74% | 78 | |LAR |0% |59.6% |31.67% |15.43% | 79 | |NE |0% |64.13% |27.34% |14.29% | 80 | |CHI |65.25% |28.13% |13.89% |5.45% | 81 | |SEA |57.82% |25.36% |11.94% |4.71% | 82 | |LAC |47.66% |18.16% |9.34% |4.5% | 83 | |BAL |52.34% |15.48% |6.89% |3.16% | 84 | |HOU |56.79% |20.73% |6.7% |3% | 85 | |IND |43.21% |15.14% |4.85% |2.12% | 86 | |DAL |42.18% |16.22% |5.14% |1.29% | 87 | |PHI |34.75% |12.26% |4.4% |1.16% | 88 | 89 | 90 | The Chiefs have the best chance of winning it all! 91 | ================================================== 92 | 93 | Remember probabilities are just that... probabilities... It doesn't mean that they WILL win. But they have the best chance to win. I love the playoffs! Anything can happen! Let's see how this plays out! 94 | 95 | ------------------------------------------------------------------------ 96 | 97 | Feel free to play around with the percentages in the "playoff\_games.csv" file to see how it affects the simulation. 98 | -------------------------------------------------------------------------------- /Data/playoff_games.csv: -------------------------------------------------------------------------------- 1 | "home.team","away.team","Avg.Prob" 2 | "KC","DAL",0.83626032872 3 | "NO","DAL",0.61602004527 4 | "BAL","DAL",0.67107807315 5 | "NE","DAL",0.72933008478 6 | "KC","PHI",0.76648426942 7 | "STL","DAL",0.70394417973 8 | "SD","DAL",0.73526048113 9 | "CHI","DAL",0.72854016909 10 | "IND","DAL",0.71346614233 11 | "KC","HOU",0.76394086625 12 | "NO","PHI",0.68274603655 13 | "KC","IND",0.72180640579 14 | "KC","CHI",0.67366383681 15 | "HOU","DAL",0.66804806198 16 | "BAL","PHI",0.69629811147 17 | "SEA","DAL",0.65738575131 18 | "NE","PHI",0.70411262962 19 | "KC","BAL",0.70484460997 20 | "NO","HOU",0.63468081741 21 | "DAL","DAL",0.65457080155 22 | "KC","SEA",0.63871002568 23 | "NO","IND",0.61854306861 24 | "STL","PHI",0.65068871818 25 | "NO","CHI",0.59016251758 26 | "BAL","HOU",0.64701266761 27 | "SD","PHI",0.68118405436 28 | "CHI","PHI",0.65129611959 29 | "BAL","IND",0.63047847477 30 | "BAL","CHI",0.64727261624 31 | "NE","HOU",0.63123622205 32 | "IND","PHI",0.6358853438 33 | "NO","BAL",0.56049099083 34 | "NE","IND",0.65612701108 35 | "PHI","DAL",0.66820596276 36 | "NE","CHI",0.65067663485 37 | "KC","NE",0.64646397955 38 | "BAL","BAL",0.57169831146 39 | "NO","SEA",0.56030772152 40 | "STL","HOU",0.59830791219 41 | "KC","SD",0.62434832803 42 | "HOU","PHI",0.58553514889 43 | "SD","HOU",0.62868472864 44 | "NE","BAL",0.59679371315 45 | "SEA","PHI",0.59383428512 46 | "STL","IND",0.58108575435 47 | "CHI","HOU",0.59776378309 48 | "STL","CHI",0.57562697054 49 | "BAL","SEA",0.57101416814 50 | "SD","IND",0.61143969462 51 | "SD","CHI",0.60582889303 52 | "IND","HOU",0.58190153181 53 | "CHI","IND",0.5805220049 54 | "CHI","CHI",0.59682857124 55 | "KC","STL",0.59269983265 56 | "NE","SEA",0.58981125239 57 | "IND","IND",0.5642027697 58 | "IND","CHI",0.57856864933 59 | "STL","BAL",0.57894010651 60 | "NO","NE",0.56976010182 61 | "SD","BAL",0.58909237394 62 | "DAL","PHI",0.56528574132 63 | "HOU","HOU",0.52992611771 64 | "NO","SD",0.56576216544 65 | "CHI","BAL",0.57670356121 66 | "BAL","NE",0.5236538294 67 | "SEA","HOU",0.57462118911 68 | "HOU","IND",0.56586499108 69 | "STL","SEA",0.5623533733 70 | "IND","BAL",0.55624850056 71 | "HOU","CHI",0.52552459292 72 | "BAL","SD",0.52053837511 73 | "SD","SEA",0.52691752153 74 | "SEA","IND",0.51912788841 75 | "NE","NE",0.54758616195 76 | "CHI","SEA",0.51741495202 77 | "SEA","CHI",0.51316679103 78 | "PHI","PHI",0.57455461706 79 | "NO","STL",0.52358154965 80 | "NE","SD",0.5190932471 81 | "IND","SEA",0.55200546334 82 | "HOU","BAL",0.51334117713 83 | "DAL","HOU",0.50735022189 84 | "BAL","STL",0.51004670684 85 | "SEA","BAL",0.49916890976 86 | "STL","NE",0.51522870949 87 | "DAL","IND",0.51379613063 88 | "SD","NE",0.52475049337 89 | "DAL","CHI",0.50279663181 90 | "HOU","SEA",0.50872211826 91 | "STL","SD",0.51059668082 92 | "NE","STL",0.49415190214 93 | "CHI","NE",0.512011347 94 | "SD","SD",0.47440904775 95 | "SEA","SEA",0.4943712725 96 | "IND","NE",0.45117053505 97 | "CHI","SD",0.5074119334 98 | "PHI","HOU",0.51573293087 99 | "DAL","BAL",0.46095253069 100 | "KC","NO",0.52611437954 101 | "IND","SD",0.48647799293 102 | "PHI","IND",0.49685884523 103 | "PHI","CHI",0.51130125355 104 | "STL","STL",0.46775193456 105 | "SD","STL",0.4772504411 106 | "HOU","NE",0.44760800999 107 | "DAL","SEA",0.42074820109 108 | "CHI","STL",0.43004072704 109 | "HOU","SD",0.44313118698 110 | "SEA","NE",0.40477306883 111 | "IND","STL",0.41327386681 112 | "PHI","BAL",0.43443714663 113 | "SEA","SD",0.4014296084 114 | "NO","NO",0.40929640987 115 | "KC","KC",0.47213600105 116 | "PHI","SEA",0.42840182604 117 | "HOU","STL",0.40117449054 118 | "DAL","NE",0.37432938698 119 | "BAL","NO",0.41914314998 120 | "SEA","STL",0.367775701 121 | "DAL","SD",0.39197154723 122 | "NE","NO",0.41786036636 123 | "PHI","NE",0.38407116248 124 | "NO","KC",0.35713112393 125 | "DAL","STL",0.3518859784 126 | "PHI","SD",0.35954532272 127 | "STL","NO",0.36720683694 128 | "BAL","KC",0.3676632102 129 | "SD","NO",0.37567649774 130 | "CHI","NO",0.36679540058 131 | "NE","KC",0.36752596065 132 | "IND","NO",0.35095178894 133 | "PHI","STL",0.33012656211 134 | "HOU","NO",0.32641937082 135 | "STL","KC",0.31850229444 136 | "SD","KC",0.32715610277 137 | "SEA","NO",0.30977195178 138 | "CHI","KC",0.3188532026 139 | "IND","KC",0.30404903363 140 | "DAL","NO",0.36488856806 141 | "HOU","KC",0.34189616336 142 | "SEA","KC",0.26677862672 143 | "PHI","NO",0.28050561457 144 | "DAL","KC",0.30892317403 145 | "PHI","KC",0.24249202698 146 | -------------------------------------------------------------------------------- /R Script/Simulate NFL Playoffs.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Predicting NFL Playoffs" 3 | output: html_notebook 4 | --- 5 | 6 | ## Million and One Simulations of the NFL Playoffs 7 | 8 | This is the code from my blog post for [A.I. Sports](https://aisportsfirm.com/predicting-nfl-playoffs/). 9 | 10 | ### Load Libraries 11 | 12 | ```{r} 13 | # load libraries 14 | library(knitr) 15 | library(data.table) 16 | library(tidyverse) 17 | library(magrittr) 18 | ``` 19 | 20 | 21 | ### Load Data 22 | 23 | ```{r} 24 | seeds <- fread("Data/playoff_seeds.csv") 25 | teams <- fread("Data/playoff_games.csv") 26 | ``` 27 | 28 | 29 | ```{r} 30 | seeds 31 | ``` 32 | 33 | ```{r} 34 | head(teams) 35 | tail(teams) 36 | ``` 37 | 38 | 39 | ### Functions needed for the modeling 40 | 41 | ```{r} 42 | ## convert_pct 43 | convert_pct <- function(x)paste(round(100*x, 2), "%", sep="") 44 | 45 | #Convert cities/nicknames to team abbreviations 46 | convertTeamAbbreviation <- function(x){ 47 | x[grep("Arizona", x, ignore.case=TRUE)] <- "ARZ" 48 | x[grep("Cardinals", x, ignore.case=TRUE)] <- "ARZ" 49 | 50 | x[grep("Atlanta", x, ignore.case=TRUE)] <- "ATL" 51 | x[grep("Falcons", x, ignore.case=TRUE)] <- "ATL" 52 | 53 | x[grep("Baltimore", x, ignore.case=TRUE)] <- "BAL" 54 | x[grep("Ravens", x, ignore.case=TRUE)] <- "BAL" 55 | 56 | x[grep("Buffalo", x, ignore.case=TRUE)] <- "BUF" 57 | x[grep("Bills", x, ignore.case=TRUE)] <- "BUF" 58 | 59 | x[grep("Carolina", x, ignore.case=TRUE)] <- "CAR" 60 | x[grep("Panthers", x, ignore.case=TRUE)] <- "CAR" 61 | 62 | x[grep("Chicago", x, ignore.case=TRUE)] <- "CHI" 63 | x[grep("Bears", x, ignore.case=TRUE)] <- "CHI" 64 | 65 | x[grep("Cincinnati", x, ignore.case=TRUE)] <- "CIN" 66 | x[grep("Bengals", x, ignore.case=TRUE)] <- "CIN" 67 | 68 | x[grep("Cleveland", x, ignore.case=TRUE)] <- "CLE" 69 | x[grep("Browns", x, ignore.case=TRUE)] <- "CLE" 70 | 71 | x[grep("Dallas", x, ignore.case=TRUE)] <- "DAL" 72 | x[grep("Cowboys", x, ignore.case=TRUE)] <- "DAL" 73 | 74 | x[grep("Denver", x, ignore.case=TRUE)] <- "DEN" 75 | x[grep("Broncos", x, ignore.case=TRUE)] <- "DEN" 76 | 77 | x[grep("Detroit", x, ignore.case=TRUE)] <- "DET" 78 | x[grep("Lions", x, ignore.case=TRUE)] <- "DET" 79 | 80 | x[grep("Free", x, ignore.case=TRUE)] <- "FA" 81 | x[grep("Agent", x, ignore.case=TRUE)] <- "FA" 82 | 83 | x[grep("Green Bay", x, ignore.case=TRUE)] <- "GB" 84 | x[grep("Packers", x, ignore.case=TRUE)] <- "GB" 85 | 86 | x[grep("Houston", x, ignore.case=TRUE)] <- "HOU" 87 | x[grep("Texans", x, ignore.case=TRUE)] <- "HOU" 88 | 89 | x[grep("Indianapolis", x, ignore.case=TRUE)] <- "IND" 90 | x[grep("Colts", x, ignore.case=TRUE)] <- "IND" 91 | 92 | x[grep("Jacksonville", x, ignore.case=TRUE)] <- "JAX" 93 | x[grep("Jaguars", x, ignore.case=TRUE)] <- "JAX" 94 | 95 | x[grep("Kansas City", x, ignore.case=TRUE)] <- "KC" 96 | x[grep("Chiefs", x, ignore.case=TRUE)] <- "KC" 97 | 98 | x[grep("Miami", x, ignore.case=TRUE)] <- "MIA" 99 | x[grep("Dolphins", x, ignore.case=TRUE)] <- "MIA" 100 | 101 | x[grep("Minnesota", x, ignore.case=TRUE)] <- "MIN" 102 | x[grep("Vikings", x, ignore.case=TRUE)] <- "MIN" 103 | 104 | x[grep("New England", x, ignore.case=TRUE)] <- "NE" 105 | x[grep("Patriots", x, ignore.case=TRUE)] <- "NE" 106 | 107 | x[grep("New Orleans", x, ignore.case=TRUE)] <- "NO" 108 | x[grep("Saints", x, ignore.case=TRUE)] <- "NO" 109 | 110 | x[grep("Jets", x, ignore.case=TRUE)] <- "NYJ" 111 | 112 | x[grep("Giants", x, ignore.case=TRUE)] <- "NYG" 113 | 114 | x[grep("Oakland", x, ignore.case=TRUE)] <- "OAK" 115 | x[grep("Raiders", x, ignore.case=TRUE)] <- "OAK" 116 | 117 | x[grep("Philadelphia", x, ignore.case=TRUE)] <- "PHI" 118 | x[grep("Eagles", x, ignore.case=TRUE)] <- "PHI" 119 | 120 | x[grep("Pittsburgh", x, ignore.case=TRUE)] <- "PIT" 121 | x[grep("Steelers", x, ignore.case=TRUE)] <- "PIT" 122 | 123 | x[grep("San Diego", x, ignore.case=TRUE)] <- "LAC" 124 | x[grep("Chargers", x, ignore.case=TRUE)] <- "LAC" 125 | x[grep("L.A. Chargers", x, ignore.case=TRUE)] <- "LAC" 126 | x[grep("SD", x, ignore.case=TRUE)] <- "LAC" 127 | 128 | x[grep("Saint Louis", x, ignore.case=TRUE)] <- "LAR" 129 | x[grep("St Louis", x, ignore.case=TRUE)] <- "LAR" 130 | x[grep("St. Louis", x, ignore.case=TRUE)] <- "LAR" 131 | x[grep("Rams", x, ignore.case=TRUE)] <- "LAR" 132 | x[grep("Los Angeles", x, ignore.case=TRUE)] <- "LAR" 133 | x[grep("L.A. Rams", x, ignore.case=TRUE)] <- "LAR" 134 | x[grep("STL", x, ignore.case=TRUE)] <- "LAR" 135 | 136 | x[grep("San Francisco", x, ignore.case=TRUE)] <- "SF" 137 | x[grep("49ers", x, ignore.case=TRUE)] <- "SF" 138 | 139 | x[grep("Seattle", x, ignore.case=TRUE)] <- "SEA" 140 | x[grep("Seahawks", x, ignore.case=TRUE)] <- "SEA" 141 | 142 | x[grep("Tampa Bay", x, ignore.case=TRUE)] <- "TB" 143 | x[grep("Buccaneers", x, ignore.case=TRUE)] <- "TB" 144 | 145 | x[grep("Tennessee", x, ignore.case=TRUE)] <- "TEN" 146 | x[grep("Titans", x, ignore.case=TRUE)] <- "TEN" 147 | 148 | x[grep("Washington", x, ignore.case=TRUE)] <- "WAS" 149 | x[grep("Redskins", x, ignore.case=TRUE)] <- "WAS" 150 | 151 | return(x) 152 | } 153 | 154 | ## simulate regular game 155 | simulate.game <- function(team1, team2){ 156 | Team1Seed <- seeds[seeds$TeamAbb == team1, "Seed"][[1]] 157 | Team2Seed <- seeds[seeds$TeamAbb == team2, "Seed"][[1]] 158 | 159 | if(Team1Seed > Team2Seed){ 160 | tmp <- team1 161 | team1 <- team2 162 | team2 <- tmp 163 | } 164 | 165 | # Extract Probabilities for each team in the matchup 166 | p.1.2 <- teams[teams$home.team == team1 & teams$away.team == team2, "Avg.Prob"][[1]] 167 | p.2.1 <- 1 - p.1.2 168 | 169 | 170 | # simulate Game 171 | game.result <- sample(c(team1, team2), size = 1, prob = c(p.1.2, p.2.1), replace=TRUE) 172 | 173 | # return the winner 174 | game.result 175 | } 176 | 177 | 178 | ## chance.df 179 | chance.df <- function(series){ 180 | 181 | tbl <- table(sim.results.df[ , series]) 182 | df <- data.frame(team = names(tbl), chance = as.numeric(tbl)/sum(tbl)) 183 | df <- df[order(df$chance, decreasing=TRUE), ] 184 | df 185 | } 186 | ``` 187 | 188 | 189 | 190 | ## SET EVERYTHING UP 191 | 192 | ```{r} 193 | # dataframe for results 194 | simulation.results <- c() 195 | 196 | # fix team names 197 | seeds$TeamAbb <- convertTeamAbbreviation(seeds$Team) 198 | teams$home.team <- convertTeamAbbreviation(teams$home.team) 199 | teams$away.team <- convertTeamAbbreviation(teams$away.team) 200 | 201 | # Set number of simulations at 1,000,001 202 | num_sims <- 1000001 203 | i <- 1 204 | 205 | # AFC Playoff Teams 206 | afc.1 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 1, "TeamAbb"][[1]] 207 | afc.2 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 2, "TeamAbb"][[1]] 208 | afc.3 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 3, "TeamAbb"][[1]] 209 | afc.4 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 4, "TeamAbb"][[1]] 210 | afc.5 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 5, "TeamAbb"][[1]] 211 | afc.6 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 6, "TeamAbb"][[1]] 212 | 213 | # NFC Playoff Teams 214 | nfc.1 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 1, "TeamAbb"][[1]] 215 | nfc.2 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 2, "TeamAbb"][[1]] 216 | nfc.3 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 3, "TeamAbb"][[1]] 217 | nfc.4 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 4, "TeamAbb"][[1]] 218 | nfc.5 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 5, "TeamAbb"][[1]] 219 | nfc.6 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 6, "TeamAbb"][[1]] 220 | ``` 221 | 222 | 223 | 224 | ## Run the Simulations 225 | 226 | This cycles through each game all the way through to the Super Bowl. It keeps track of how far each team made it each time. 227 | 228 | ```{r} 229 | set.seed(1234) 230 | while (i <= num_sims) { 231 | 232 | ##### Wild Card Weekend 233 | # AFC 234 | wc.1.afc <- simulate.game(afc.3, afc.6) 235 | wc.2.afc <- simulate.game(afc.4, afc.5) 236 | 237 | # NFC 238 | wc.1.nfc <- simulate.game(nfc.3, nfc.6) 239 | wc.2.nfc <- simulate.game(nfc.4, nfc.5) 240 | 241 | ##### Divisional Weekend 242 | # AFC 243 | dw.1.afc <- simulate.game(afc.1, wc.2.afc) 244 | dw.2.afc <- simulate.game(afc.2, wc.1.afc) 245 | 246 | # NFC 247 | dw.1.nfc <- simulate.game(nfc.1, wc.2.nfc) 248 | dw.2.nfc <- simulate.game(nfc.2, wc.1.nfc) 249 | 250 | ##### Championship Weekend 251 | # AFC 252 | cw.1.afc <- simulate.game(dw.1.afc, dw.2.afc) 253 | 254 | # NFC 255 | cw.1.nfc <- simulate.game(dw.1.nfc, dw.2.nfc) 256 | 257 | ##### Superbowl 258 | champ <- simulate.game(cw.1.afc, cw.1.nfc) 259 | 260 | #print(paste0("This is the winner ",champ)) 261 | 262 | results.all <- c( 263 | i, 264 | wc.1.afc, 265 | wc.2.afc, 266 | wc.1.nfc, 267 | wc.2.nfc, 268 | dw.1.afc, 269 | dw.2.afc, 270 | dw.1.nfc, 271 | dw.2.nfc, 272 | cw.1.afc, 273 | cw.1.nfc, 274 | champ 275 | ) 276 | 277 | simulation.results <- c(simulation.results, results.all) 278 | 279 | i <- i + 1 280 | } 281 | ``` 282 | 283 | ## Organize Results 284 | 285 | ```{r} 286 | sim.results.mat <- matrix(simulation.results, ncol=12, byrow=TRUE) 287 | sim.results.df <- as.data.frame(sim.results.mat) 288 | names(sim.results.df) <- c( 289 | "sim", 290 | "wc.1.afc", 291 | "wc.2.afc", 292 | "wc.1.nfc", 293 | "wc.2.nfc", 294 | "dw.1.afc", 295 | "dw.2.afc", 296 | "dw.1.nfc", 297 | "dw.2.nfc", 298 | "cw.1.afc", 299 | "cw.1.nfc", 300 | "champ" 301 | ) 302 | ``` 303 | 304 | 305 | ## Get Probabilities 306 | 307 | ```{r message=FALSE, warning=FALSE} 308 | # Superbowl Champions 309 | champs.df <- chance.df("champ") 310 | 311 | # Conference Champions 312 | AFCC.df <- chance.df("cw.1.afc") 313 | NFCC.df <- chance.df("cw.1.nfc") 314 | Superbowl <- rbind(AFCC.df, NFCC.df) 315 | 316 | # Divisional Champions 317 | afc.1.df <- chance.df("dw.1.afc") 318 | afc.2.df <- chance.df("dw.2.afc") 319 | nfc.1.df <- chance.df("dw.1.nfc") 320 | nfc.2.df <- chance.df("dw.2.nfc") 321 | Conference <- rbind(afc.1.df, afc.2.df, nfc.1.df, nfc.2.df) 322 | 323 | # Wildcard Games 324 | afc.wc1.df <- chance.df("wc.1.afc") 325 | afc.wc2.df <- chance.df("wc.2.afc") 326 | nfc.wc1.df <- chance.df("wc.1.nfc") 327 | nfc.wc2.df <- chance.df("wc.2.nfc") 328 | Divisional <- rbind(afc.wc1.df, afc.wc2.df, nfc.wc1.df, nfc.wc2.df) 329 | 330 | allteams <- unique(teams$home.team) 331 | allteams <- as.data.frame(allteams) 332 | colnames(allteams) <- "team" 333 | 334 | # Merge all probabilities 335 | all.chances.df <- allteams %>% 336 | left_join(Divisional, by = "team") %>% 337 | rename(Divisional = chance) %>% 338 | left_join(Conference, by = "team") %>% 339 | rename(Conference = chance) %>% 340 | left_join(Superbowl, by = "team") %>% 341 | rename(Superbowl = chance) %>% 342 | left_join(champs.df, by = "team") %>% 343 | rename(Champion = chance) %>% 344 | arrange(desc(Champion), desc(Superbowl), desc(Conference), desc(Divisional)) 345 | ``` 346 | 347 | 348 | ## Fix Percentages 349 | 350 | ```{r} 351 | # Fix percentages 352 | all.chances.df$Divisional <- ifelse(is.na(all.chances.df$Divisional), 0, all.chances.df$Divisional) 353 | all.chances.df$Conference <- ifelse(is.na(all.chances.df$Conference), 0, all.chances.df$Conference) 354 | all.chances.df$Superbowl <- ifelse(is.na(all.chances.df$Superbowl), 0, all.chances.df$Superbowl) 355 | all.chances.df$Champion <- ifelse(is.na(all.chances.df$Champion), 0, all.chances.df$Champion) 356 | 357 | all.chances.df[,2:5] <- sapply(all.chances.df[,2:5], convert_pct) 358 | ``` 359 | 360 | ## View Results 361 | 362 | ```{r} 363 | # View results 364 | kable(all.chances.df) 365 | ``` 366 | 367 | 368 | # The Chiefs have the best chance of winning it all! 369 | 370 | Remember probabilities are just that... probabilities... It doesn't mean that they WILL win. But they have the best chance to win. I love the playoffs! Anything can happen! Let's see how this plays out! 371 | 372 | 373 | 374 | 375 | *** -------------------------------------------------------------------------------- /NFL Playoff Monte Carlo.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | ################################### 4 | ### Monte Carlo Simulation #### 5 | ################################### 6 | 7 | 8 | 9 | # This script will generate probabilities for each team to advance through each round of the NFL Playoffs. 10 | 11 | 12 | ############################## 13 | ## Load necessary libraries ## -------------------------------------------------------------------------- 14 | ############################## 15 | 16 | library(knitr) 17 | library(data.table) 18 | library(tidyverse) 19 | library(magrittr) 20 | 21 | 22 | ############################## 23 | ## Load necessary Datafiles ## -------------------------------------------------------------------------- 24 | ############################## 25 | 26 | 27 | seeds <- fread("Data/playoff_seeds.csv") 28 | teams <- fread("Data/playoff_games.csv") 29 | 30 | 31 | 32 | ################################### 33 | ##### ##### 34 | ##### ALL NECESSARY FUNCTIONS ##### --------------------------------------------------------------------- 35 | ##### ##### 36 | ################################### 37 | 38 | ## convert_pct 39 | convert_pct <- function(x)paste(round(100*x, 2), "%", sep="") 40 | 41 | #Convert cities/nicknames to team abbreviations 42 | convertTeamAbbreviation <- function(x){ 43 | x[grep("Arizona", x, ignore.case=TRUE)] <- "ARZ" 44 | x[grep("Cardinals", x, ignore.case=TRUE)] <- "ARZ" 45 | 46 | x[grep("Atlanta", x, ignore.case=TRUE)] <- "ATL" 47 | x[grep("Falcons", x, ignore.case=TRUE)] <- "ATL" 48 | 49 | x[grep("Baltimore", x, ignore.case=TRUE)] <- "BAL" 50 | x[grep("Ravens", x, ignore.case=TRUE)] <- "BAL" 51 | 52 | x[grep("Buffalo", x, ignore.case=TRUE)] <- "BUF" 53 | x[grep("Bills", x, ignore.case=TRUE)] <- "BUF" 54 | 55 | x[grep("Carolina", x, ignore.case=TRUE)] <- "CAR" 56 | x[grep("Panthers", x, ignore.case=TRUE)] <- "CAR" 57 | 58 | x[grep("Chicago", x, ignore.case=TRUE)] <- "CHI" 59 | x[grep("Bears", x, ignore.case=TRUE)] <- "CHI" 60 | 61 | x[grep("Cincinnati", x, ignore.case=TRUE)] <- "CIN" 62 | x[grep("Bengals", x, ignore.case=TRUE)] <- "CIN" 63 | 64 | x[grep("Cleveland", x, ignore.case=TRUE)] <- "CLE" 65 | x[grep("Browns", x, ignore.case=TRUE)] <- "CLE" 66 | 67 | x[grep("Dallas", x, ignore.case=TRUE)] <- "DAL" 68 | x[grep("Cowboys", x, ignore.case=TRUE)] <- "DAL" 69 | 70 | x[grep("Denver", x, ignore.case=TRUE)] <- "DEN" 71 | x[grep("Broncos", x, ignore.case=TRUE)] <- "DEN" 72 | 73 | x[grep("Detroit", x, ignore.case=TRUE)] <- "DET" 74 | x[grep("Lions", x, ignore.case=TRUE)] <- "DET" 75 | 76 | x[grep("Free", x, ignore.case=TRUE)] <- "FA" 77 | x[grep("Agent", x, ignore.case=TRUE)] <- "FA" 78 | 79 | x[grep("Green Bay", x, ignore.case=TRUE)] <- "GB" 80 | x[grep("Packers", x, ignore.case=TRUE)] <- "GB" 81 | 82 | x[grep("Houston", x, ignore.case=TRUE)] <- "HOU" 83 | x[grep("Texans", x, ignore.case=TRUE)] <- "HOU" 84 | 85 | x[grep("Indianapolis", x, ignore.case=TRUE)] <- "IND" 86 | x[grep("Colts", x, ignore.case=TRUE)] <- "IND" 87 | 88 | x[grep("Jacksonville", x, ignore.case=TRUE)] <- "JAX" 89 | x[grep("Jaguars", x, ignore.case=TRUE)] <- "JAX" 90 | 91 | x[grep("Kansas City", x, ignore.case=TRUE)] <- "KC" 92 | x[grep("Chiefs", x, ignore.case=TRUE)] <- "KC" 93 | 94 | x[grep("Miami", x, ignore.case=TRUE)] <- "MIA" 95 | x[grep("Dolphins", x, ignore.case=TRUE)] <- "MIA" 96 | 97 | x[grep("Minnesota", x, ignore.case=TRUE)] <- "MIN" 98 | x[grep("Vikings", x, ignore.case=TRUE)] <- "MIN" 99 | 100 | x[grep("New England", x, ignore.case=TRUE)] <- "NE" 101 | x[grep("Patriots", x, ignore.case=TRUE)] <- "NE" 102 | 103 | x[grep("New Orleans", x, ignore.case=TRUE)] <- "NO" 104 | x[grep("Saints", x, ignore.case=TRUE)] <- "NO" 105 | 106 | x[grep("Jets", x, ignore.case=TRUE)] <- "NYJ" 107 | 108 | x[grep("Giants", x, ignore.case=TRUE)] <- "NYG" 109 | 110 | x[grep("Oakland", x, ignore.case=TRUE)] <- "OAK" 111 | x[grep("Raiders", x, ignore.case=TRUE)] <- "OAK" 112 | 113 | x[grep("Philadelphia", x, ignore.case=TRUE)] <- "PHI" 114 | x[grep("Eagles", x, ignore.case=TRUE)] <- "PHI" 115 | 116 | x[grep("Pittsburgh", x, ignore.case=TRUE)] <- "PIT" 117 | x[grep("Steelers", x, ignore.case=TRUE)] <- "PIT" 118 | 119 | x[grep("San Diego", x, ignore.case=TRUE)] <- "LAC" 120 | x[grep("Chargers", x, ignore.case=TRUE)] <- "LAC" 121 | x[grep("L.A. Chargers", x, ignore.case=TRUE)] <- "LAC" 122 | x[grep("SD", x, ignore.case=TRUE)] <- "LAC" 123 | 124 | x[grep("Saint Louis", x, ignore.case=TRUE)] <- "LAR" 125 | x[grep("St Louis", x, ignore.case=TRUE)] <- "LAR" 126 | x[grep("St. Louis", x, ignore.case=TRUE)] <- "LAR" 127 | x[grep("Rams", x, ignore.case=TRUE)] <- "LAR" 128 | x[grep("Los Angeles", x, ignore.case=TRUE)] <- "LAR" 129 | x[grep("L.A. Rams", x, ignore.case=TRUE)] <- "LAR" 130 | x[grep("STL", x, ignore.case=TRUE)] <- "LAR" 131 | 132 | x[grep("San Francisco", x, ignore.case=TRUE)] <- "SF" 133 | x[grep("49ers", x, ignore.case=TRUE)] <- "SF" 134 | 135 | x[grep("Seattle", x, ignore.case=TRUE)] <- "SEA" 136 | x[grep("Seahawks", x, ignore.case=TRUE)] <- "SEA" 137 | 138 | x[grep("Tampa Bay", x, ignore.case=TRUE)] <- "TB" 139 | x[grep("Buccaneers", x, ignore.case=TRUE)] <- "TB" 140 | 141 | x[grep("Tennessee", x, ignore.case=TRUE)] <- "TEN" 142 | x[grep("Titans", x, ignore.case=TRUE)] <- "TEN" 143 | 144 | x[grep("Washington", x, ignore.case=TRUE)] <- "WAS" 145 | x[grep("Redskins", x, ignore.case=TRUE)] <- "WAS" 146 | 147 | return(x) 148 | } 149 | 150 | ## simulate regular game 151 | simulate.game <- function(team1, team2){ 152 | Team1Seed <- seeds[seeds$TeamAbb == team1, "Seed"][[1]] 153 | Team2Seed <- seeds[seeds$TeamAbb == team2, "Seed"][[1]] 154 | 155 | if(Team1Seed > Team2Seed){ 156 | tmp <- team1 157 | team1 <- team2 158 | team2 <- tmp 159 | } 160 | 161 | # Extract Probabilities for each team in the matchup 162 | p.1.2 <- teams[teams$home.team == team1 & teams$away.team == team2, "Avg.Prob"][[1]] 163 | p.2.1 <- 1 - p.1.2 164 | 165 | 166 | # simulate Game 167 | game.result <- sample(c(team1, team2), size = 1, prob = c(p.1.2, p.2.1), replace=TRUE) 168 | 169 | # return the winner 170 | game.result 171 | } 172 | 173 | 174 | ## chance.df 175 | chance.df <- function(series){ 176 | 177 | tbl <- table(sim.results.df[ , series]) 178 | df <- data.frame(team = names(tbl), chance = as.numeric(tbl)/sum(tbl)) 179 | df <- df[order(df$chance, decreasing=TRUE), ] 180 | df 181 | } 182 | 183 | 184 | 185 | ############################# 186 | ##### ##### 187 | ##### SET EVERYTHING UP ##### --------------------------------------------------------------------------- 188 | ##### ##### 189 | ############################# 190 | 191 | 192 | # dataframe for results 193 | simulation.results <- c() 194 | 195 | # fix team names 196 | seeds$TeamAbb <- convertTeamAbbreviation(seeds$Team) 197 | teams$home.team <- convertTeamAbbreviation(teams$home.team) 198 | teams$away.team <- convertTeamAbbreviation(teams$away.team) 199 | 200 | # Set number of simulations at 1,000,001 -> Better than Goldman Sachs 201 | ## feel free to lower this number to 10,000-50,000 for it to complete the simulation in a reasonable timeframe 202 | num_sims <- 1000001 203 | i <- 1 204 | 205 | # AFC Playoff Teams 206 | afc.1 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 1, "TeamAbb"][[1]] 207 | afc.2 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 2, "TeamAbb"][[1]] 208 | afc.3 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 3, "TeamAbb"][[1]] 209 | afc.4 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 4, "TeamAbb"][[1]] 210 | afc.5 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 5, "TeamAbb"][[1]] 211 | afc.6 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 6, "TeamAbb"][[1]] 212 | 213 | # NFC Playoff Teams 214 | nfc.1 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 1, "TeamAbb"][[1]] 215 | nfc.2 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 2, "TeamAbb"][[1]] 216 | nfc.3 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 3, "TeamAbb"][[1]] 217 | nfc.4 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 4, "TeamAbb"][[1]] 218 | nfc.5 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 5, "TeamAbb"][[1]] 219 | nfc.6 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 6, "TeamAbb"][[1]] 220 | 221 | 222 | 223 | 224 | ############################### 225 | ##### ##### 226 | ##### Run the Simulations ##### ------------------------------------------------------------------------ 227 | ##### ##### 228 | ############################### 229 | 230 | 231 | 232 | set.seed(1234) 233 | while (i <= num_sims) { 234 | 235 | ##### Wild Card Weekend 236 | # AFC 237 | wc.1.afc <- simulate.game(afc.3, afc.6) 238 | wc.2.afc <- simulate.game(afc.4, afc.5) 239 | 240 | # NFC 241 | wc.1.nfc <- simulate.game(nfc.3, nfc.6) 242 | wc.2.nfc <- simulate.game(nfc.4, nfc.5) 243 | 244 | ##### Divisional Weekend 245 | # AFC 246 | dw.1.afc <- simulate.game(afc.1, wc.2.afc) 247 | dw.2.afc <- simulate.game(afc.2, wc.1.afc) 248 | 249 | # NFC 250 | dw.1.nfc <- simulate.game(nfc.1, wc.2.nfc) 251 | dw.2.nfc <- simulate.game(nfc.2, wc.1.nfc) 252 | 253 | ##### Championship Weekend 254 | # AFC 255 | cw.1.afc <- simulate.game(dw.1.afc, dw.2.afc) 256 | 257 | # NFC 258 | cw.1.nfc <- simulate.game(dw.1.nfc, dw.2.nfc) 259 | 260 | ##### Superbowl 261 | champ <- simulate.game(cw.1.afc, cw.1.nfc) 262 | 263 | #print(paste0("This is the winner ",champ)) 264 | 265 | results.all <- c( 266 | i, 267 | wc.1.afc, 268 | wc.2.afc, 269 | wc.1.nfc, 270 | wc.2.nfc, 271 | dw.1.afc, 272 | dw.2.afc, 273 | dw.1.nfc, 274 | dw.2.nfc, 275 | cw.1.afc, 276 | cw.1.nfc, 277 | champ 278 | ) 279 | 280 | simulation.results <- c(simulation.results, results.all) 281 | 282 | i <- i + 1 283 | } 284 | 285 | 286 | 287 | # Results 288 | sim.results.mat <- matrix(simulation.results, ncol=12, byrow=TRUE) 289 | sim.results.df <- as.data.frame(sim.results.mat) 290 | names(sim.results.df) <- c( 291 | "sim", 292 | "wc.1.afc", 293 | "wc.2.afc", 294 | "wc.1.nfc", 295 | "wc.2.nfc", 296 | "dw.1.afc", 297 | "dw.2.afc", 298 | "dw.1.nfc", 299 | "dw.2.nfc", 300 | "cw.1.afc", 301 | "cw.1.nfc", 302 | "champ" 303 | ) 304 | 305 | 306 | ################################################# 307 | ##### ##### 308 | ##### Create a table with all probabilities ##### ----------------------------------------------------------------------------------------------- 309 | ##### ##### 310 | ################################################# 311 | 312 | # Superbowl Champions 313 | champs.df <- chance.df("champ") 314 | 315 | # Conference Champions 316 | AFCC.df <- chance.df("cw.1.afc") 317 | NFCC.df <- chance.df("cw.1.nfc") 318 | Superbowl <- rbind(AFCC.df, NFCC.df) 319 | 320 | # Divisional Champions 321 | afc.1.df <- chance.df("dw.1.afc") 322 | afc.2.df <- chance.df("dw.2.afc") 323 | nfc.1.df <- chance.df("dw.1.nfc") 324 | nfc.2.df <- chance.df("dw.2.nfc") 325 | Conference <- rbind(afc.1.df, afc.2.df, nfc.1.df, nfc.2.df) 326 | 327 | # Wildcard Games 328 | afc.wc1.df <- chance.df("wc.1.afc") 329 | afc.wc2.df <- chance.df("wc.2.afc") 330 | nfc.wc1.df <- chance.df("wc.1.nfc") 331 | nfc.wc2.df <- chance.df("wc.2.nfc") 332 | Divisional <- rbind(afc.wc1.df, afc.wc2.df, nfc.wc1.df, nfc.wc2.df) 333 | 334 | allteams <- unique(teams$home.team) 335 | allteams <- as.data.frame(allteams) 336 | colnames(allteams) <- "team" 337 | 338 | # Merge all probabilities 339 | all.chances.df <- allteams %>% 340 | left_join(Divisional, by = "team") %>% 341 | rename(Divisional = chance) %>% 342 | left_join(Conference, by = "team") %>% 343 | rename(Conference = chance) %>% 344 | left_join(Superbowl, by = "team") %>% 345 | rename(Superbowl = chance) %>% 346 | left_join(champs.df, by = "team") %>% 347 | rename(Champion = chance) %>% 348 | arrange(desc(Champion), desc(Superbowl), desc(Conference), desc(Divisional)) 349 | 350 | 351 | # Fix percentages 352 | all.chances.df$Divisional <- ifelse(is.na(all.chances.df$Divisional), 0, all.chances.df$Divisional) 353 | all.chances.df$Conference <- ifelse(is.na(all.chances.df$Conference), 0, all.chances.df$Conference) 354 | all.chances.df$Superbowl <- ifelse(is.na(all.chances.df$Superbowl), 0, all.chances.df$Superbowl) 355 | all.chances.df$Champion <- ifelse(is.na(all.chances.df$Champion), 0, all.chances.df$Champion) 356 | 357 | all.chances.df[,2:5] <- sapply(all.chances.df[,2:5], convert_pct) 358 | 359 | 360 | # View results 361 | kable(all.chances.df) 362 | 363 | # Write to a file 364 | output_filename <- "NFLPlayoff_probs_2019.csv" 365 | write.csv(all.chances.df, output_filename, row.names=FALSE) 366 | 367 | -------------------------------------------------------------------------------- /R Script/NFL Playoff Monte Carlo.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | ################################### 4 | ### Monte Carlo Simulation #### 5 | ################################### 6 | 7 | 8 | 9 | # This script will generate probabilities for each team to advance through each round of the NFL Playoffs. 10 | 11 | 12 | ############################## 13 | ## Load necessary libraries ## -------------------------------------------------------------------------- 14 | ############################## 15 | 16 | library(knitr) 17 | library(data.table) 18 | library(tidyverse) 19 | library(magrittr) 20 | 21 | 22 | ############################## 23 | ## Load necessary Datafiles ## -------------------------------------------------------------------------- 24 | ############################## 25 | 26 | 27 | seeds <- fread("Data/playoff_seeds.csv") 28 | teams <- fread("Data/playoff_games.csv") 29 | 30 | 31 | 32 | ################################### 33 | ##### ##### 34 | ##### ALL NECESSARY FUNCTIONS ##### --------------------------------------------------------------------- 35 | ##### ##### 36 | ################################### 37 | 38 | ## convert_pct 39 | convert_pct <- function(x)paste(round(100*x, 2), "%", sep="") 40 | 41 | #Convert cities/nicknames to team abbreviations 42 | convertTeamAbbreviation <- function(x){ 43 | x[grep("Arizona", x, ignore.case=TRUE)] <- "ARZ" 44 | x[grep("Cardinals", x, ignore.case=TRUE)] <- "ARZ" 45 | 46 | x[grep("Atlanta", x, ignore.case=TRUE)] <- "ATL" 47 | x[grep("Falcons", x, ignore.case=TRUE)] <- "ATL" 48 | 49 | x[grep("Baltimore", x, ignore.case=TRUE)] <- "BAL" 50 | x[grep("Ravens", x, ignore.case=TRUE)] <- "BAL" 51 | 52 | x[grep("Buffalo", x, ignore.case=TRUE)] <- "BUF" 53 | x[grep("Bills", x, ignore.case=TRUE)] <- "BUF" 54 | 55 | x[grep("Carolina", x, ignore.case=TRUE)] <- "CAR" 56 | x[grep("Panthers", x, ignore.case=TRUE)] <- "CAR" 57 | 58 | x[grep("Chicago", x, ignore.case=TRUE)] <- "CHI" 59 | x[grep("Bears", x, ignore.case=TRUE)] <- "CHI" 60 | 61 | x[grep("Cincinnati", x, ignore.case=TRUE)] <- "CIN" 62 | x[grep("Bengals", x, ignore.case=TRUE)] <- "CIN" 63 | 64 | x[grep("Cleveland", x, ignore.case=TRUE)] <- "CLE" 65 | x[grep("Browns", x, ignore.case=TRUE)] <- "CLE" 66 | 67 | x[grep("Dallas", x, ignore.case=TRUE)] <- "DAL" 68 | x[grep("Cowboys", x, ignore.case=TRUE)] <- "DAL" 69 | 70 | x[grep("Denver", x, ignore.case=TRUE)] <- "DEN" 71 | x[grep("Broncos", x, ignore.case=TRUE)] <- "DEN" 72 | 73 | x[grep("Detroit", x, ignore.case=TRUE)] <- "DET" 74 | x[grep("Lions", x, ignore.case=TRUE)] <- "DET" 75 | 76 | x[grep("Free", x, ignore.case=TRUE)] <- "FA" 77 | x[grep("Agent", x, ignore.case=TRUE)] <- "FA" 78 | 79 | x[grep("Green Bay", x, ignore.case=TRUE)] <- "GB" 80 | x[grep("Packers", x, ignore.case=TRUE)] <- "GB" 81 | 82 | x[grep("Houston", x, ignore.case=TRUE)] <- "HOU" 83 | x[grep("Texans", x, ignore.case=TRUE)] <- "HOU" 84 | 85 | x[grep("Indianapolis", x, ignore.case=TRUE)] <- "IND" 86 | x[grep("Colts", x, ignore.case=TRUE)] <- "IND" 87 | 88 | x[grep("Jacksonville", x, ignore.case=TRUE)] <- "JAX" 89 | x[grep("Jaguars", x, ignore.case=TRUE)] <- "JAX" 90 | 91 | x[grep("Kansas City", x, ignore.case=TRUE)] <- "KC" 92 | x[grep("Chiefs", x, ignore.case=TRUE)] <- "KC" 93 | 94 | x[grep("Miami", x, ignore.case=TRUE)] <- "MIA" 95 | x[grep("Dolphins", x, ignore.case=TRUE)] <- "MIA" 96 | 97 | x[grep("Minnesota", x, ignore.case=TRUE)] <- "MIN" 98 | x[grep("Vikings", x, ignore.case=TRUE)] <- "MIN" 99 | 100 | x[grep("New England", x, ignore.case=TRUE)] <- "NE" 101 | x[grep("Patriots", x, ignore.case=TRUE)] <- "NE" 102 | 103 | x[grep("New Orleans", x, ignore.case=TRUE)] <- "NO" 104 | x[grep("Saints", x, ignore.case=TRUE)] <- "NO" 105 | 106 | x[grep("Jets", x, ignore.case=TRUE)] <- "NYJ" 107 | 108 | x[grep("Giants", x, ignore.case=TRUE)] <- "NYG" 109 | 110 | x[grep("Oakland", x, ignore.case=TRUE)] <- "OAK" 111 | x[grep("Raiders", x, ignore.case=TRUE)] <- "OAK" 112 | 113 | x[grep("Philadelphia", x, ignore.case=TRUE)] <- "PHI" 114 | x[grep("Eagles", x, ignore.case=TRUE)] <- "PHI" 115 | 116 | x[grep("Pittsburgh", x, ignore.case=TRUE)] <- "PIT" 117 | x[grep("Steelers", x, ignore.case=TRUE)] <- "PIT" 118 | 119 | x[grep("San Diego", x, ignore.case=TRUE)] <- "LAC" 120 | x[grep("Chargers", x, ignore.case=TRUE)] <- "LAC" 121 | x[grep("L.A. Chargers", x, ignore.case=TRUE)] <- "LAC" 122 | x[grep("SD", x, ignore.case=TRUE)] <- "LAC" 123 | 124 | x[grep("Saint Louis", x, ignore.case=TRUE)] <- "LAR" 125 | x[grep("St Louis", x, ignore.case=TRUE)] <- "LAR" 126 | x[grep("St. Louis", x, ignore.case=TRUE)] <- "LAR" 127 | x[grep("Rams", x, ignore.case=TRUE)] <- "LAR" 128 | x[grep("Los Angeles", x, ignore.case=TRUE)] <- "LAR" 129 | x[grep("L.A. Rams", x, ignore.case=TRUE)] <- "LAR" 130 | x[grep("STL", x, ignore.case=TRUE)] <- "LAR" 131 | 132 | x[grep("San Francisco", x, ignore.case=TRUE)] <- "SF" 133 | x[grep("49ers", x, ignore.case=TRUE)] <- "SF" 134 | 135 | x[grep("Seattle", x, ignore.case=TRUE)] <- "SEA" 136 | x[grep("Seahawks", x, ignore.case=TRUE)] <- "SEA" 137 | 138 | x[grep("Tampa Bay", x, ignore.case=TRUE)] <- "TB" 139 | x[grep("Buccaneers", x, ignore.case=TRUE)] <- "TB" 140 | 141 | x[grep("Tennessee", x, ignore.case=TRUE)] <- "TEN" 142 | x[grep("Titans", x, ignore.case=TRUE)] <- "TEN" 143 | 144 | x[grep("Washington", x, ignore.case=TRUE)] <- "WAS" 145 | x[grep("Redskins", x, ignore.case=TRUE)] <- "WAS" 146 | 147 | return(x) 148 | } 149 | 150 | ## simulate regular game 151 | simulate.game <- function(team1, team2){ 152 | Team1Seed <- seeds[seeds$TeamAbb == team1, "Seed"][[1]] 153 | Team2Seed <- seeds[seeds$TeamAbb == team2, "Seed"][[1]] 154 | 155 | if(Team1Seed > Team2Seed){ 156 | tmp <- team1 157 | team1 <- team2 158 | team2 <- tmp 159 | } 160 | 161 | # Extract Probabilities for each team in the matchup 162 | p.1.2 <- teams[teams$home.team == team1 & teams$away.team == team2, "Avg.Prob"][[1]] 163 | p.2.1 <- 1 - p.1.2 164 | 165 | 166 | # simulate Game 167 | game.result <- sample(c(team1, team2), size = 1, prob = c(p.1.2, p.2.1), replace=TRUE) 168 | 169 | # return the winner 170 | game.result 171 | } 172 | 173 | 174 | ## chance.df 175 | chance.df <- function(series){ 176 | 177 | tbl <- table(sim.results.df[ , series]) 178 | df <- data.frame(team = names(tbl), chance = as.numeric(tbl)/sum(tbl)) 179 | df <- df[order(df$chance, decreasing=TRUE), ] 180 | df 181 | } 182 | 183 | 184 | 185 | ############################# 186 | ##### ##### 187 | ##### SET EVERYTHING UP ##### --------------------------------------------------------------------------- 188 | ##### ##### 189 | ############################# 190 | 191 | 192 | # dataframe for results 193 | simulation.results <- c() 194 | 195 | # fix team names 196 | seeds$TeamAbb <- convertTeamAbbreviation(seeds$Team) 197 | teams$home.team <- convertTeamAbbreviation(teams$home.team) 198 | teams$away.team <- convertTeamAbbreviation(teams$away.team) 199 | 200 | # Set number of simulations at 1,000,001 -> Better than Goldman Sachs 201 | ## feel free to lower this number to 10,000-50,000 for it to complete the simulation in a reasonable timeframe 202 | num_sims <- 1000001 203 | i <- 1 204 | 205 | # AFC Playoff Teams 206 | afc.1 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 1, "TeamAbb"][[1]] 207 | afc.2 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 2, "TeamAbb"][[1]] 208 | afc.3 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 3, "TeamAbb"][[1]] 209 | afc.4 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 4, "TeamAbb"][[1]] 210 | afc.5 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 5, "TeamAbb"][[1]] 211 | afc.6 <- seeds[seeds$Conference == "AFC" & seeds$Seed == 6, "TeamAbb"][[1]] 212 | 213 | # NFC Playoff Teams 214 | nfc.1 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 1, "TeamAbb"][[1]] 215 | nfc.2 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 2, "TeamAbb"][[1]] 216 | nfc.3 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 3, "TeamAbb"][[1]] 217 | nfc.4 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 4, "TeamAbb"][[1]] 218 | nfc.5 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 5, "TeamAbb"][[1]] 219 | nfc.6 <- seeds[seeds$Conference == "NFC" & seeds$Seed == 6, "TeamAbb"][[1]] 220 | 221 | 222 | 223 | 224 | ############################### 225 | ##### ##### 226 | ##### Run the Simulations ##### ------------------------------------------------------------------------ 227 | ##### ##### 228 | ############################### 229 | 230 | 231 | 232 | set.seed(1234) 233 | while (i <= num_sims) { 234 | 235 | ##### Wild Card Weekend 236 | # AFC 237 | wc.1.afc <- simulate.game(afc.3, afc.6) 238 | wc.2.afc <- simulate.game(afc.4, afc.5) 239 | 240 | # NFC 241 | wc.1.nfc <- simulate.game(nfc.3, nfc.6) 242 | wc.2.nfc <- simulate.game(nfc.4, nfc.5) 243 | 244 | ##### Divisional Weekend 245 | # AFC 246 | dw.1.afc <- simulate.game(afc.1, wc.2.afc) 247 | dw.2.afc <- simulate.game(afc.2, wc.1.afc) 248 | 249 | # NFC 250 | dw.1.nfc <- simulate.game(nfc.1, wc.2.nfc) 251 | dw.2.nfc <- simulate.game(nfc.2, wc.1.nfc) 252 | 253 | ##### Championship Weekend 254 | # AFC 255 | cw.1.afc <- simulate.game(dw.1.afc, dw.2.afc) 256 | 257 | # NFC 258 | cw.1.nfc <- simulate.game(dw.1.nfc, dw.2.nfc) 259 | 260 | ##### Superbowl 261 | champ <- simulate.game(cw.1.afc, cw.1.nfc) 262 | 263 | #print(paste0("This is the winner ",champ)) 264 | 265 | results.all <- c( 266 | i, 267 | wc.1.afc, 268 | wc.2.afc, 269 | wc.1.nfc, 270 | wc.2.nfc, 271 | dw.1.afc, 272 | dw.2.afc, 273 | dw.1.nfc, 274 | dw.2.nfc, 275 | cw.1.afc, 276 | cw.1.nfc, 277 | champ 278 | ) 279 | 280 | simulation.results <- c(simulation.results, results.all) 281 | 282 | i <- i + 1 283 | } 284 | 285 | 286 | 287 | # Results 288 | sim.results.mat <- matrix(simulation.results, ncol=12, byrow=TRUE) 289 | sim.results.df <- as.data.frame(sim.results.mat) 290 | names(sim.results.df) <- c( 291 | "sim", 292 | "wc.1.afc", 293 | "wc.2.afc", 294 | "wc.1.nfc", 295 | "wc.2.nfc", 296 | "dw.1.afc", 297 | "dw.2.afc", 298 | "dw.1.nfc", 299 | "dw.2.nfc", 300 | "cw.1.afc", 301 | "cw.1.nfc", 302 | "champ" 303 | ) 304 | 305 | 306 | ################################################# 307 | ##### ##### 308 | ##### Create a table with all probabilities ##### ----------------------------------------------------------------------------------------------- 309 | ##### ##### 310 | ################################################# 311 | 312 | # Superbowl Champions 313 | champs.df <- chance.df("champ") 314 | 315 | # Conference Champions 316 | AFCC.df <- chance.df("cw.1.afc") 317 | NFCC.df <- chance.df("cw.1.nfc") 318 | Superbowl <- rbind(AFCC.df, NFCC.df) 319 | 320 | # Divisional Champions 321 | afc.1.df <- chance.df("dw.1.afc") 322 | afc.2.df <- chance.df("dw.2.afc") 323 | nfc.1.df <- chance.df("dw.1.nfc") 324 | nfc.2.df <- chance.df("dw.2.nfc") 325 | Conference <- rbind(afc.1.df, afc.2.df, nfc.1.df, nfc.2.df) 326 | 327 | # Wildcard Games 328 | afc.wc1.df <- chance.df("wc.1.afc") 329 | afc.wc2.df <- chance.df("wc.2.afc") 330 | nfc.wc1.df <- chance.df("wc.1.nfc") 331 | nfc.wc2.df <- chance.df("wc.2.nfc") 332 | Divisional <- rbind(afc.wc1.df, afc.wc2.df, nfc.wc1.df, nfc.wc2.df) 333 | 334 | allteams <- unique(teams$home.team) 335 | allteams <- as.data.frame(allteams) 336 | colnames(allteams) <- "team" 337 | 338 | # Merge all probabilities 339 | all.chances.df <- allteams %>% 340 | left_join(Divisional, by = "team") %>% 341 | rename(Divisional = chance) %>% 342 | left_join(Conference, by = "team") %>% 343 | rename(Conference = chance) %>% 344 | left_join(Superbowl, by = "team") %>% 345 | rename(Superbowl = chance) %>% 346 | left_join(champs.df, by = "team") %>% 347 | rename(Champion = chance) %>% 348 | arrange(desc(Champion), desc(Superbowl), desc(Conference), desc(Divisional)) 349 | 350 | 351 | # Fix percentages 352 | all.chances.df$Divisional <- ifelse(is.na(all.chances.df$Divisional), 0, all.chances.df$Divisional) 353 | all.chances.df$Conference <- ifelse(is.na(all.chances.df$Conference), 0, all.chances.df$Conference) 354 | all.chances.df$Superbowl <- ifelse(is.na(all.chances.df$Superbowl), 0, all.chances.df$Superbowl) 355 | all.chances.df$Champion <- ifelse(is.na(all.chances.df$Champion), 0, all.chances.df$Champion) 356 | 357 | all.chances.df[,2:5] <- sapply(all.chances.df[,2:5], convert_pct) 358 | 359 | 360 | # View results 361 | kable(all.chances.df) 362 | 363 | # Write to a file 364 | output_filename <- "NFLPlayoff_probs_2019.csv" 365 | write.csv(all.chances.df, output_filename, row.names=FALSE) 366 | 367 | --------------------------------------------------------------------------------