Build a Quick Elo

[This article was first published on Analysis of AFL, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

One of my favourite sites is squiggle, mainly because I like to check out what other people have tipped, what their respective margins are and how they are aligned.

As some of you know James and I have been working on an AFL R package called fitzRoy

One of our main goals is to get more people to build out AFL models.

For me that’s mainly because I like reading AFL stats content, be it probably a bit too much!

Having done a presentation at useR, one of the main problems I found with getting people wanting to give it a go is that they feel as though building their own model is simply too complex, that they are out of their depth.

Well I am here to say, that’s not true. Anyone can give it a go.

I think there are many camps to the AFL stats fanbase. One of which I would like to try and include more.

That is those who feel as though they can’t contribute or can’t analyse simply because they don’t know R/How to build out models.

So while you might be reading other blogs and sure they are “coding” it up from “scratch”. I think a missing point to this thought is while that’s true, it also doesn’t have to be you. Lots of people develop packages and answer questions on sites like stackoverflow.

So if you have ever wanted to build your own ELO for AFL why not use this ELO package. That’s what it was designed for, for people to use it.

## -- Attaching packages ----------------------- tidyverse 1.2.1 --
## v ggplot2     v purrr   0.2.5     
## v tibble  1.4.2          v dplyr   0.7.6     
## v tidyr   0.8.1          v stringr 1.3.1     
## v readr   1.1.1          v forcats 0.3.0
## -- Conflicts -------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
##     date
# Get data
results <- fitzRoy::get_match_results()
results <- results %>%filter(Season %in% c(2014,2015,2016,2017))%>%
  mutate(seas_rnd = paste0(Season, ".", Round.Number),
         First.Game = ifelse(Round.Number == 1, TRUE, FALSE)

fixture <- fitzRoy::get_fixture()
fixture <- fixture %>%
  # filter(Date > max(results$Date)) %>%
  mutate(Date = ymd(format(Date, "%Y-%m-%d"))) %>%
  rename(Round.Number = Round)

# Simple ELO
# Set parameters
HGA <- 0
carryOver <- 1
B <- 0.03
k_val <- 20

# Create margin function to ensure result is between 0 and 1
map_margin_to_outcome <- function(margin, B) {
  1 / (1 + (exp(-B * margin)))

# Run ELO <-
  map_margin_to_outcome(Home.Points - Away.Points, B = B) ~
    adjust(Home.Team, HGA) +
    Away.Team +
    group(seas_rnd) ,
    # regress(First.Game, 1500, carryOver),
  k = k_val,
  data = results

# as.matrix(
# final.elos(

# Do predictions
fixture <- fixture %>%filter(Season==2018)%>%
  mutate(Prob = predict(, newdata = fixture))

results <- fitzRoy::get_match_results()
# View(fixture)

results<-select(results,Date, Home.Team, Margin)

left_join(fixture, results, by=c("Date"="Date","Home.Team"="Home.Team" ))%>%
  mutate(accuracy=sum(right_pick, na.rm = TRUE))%>%View()

So if you run that script end to end you should have a working ELO model that you can play around with.

Somethings to note.

  • This model has no HGA, yes you read that right! HGA <- 0 its set to 0 here!
  • No mean reversion between seasons! carryOver <- 1 I think thats right?
  • I set k=20 for no reason other than I read this blog post here 538 ELO, is that the best way to decide? What would you do differently?

To leave a comment for the author, please follow the link and comment on their blog: Analysis of AFL. offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)