
Bayesian Aldrich-McKelvey scaling (Hare et al. 2015)
Source:R/spatial_voting.R
morie_spatial_voting_bayesian_am.RdRespondent \(i\) places stimulus \(j\) at
$$z_{ij} \sim N(a_i + b_i \hat z_j,\; 1 / (\tau_i \tau_j)),$$
a respondent-specific shift and stretch of the common stimulus
positions \(\hat z\) plus noise whose precision factors into a
respondent and a stimulus part. Priors follow the authors' JAGS
template: \(a_i, b_i \sim U(-100, 100)\),
\(\tau_j \sim G(0.1, 0.1)\), \(\tau_i \sim G(g_a, g_b)\) with
\(g_a, g_b \sim G(0.1, 0.1)\), and \(\hat z\) the standardised
version of \(z^* \sim N(0, 1)\), with the polarity stimulus
restricted to the left (\(z^* \le 0\)). Standardising fixes the
location and scale, the polarity restriction the reflection.
Usage
morie_spatial_voting_bayesian_am(
Z,
n_samples = 1000L,
burn_in = 200L,
polarity = 1L,
seed = 42L
)Value
List: zeta_mean, zeta_sd and
zeta_interval (central 95\
b (posterior mean shifts and stretches), tau_stimulus,
draws (retained \(\hat z\), one row per draw),
n_samples, engine.
Details
Gibbs sampling: \(a_i \mid b_i\) and \(b_i \mid a_i\) are truncated
normals, \(\tau_j\), \(\tau_i\) and \(g_b\) conjugate gammas, and
\(g_a\) and each \(z^*_j\) are slice sampled (Neal 2003); every
\(z^*_j\) enters every \(\hat z\) through the mean and standard
deviation, so the stimuli are updated one at a time against the full
likelihood. On 150 simulated respondents and five stimuli the
posterior means and standard deviations agree with the JAGS model run
through asmcjr::BAM to the third decimal.
References
Hare, C., Armstrong, D. A., Bakker, R., Carroll, R. and Poole, K. T. (2015). Using Bayesian Aldrich-McKelvey scaling to study citizens' ideological preferences and perceptions. American Journal of Political Science 59(3), 759-774.
Neal, R. M. (2003). Slice sampling. Annals of Statistics 31(3), 705-767.
Examples
set.seed(1)
zt <- c(-1, -0.3, 0.4, 1.2)
Z <- rnorm(40, 0, 0.5) + outer(runif(40, 0.5, 1.5), zt) +
matrix(rnorm(160, 0, 0.3), 40, 4)
fit <- morie_spatial_voting_bayesian_am(Z, n_samples = 200L,
burn_in = 100L)
round(fit$zeta_mean, 2)
#> [1] -1.13 -0.42 0.38 1.18
# the true positions, standardised the same way
round((zt - mean(zt)) / sd(zt), 2)
#> [1] -1.14 -0.40 0.34 1.19