---
title: "Introduction to Elo Rankings and the 'elo' Package"
author: "Ethan Heinzen"
output:
  rmarkdown::html_vignette:
    toc: true
vignette: >
  %\VignetteIndexEntry{Introduction to Elo Rankings and the 'elo' Package}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

# 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.

```{r}
library(elo)
```

## Naming Schema

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`.

# Basic Functions

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

```{r}
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()`:

```{r}
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()`:

```{r}
elo.calc(wins.A, elo.A, elo.B, k = 20)
```

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

```{r}
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:

```{r}
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:

```{r}
elo.prob(~ elo.A + elo.B, data = dat)
```

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

```{r}
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.
