Usage help: observed data
Hi!
I would like to model a process very similar to what is described Probabilistic Models of Cognition under the name of Tug of War.
There is a game involving two players. The outcome is always either a win or loss. Each player has some internal strength. Probability of winning player1 over player2 is given as P_ij = strength_i - strength_j.
I have historic data of outcomes for several players and would like to find out each player strength.
If I use PyMC, then the modelling goes like this:
model = pm.Model()
with model:
strength = pm.Normal("strength", 0, 1, shape=num_players)
diffs = strength[games.Player1] - strength[games.Player2]
obs = pm.Bernoulli("wins", logit_p=diffs, observed=games.Player1Wins)
trace = pm.sample()
where games is a table with 3 columns. Player1 - id of the first player. Player2 - id of the second player. Player1Wins - 1 if player one wins, 0 otherwise.
I tried to come up with that in WebPPL:
var model = function() {
var strength = mem(function (person) {return gaussian(0, 1)})
var winner = function (player1, player2) {
strength(player1) > strength(player2) ? player1 : player2 }
var beat = function(player1,player2){winner(player1,player2) == player1}
mapData({data: [
['Player-2', 'Player-1'],
['Player-3', 'Player-1'],
['Player-3', 'Player-2'],
['Player-2', 'Player-1'],
['Player-3', 'Player-1'],
['Player-2', 'Player-1'],
['Player-4', 'Player-3'],
['Player-4', 'Player-3'],
]}, function (gameOutcome) {
condition(beat(gameOutcome0], gameOutcome[1]))
})
return strength('Player-1')
}
var dist = Infer({method: 'MCMC', kernel: 'MH', samples: 100},
model)
print('Expected strength: ' + expectation(dist[0]))
viz(dist)
I have a couple of questions regarding this code:
- Does it seems right to provide observable data the way I did?
- I am unsure how to obtain strength of all players in one go. Names and number of players will be dynamic, I do not know it beforehand.
I think I found a way of providing the data that is more similar to PyMC:
var model = function() {
var strength = mem(function (person) {return gaussian(0, 1)})
var p_win = function(p1, p2) {
strength(p1) - strength(p2)
}
var sigmoid = function(x) {
return 1 / (1 + Math.exp(-1 * x))
}
mapData({data: [
['Player-1', 'Player-2', 0],
['Player-1', 'Player-3', 0],
['Player-2', 'Player-3', 0],
['Player-1', 'Player-2', 0],
['Player-3', 'Player-1', 1],
['Player-2', 'Player-1', 1],
['Player-4', 'Player-3', 1],
['Player-4', 'Player-3', 1],
]}, function (gameOutcome) {
var logit = p_win(gameOutcome[0], gameOutcome[1])
var firstWon = gameOutcome[2] == 1 ? true : false
factor(Bernoulli({p: sigmoid(logit)}).score(firstWon))
})
return strength('Player-1')
}
var dist = Infer({method: 'MCMC', kernel: 'MH', samples: 8000}, model)
Still it is not clear to me how to obtain/work with strengths of all players.
it may be helpful to use observe instead of factor plus score (though it does something very similar).
you can return the object of all strengths ({player1: strength('Player-1'), player2: ...}) and then eg use viz.marginals` to examine them. some of the examples in the learning as inference section of probmods should help.