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.
elo
PackageThe elo
package includes functions to address all kinds of Elo calculations.
library(elo)
Most functions begin with the prefix "elo.", for easy autocompletion.
Vectors or scalars of Elo scores are denoted elo.A
or elo.B
.
Vectors or scalars of wins by team A are denoted by wins.A
.
Vectors or scalars of win probabilities are denoted by p.A
.
Vectors of team names are denoted team.A
or team.B
.
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)
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)
All of these functions assume that Elo scores are constant. The next vignette explores calculating "running" Elos.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.