## Sunday, April 14, 2013

### Methodological update

The publication of a Galaxy poll in today's Murdoch tabloids allows me to explain how I have updated my Bayesian models to handle primary vote predictions from the polling agencies.

We will begin with the primary vote estimate. I have rewritten my TPP JAGS model for this purpose. The TPP model was a fairly simple affair; it was only populated with one dimensional arrays, In contrast, the primary vote model is populated with a number of two-dimensional matrices (I was seeking a more integrated solution than the one I have got working).

In the process of testing the new model, I discovered that the element of the model that allowed for rounding errors accounted for about half the reason why the model was not adding to 100 percent. So I have deleted this element from both the Primary and TPP models. This deletion means the line produced by the model is a little more "noisy" than the line from the earlier model.

While there are still issues with the model adding to 100 per cent, it typically hovers between 99.5 and 100.5. I am looking for strategies to constrain the model to add to 100 per cent. If you have any suggestions, I would gladly welcome them.

The primary voting model is as follows.

    model {
## -- observational model - note: rounding commented out ...
for(poll in 1:NUMPOLLS) { # for each poll result - rows
for(party in 1:PARTIES) { # for each party - columns
#roundingEffect[poll, party] ~ dunif(-houseRounding[poll], houseRounding[poll])
yhat[poll, party] <- houseEffect[house[poll], party] + walk[pollDay[poll], party] #+
#roundingEffect[poll, party]
primaryVotes[poll, party] ~ dnorm(yhat[poll, party], precision[poll, party])
}
}

## -- temporal model
for (party in 1:PARTIES) { # columns
for(day in 2:PERIOD) { # rows
walk[day, party] ~ dnorm(walk[day-1, party], walkPrecision[party])
}
}

## -- sum-to-zero constraint on house effects (ignoring Morgan F2F)
for (party in 1:PARTIES) { # for each party
houseEffect[1, party] <- -sum( houseEffect[2:HOUSECOUNT, party] ) +
houseEffect[MORGANF2F, party]
}

## -- constrained priors for the daily walk
for(party in 1:PARTIES) { # for each party
sigmaWalk[party] ~ dunif(0, 0.01)                ## uniform prior on std. dev.
walkPrecision[party] <- pow(sigmaWalk[party], -2)## for the day-to-day random walk
}

## -- uninformative priors for daily walk
for (party in 1:PARTIES) { # for each party
walk[1, party] ~ dunif(0.0, 1.0) # completely uninformative
}

## -- vague normal priors for house effects
for (party in 1:PARTIES) { # for each party (cols)
for(house in 2:HOUSECOUNT) { #  (rows)
houseEffect[house, party] ~ dnorm(0, pow(0.1, -2))
}
}
}

The results from the model are as follows:

The underlying house effects were as follows.

A couple of diagnostic charts follow.

The TPP model is only changed a little. I made the prior for the daily walk the uniform distribution between 0 and 100%. And I have removed the the element of the model that dealt with rounding adjustments from the pollster. The results are as follows: