Introduction to Elo Rankings and the 'elo' Package

Introduction to Elo Rankings

Elo is a system of ratings/rankings (named after its creator, Arpad Elo) for pairwise matchups. In short, pairs of "teams" ("A" and "B") begin a match with rankings $R_A$ and $R_B$. The result ("score") of the game is coded as 0/0.5/1 for loss/tie/win, respectively. The prior expectation of this result can be expressed as $$P_A = \frac{1}{1 + 10^{(R_B - R_A) / 400}}$$ $$P_B = \frac{1}{1 + 10^{(R_A - R_B) / 400}} = 1 - P_A$$ where $$P_i$$ is the prior probability that team $i$ wins the match.

After each match, ratings are updated as follows: $$R^{new}_A = R_A + K(S_A - P_A)$$ $$R^{new}_B = R_B + K(S_B - P_B) = R_B + K(1 - S_A - (1 - P_A)) = R_B - K(S_A - P_A)$$ where $S_i$ is the score of team $i$ (0/0.5/1) and $K$ is an update weight (commonly called the "k-factor").

Therefore, we see that the system as a whole (all teams) retains ("conserves") its total sum of Elo ratings; for every rating point team A gains/loses, team B loses/gains the same amount.

The elo Package

The elo package includes functions to address all kinds of Elo calculations.

library(elo)

Naming Schema

Most functions begin with the prefix "elo.", for easy autocompletion.

Basic Functions

To calculate the probability team.A beats team.B, use elo.prob():

elo.A <- c(1500, 1500)
elo.B <- c(1500, 1600)
elo.prob(elo.A, elo.B)

To calculate the score update after the two teams play, use elo.update():

wins.A <- c(1, 0)
elo.update(wins.A, elo.A, elo.B, k = 20)

To calculate the new Elo scores after the update, use elo.calc():

elo.calc(wins.A, elo.A, elo.B, k = 20)

It may be helpful to calculate wins.A from raw scores:

points.A <- c(4, 1)
points.B <- c(3, 3)
elo.calc(score(points.A, points.B), elo.A, elo.B, k = 20)

Formula Interface

All of the "basic" functions accept formulas as input:

dat <- data.frame(elo.A = c(1500, 1500), elo.B = c(1500, 1600),
                  wins.A = c(1, 0), k = 20)
form <- wins.A ~ elo.A + elo.B + k(k)
elo.prob(form, data = dat)
elo.update(form, data = dat)
elo.calc(form, data = dat)

Note that for elo.prob(), formula = can be more succinct:

elo.prob(~ elo.A + elo.B, data = dat)

We can even adjust the Elos, for, e.g., home-field advantage.

elo.calc(wins.A ~ adjust(elo.A, 10) + elo.B + k(k), data = dat)

Final Thoughts

All of these functions assume that Elo scores are constant. The next vignette explores calculating "running" Elos.



Try the elo package in your browser

Any scripts or data that you put into this service are public.

elo documentation built on Aug. 23, 2023, 5:10 p.m.