In an experiment with Approximate Bayesian Computation and R packages, I uploaded a new R package of my own to GitHub a few days ago named bcf for Bayesian Coin Flip. It simulates -person games of skill, approximating these games as multiple players flipping coins with different “fairness parameters” . The first player to obtain a “Heads” result first wins, dealing with ties in a sensible way.1
The ABC concept is well explained in a pair of articles. First, Rasmus Bååth introduces ABC through an exercise involving mismatched socks in the laundry (thanks for pointing me to this, Kenny). And Darren Wilkinson also does a nice job explaining how ABC works.
As far as bcf is concerned, the probability of a coin coming up Heads is picked from a distribution assigned to each player, . The package then simulates a set of games using these parameters and provides samples from the joint distribution . Finally, by keeping only the data that match an observed result, we end up with a distribution proportional to the posterior .2
Example Usage
I built the package to better understand ABC and to humorously model our office’s dart-playing abilities. To keep things simple, the bcf package only provides a few functions: We can initialize a player, run a game, and use the results of the game to update a player’s statistics.
A basic game might go like so: We assume a pretty weak prior () for each player before running a few games. After each game, we update the involved players.
In practice, I think it’s pretty easy to use. First, instantiate a few players:
library(bcf)
tom <- new_player("Tom", alpha = 1.2, beta = 1.2)
david <- new_player("David", alpha = 1.2, beta = 1.2)
kevin <- new_player("Kevin", alpha = 1.2, beta = 1.2)
print(tom)
## UUID: d8cfe17e-c81d-11e7-9f88-f45c899c4b7b
## Name: Tom
##
## Games: 0
## Wins: 0
## Losses: 0
##
## Est. Distribution: Beta(1.200, 1.200)
## MAP Win Percentage: 50.000
Then simulate three games for which we already have results:
# Tom wins, David places second, Kevin finishes third
game_1 <- abc_coin_flip_game(
players = list(tom, david, kevin),
result = c(1, 2, 3),
iters = 5000, cores = 5L)
## No. players: 3
## Assign result: 1, 2, 3
## Iters: 5000
## CPU cores: 5
## Workloads: 1000, 1000, 1000, 1000, 1000
tom <- update_player(tom, game_1)
david <- update_player(david, game_1)
kevin <- update_player(kevin, game_1)
# Tom wins, Kevin places second, David finishes third
game_2 <- abc_coin_flip_game(
players = list(tom, david, kevin),
result = c(1, 3, 2),
iters = 5000, cores = 5L)
tom <- update_player(tom, game_2)
david <- update_player(david, game_2)
kevin <- update_player(kevin, game_2)
# Tom finishes second, David wins, Kevin finishes third
game_3 <- abc_coin_flip_game(
players = list(tom, david, kevin),
result = c(2, 1, 3),
iters = 5000, cores = 5L)
tom <- update_player(tom, game_3)
david <- update_player(david, game_3)
kevin <- update_player(kevin, game_3)
bcf then provides methods for examining both players and games:
print(game_3)
## # A tibble: 6 x 6
## Tom David Kevin outcome n pct
## <dbl> <dbl> <dbl> <chr> <int> <dbl>
## 1 1 2 3 1627 32.5
## 2 1 3 2 1917 38.3
## 3 2 1 3 *** 439 8.8
## 4 2 3 1 590 11.8
## 5 3 1 2 222 4.4
## 6 3 2 1 205 4.1
plot(game_3)
plot(tom)
This has been a pretty fun experiment in ABC and in R packaging. I’ll update this post if I ever return to the project.
-
If mote than one player obtains the same result on a given flip, these players play one or more sub-games to break the tie. ↩︎
-
One gotcha—for now—is that bcf imposes a beta distribution for each player’s win probability. After working out the likelihood on paper, I don’t think the posterior is actually a beta…just almost a beta. The possibility of ties and additional rounds adds complication. ↩︎