Predict the 2020 NCAA Football Season with Linear and Logistic Regression in R
By: Matt C
Tags: Logistic Regression, Data Science, R Programming, Linear Regression, NCAA Football

The NCAA_L1_Teams dataset contains a list of over 500 teams and a dummy variable FBS which is 1 if the team is in the FBS and 0 if not.

Setting up the Data

To make the forecasts we’ll need a ranking system. Elo is the ranking system used in chess and is fairly easy to implement. It simply awards or subtracts points based on weather a team wins or loses and the change in ranking is based the relative strength of a teams opponent. So if a team with a high ranking beats a team with a low ranking neither rankings will change much because that was the expected outcome. However, if a team with a much lower ranking wins both teams will experience a large change to reflect the upset.

To implement this system, first we need to add two variables ELO and Opp_ELO to the NCAA_L1 dataset. We’ll initialize both to 0, these values will get overwritten when we run our ranking algorithm.

We also need to convert the Results column to numeric values.

Next we need to add the ELO column to the NCAAF_L1_Teams dataset. This dataset will act as a database for each teams current rating. We’ll initialize to 1500 if the team is FBS and 1200 if not.

We’ll need to separate the games that haven’t been played from the games that have been played. We’ll save the upcoming games in a variable called NCAAF_L1_Future with the following filter() function.

Now we’ll select only games that have been played in the original NCAAF_L1 dataset. We also need to sort the dataset by Date and Game_ID. It’s very important that the dataset is in order by date so that the Elo ranking system can apply rankings in chronological order.

Creating the Elo Rankings

We start by looping through all of the rows in the NCAAF_L1 dataset. However, we only want to execute ranking updates when the row is odd because, remember, each game is doubled in this dataset.

First two games in NCAAF_L1

The first line after the loop is an if statement to ensure the ranking system only updates if i is odd. Even though we’re only executing ranking updates when i is odd, we’ll simultaneously update the even rows by subsetting them with i+1.

Inside the loop the first thing we need to do is store the two teams into variables Team_A and Team_B, and the results for each team into the variables Result_A and Result_B.

Then we load the current Elo ranking from the NCAAF_L1_Teams dataset into ELO_A and ELO_B.

To recreate each teams Elo history we need to add back the rankings to the NCAA_L1 dataset.

I’m not going to explain each component of Elo, but here is a source if you’re interested:

https://metinmediamath.wordpress.com/2013/11/27/how-to-calculate-the-elo-rating-including-example/

Otherwise, we can run the following code to update each teams Elo:

Finally, update the NCAAF_L1_Teams dataset with each teams new Elo.

The full code inside the for loop is as follows:

View the Top 25 Rankings

Create the spread and win percentage models

First, we need to create a few variables in the NCAAF_L1 dataset to set up the models. We’ll recast ELO and Opp_ELO as numeric variables just to be sure we don’t get any errors. Then we’ll add Elo_Difference, which as the name implies, is the difference between both team’s rankings. This is going to be the main variable in our model.

We can get a naïve view of how well the ranking system can predict games simply by comparing Elo. To do so we’ll create a variable Elo_Forecast_Pred where if Elo is greater than Opp_Elo we would predict that result is a win. If we create a variable Elo_Forecast_Result, we can evaluate the ranking system accuracy by placing a 1 into the it if the prediction is accurate.

The following snippet looks at how well the Elo rankings predicted the 2019 season:

It predicts ~72% of games. Which is pretty good considering we’re only dealing with high level win/loss data.