# Modelling a mixed model in JAGS/BUGS [closed]

I am currently in the process of implementing a model for soccer result prediction in JAGS. Actually, I have implemented several, but I have reached my most difficult challenge yet: A model described by Rue & Salvesen in their paper "Prediction and retrospective analysis of soccer matches in a league". Their model uses a mixed model for truncating a Poisson distribution conditioned on attack / defense strength after 5 goals. They have also adapted a law from Dixon & Coles (1997) to increase the probability of 0-0 and 1-1 results in low-scoring games.

My problem is as follows, I am trying to implement the mixed-model: $$\pi_{g1}(x_{A,B},y_{A,B}|\lambda_{A,B}^{(x)},\lambda_{A,B}^{(y)}) = \kappa(x_{A,B},y_{A,B}|\lambda_{A,B}^{(x)},\lambda_{A,B}^{(y)})Po(x_{A,B}|\lambda_{A,B}^{(x)})Po(y_{A,B}|\lambda_{A,B}^{(y)})$$ Where $x_{A,B}$ denotes the number of goals scored by the home team in the game between teams A and B, and $log(\lambda_{A,B}^{(x)})$ denotes the teams' strength. I have tried to implement these two laws in JAGS by using the zeros-ones trick, but with no luck so far (error: illegal parent values). My JAGS model so far:

data {
C <- 10000

for(i in 1:noGames) {
zeros[i] <- 0
}

homeGoalAvg <- 0.395
awayGoalAvg <- 0.098

rho <- 0.1
}

model {

### Time model - Brownian motion
tau ~ dgamma(10, 0.1)
precision ~ dgamma(0.1, 1)

for(t in 1:noTeams) {
attack[t, 1] ~ dnorm(0, precision)
defence[t, 1] ~ dnorm(0, precision)

for(s in 2:noTimeslices) {
attack[t, s] ~ dnorm(attack[t, (s-1)], (tau * precision) /
(abs(days[t,s]-days[t,s-1])))
defence[t, s] ~ dnorm(defence[t, (s-1)], (tau * precision) /
(abs(days[t,s]-days[t,s-1])))
}
}

### Goal model
gamma ~ dunif(0, 0.1)

for(i in 1:noGames) {

delta[i]            <-  (
attack[team[i, 1], timeslice[i, 1]] +
defence[team[i, 1], timeslice[i, 1]] -
attack[team[i, 2], timeslice[i, 2]] -
defence[team[i, 2], timeslice[i, 2]]
) / 2

log(homeLambda[i])  <-  (
homeGoalAvg +
(
attack[team[i, 1], timeslice[i, 1]] -
defence[team[i, 2], timeslice[i, 2]] -
gamma * delta[i]
)
)

log(awayLambda[i])  <-  (
awayGoalAvg +
(
attack[team[i, 2], timeslice[i, 2]] -
defence[team[i, 1], timeslice[i, 1]] +
gamma * delta[i]
)
)

goalsScored[i, 1] ~ dpois( homeLambda[i] )
goalsScored[i, 2] ~ dpois( awayLambda[i] )

is0X[i] <- ifelse(goalsScored[i, 1]==0, 1, 0)
isX0[i] <- ifelse(goalsScored[i, 2]==0, 1, 0)
is1X[i] <- ifelse(goalsScored[i, 1]==1, 1, 0)
isX1[i] <- ifelse(goalsScored[i, 2]==1, 1, 0)
is00[i] <- is0X[i] * isX0[i]
is01[i] <- is0X[i] * isX1[i]
is10[i] <- is1X[i] * isX0[i]
is11[i] <- is1X[i] * isX1[i]

kappa[i] <- (
is00[i] * ( 1 + (homeLambda[i] * awayLambda[i] * rho) ) +
is01[i] * ( 1 - (homeLambda[i] * rho                ) ) +
is10[i] * ( 1 - (awayLambda[i] * rho                ) ) +
is11[i] * ( 1 + rho                                     ) +
1 -       ( is00[i] + is01[i] + is10[i] + is11[i]     )
)

# This does not work!
zeros[i] ~ dpois(-log(kappa[i]) + C)
}

}

• I think Marat is close - there could be something with the ifelse. I would recommend to simplify your model to smallest version that doesn't work! This could show you the way. – Curious Dec 7 '13 at 9:22
• You could try Stan instead - it enables you to do actual programming rather then "tricks" stuff. Also @Curious is right - try to simplify your model: start with very basic one and make it a little bit more complicated one step at a time until it stops working. – Tim Feb 25 '15 at 11:51

is0X[i] <- ifelse(goalsScored[i, 1]==0, 1, 0)


you should try

is0X[i] <- goalsScored[i, 1]==0


goalsScored[i, 1]==0 returns 1 if True and 0 if False

• Thanks man, but that didn't do it for me. Still haven't found a solution to this. – thomrand Jan 19 '13 at 12:57

I do not think you can define zeros[i] ~ dpois(-log(kappa[i]) + C) inside of the model construction.

Try to revise the code to be zeros ~ dpois(-log(kappa[i]) + C) (take out of '[i]').

After defining the model, you re-define the data at zeors:

data\$zero=0


Try if this works.

Refer to The zero-crossings trick for JAGS: Finding roots stochastically for more information.