Bayesian Coin Flips—The bcf Package

November 12, 2017 at 10 PM

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.


  1. 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. ↩︎

  2. 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. ↩︎