Build a Quick Elo
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.
library(tidyverse) ## -- Attaching packages ----------------------- tidyverse 1.2.1 -- ## v ggplot2 3.0.0.9000 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() library(elo) library(fitzRoy) library(lubridate) ## ## 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 elo.data <- elo.run( 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.data.frame(elo.data) # as.matrix(elo.data) # final.elos(elo.data) # Do predictions fixture <- fixture %>%filter(Season==2018)%>% mutate(Prob = predict(elo.data, 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(pick=if_else(Prob>0.5,1,-1))%>% mutate(correct=pick*Margin)%>% mutate(right_pick=if_else(correct>0,1,0))%>% 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?
R-bloggers.com 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.