Chapter 6 Multilevel modeling

6.1 Intro to multilevel modeling

[Explanation on what multilevel modeling is - structure in the data, partial pooling, repeated measures]

6.2 A multilevel version of the biased agent and of the simple memory agent

We are now conceptualizing our agents as being part of (sampled from) a more general population. This general population is characterized by a population level average parameter value (e.g. a general bias of 0.8 as we all like right hands more) and a certain variation in the population (e.g. a standard deviation of 0.1, as we are all a bit different from each other). Each biased agent’s rate is then sampled from that distribution. Same for the memory agents.

[MISSING: DAG PLOTS OF THE TWO SCENARIOS]

Again, it’s practical to work in log odds. Why? Well, it’s not unconceivable that an agent would be 3 sd from the mean. So a biased agent could have a rate of 0.8 + 3 * 0.1, which gives a rate of 1.1. It’s kinda impossible to choose 110% of the time the right hand. We want an easy way to avoid these situations without too carefully tweaking our parameters, or including exception statements (e.g. if rate > 1, then rate = 1). Conversion to log odds is again a wonderful way to work in a boundless space, and in the last step shrinking everything back to 0-1 probability space.

N.B. we model all agents with some added noise as we assume it cannot be eliminated from our studies.

pacman::p_load(tidyverse,
               here,
               posterior,
               cmdstanr,
               brms, tidybayes)

# Shared parameters
agents <- 100
trials <- 120
noise <- 0

# Biased agents parameters
rateM <- 1.386 # roughly 0.8 once inv_logit scaled
rateSD <- 0.65 # roughly giving a sd of 0.1 in prob scale

# Memory agents parameters
biasM <- 0
biasSD <- 0.1
betaM <- 1.5
betaSD <- 0.3
# Functions of the agents
RandomAgentNoise_f <- function(rate, noise) {
  choice <- rbinom(1, 1, inv_logit_scaled(rate))
  if (rbinom(1, 1, noise) == 1) {
    choice = rbinom(1, 1, 0.5)
  }
  return(choice)
}

MemoryAgentNoise_f <- function(bias, beta, otherRate, noise) {
  rate <- inv_logit_scaled(bias + beta * logit_scaled(otherRate))
  choice <- rbinom(1, 1, rate)
  if (rbinom(1, 1, noise) == 1) {
    choice = rbinom(1, 1, 0.5)
  }
  return(choice)
}

6.3 Generating the agents

[MISSING: PARALLELIZE]

# Looping through all the agents to generate the data.
d <- NULL

for (agent in 1:agents) {
  
  rate <- rnorm(1, rateM, rateSD)
  bias <- rnorm(1, biasM, biasSD)
  beta <- rnorm(1, betaM, betaSD)
  
  randomChoice <- rep(NA, trials)
  memoryChoice <- rep(NA, trials)
  memoryRate <- rep(NA, trials)
  
  for (trial in 1:trials) {
    
    randomChoice[trial] <- RandomAgentNoise_f(rate, noise)
    if (trial == 1) {
      memoryChoice[trial] <- rbinom(1,1,0.5)
    } else {
      memoryChoice[trial] <- MemoryAgentNoise_f(bias, beta, mean(randomChoice[1:trial], na.rm = T), noise)
    }
  }
  
  temp <- tibble(agent, trial = seq(trials), randomChoice, randomRate = rate, memoryChoice, memoryRate, noise, rateM, rateSD, bias, beta, biasM, biasSD, betaM, betaSD)
  
  if (agent > 1) {
    d <- rbind(d, temp)
  } else{
    d <- temp
  }
  
}

d <- d %>% group_by(agent) %>% mutate(
  randomRate = cumsum(randomChoice) / seq_along(randomChoice),
  memoryRate = cumsum(memoryChoice) / seq_along(memoryChoice)
)

6.4 Plotting the agents

# A plot of the proportion of right hand choices for the random agents
p1 <- ggplot(d, aes(trial, randomRate, group = agent, color = agent)) + 
  geom_line(alpha = 0.5) + 
  geom_hline(yintercept = 0.5, linetype = "dashed") + 
  ylim(0,1) + 
  theme_classic() 
# A plot of the proportion of right hand choices for the memory agents
p2 <- ggplot(d, aes(trial, memoryRate, group = agent, color = agent)) + 
  geom_line(alpha = 0.5) + 
  geom_hline(yintercept = 0.5, linetype = "dashed") + 
  ylim(0,1) + 
  theme_classic() 
p1 + p2

# A plot of whether memory and random agents are matched in proportion at different stages

p3 <- d %>% subset(trial == 10) %>% ggplot(aes(randomRate, memoryRate)) +
  geom_point() +
  geom_smooth(method = lm) +
  geom_abline(intercept = 0, slope = 1, color = "red") +
  xlim(0.25, 1) +
  ylim(0.25, 1) +
  xlab("correlation at 10 trials") +
  theme_bw()

p4 <- d %>% subset(trial == 60) %>% ggplot(aes(randomRate, memoryRate)) +
  geom_point() +
  geom_smooth(method = lm) +
  geom_abline(intercept = 0, slope = 1, color = "red") +
  xlim(0.25, 1) +
  ylim(0.25, 1) +
  xlab("correlation at 60 trials") +
  theme_bw()

p5 <- d %>% subset(trial == 120) %>% ggplot(aes(randomRate, memoryRate)) +
  geom_point() +
  geom_smooth(method = lm) +
  geom_abline(intercept = 0, slope = 1, color = "red") +
  xlim(0.25, 1) +
  ylim(0.25, 1) +
  xlab("correlation at 120 trials") +
  theme_bw()

p3 + p4 + p5
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 7 rows containing missing values (`geom_smooth()`).
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 6 rows containing missing values (`geom_smooth()`).

Note that as the n of trials increases, the memory model matches the random model better and better

6.5 Coding the multilevel agents

6.5.1 Multilevel random

Remember that the simulated parameters are: * biasM <- 0 * biasSD <- 0.1 * betaM <- 1.5 * betaSD <- 0.3

Prep the data

d1 <- d %>% 
  subset(select = c(agent, randomChoice)) %>% 
  mutate(row = row_number()) %>% 
  pivot_wider(names_from = agent, values_from = randomChoice)

## Create the data
data <- list(
  trials = trials,
  agents = agents,
  h = as.matrix(d1[,2:101])
)
stan_model <- "
//
// This STAN model infers a random bias from a sequences of 1s and 0s (right and left). Now multilevel
//

functions{
  real normal_lb_rng(real mu, real sigma, real lb) { // normal distribution with a lower bound
    real p = normal_cdf(lb | mu, sigma);  // cdf for bounds
    real u = uniform_rng(p, 1);
    return (sigma * inv_Phi(u)) + mu;  // inverse cdf for value
  }
}

// The input (data) for the model. n of trials and h of hands
data {
 int<lower = 1> trials;
 int<lower = 1> agents;
 array[trials, agents] int h;
}

// The parameters accepted by the model. 
parameters {
  real thetaM;
  real<lower = 0> thetaSD;
  array[agents] real theta;
}

// The model to be estimated. 
model {
  target += normal_lpdf(thetaM | 0, 1);
  target += normal_lpdf(thetaSD | 0, .3)  -
    normal_lccdf(0 | 0, .3);

  // The prior for theta is a uniform distribution between 0 and 1
  target += normal_lpdf(theta | thetaM, thetaSD); 
 
  for (i in 1:agents)
    target += bernoulli_logit_lpmf(h[,i] | theta[i]);
  
}


generated quantities{
   real thetaM_prior;
   real<lower=0> thetaSD_prior;
   real<lower=0, upper=1> theta_prior;
   real<lower=0, upper=1> theta_posterior;
   
   int<lower=0, upper = trials> prior_preds;
   int<lower=0, upper = trials> posterior_preds;
   
   thetaM_prior = normal_rng(0,1);
   thetaSD_prior = normal_lb_rng(0,0.3,0);
   theta_prior = inv_logit(normal_rng(thetaM_prior, thetaSD_prior));
   theta_posterior = inv_logit(normal_rng(thetaM, thetaSD));
   
   prior_preds = binomial_rng(trials, inv_logit(thetaM_prior));
   posterior_preds = binomial_rng(trials, inv_logit(thetaM));
  
}
"
write_stan_file(
  stan_model,
  dir = "stan/",
  basename = "W5_MultilevelBias.stan")

file <- file.path("stan/W5_MultilevelBias.stan")
mod <- cmdstan_model(file, 
                     cpp_options = list(stan_threads = TRUE),
                     stanc_options = list("O1"))

# The following command calls Stan with specific options.
samples <- mod$sample(
  data = data,
  seed = 123,
  chains = 2,
  parallel_chains = 2,
  threads_per_chain = 2,
  iter_warmup = 2000,
  iter_sampling = 2000,
  refresh = 500,
  max_treedepth = 20,
  adapt_delta = 0.99,
)

samples$save_object(file = "simmodels/W5_MultilevelBias.RDS")

6.5.2 Assessing multilevel random agents

Besides the usual prior predictive checks, prior posterior update checks, posterior predictive checks, based on the population level estimates; we also want to plot at least a few of the single agents to assess how well the model is doing for them.

[MISSING: PLOT MODEL ESTIMATES AGAINST N OF HEADS BY PARTICIPANT]

samples <- readRDS("simmodels/W5_MultilevelBias.RDS")

samples$cmdstan_diagnose()
## File /var/folders/lt/zspkqnxd5yg92kybm5f433_cfjr0d6/T/RtmpTP5vj3/W5_MultilevelBias-202303101235-1-84831d.csv not found
## File /var/folders/lt/zspkqnxd5yg92kybm5f433_cfjr0d6/T/RtmpTP5vj3/W5_MultilevelBias-202303101235-2-84831d.csv not found
## No valid input files, exiting.
samples$summary() 
## # A tibble: 109 × 10
##    variable      mean    median     sd    mad        q5      q95  rhat ess_bulk ess_tail
##    <chr>        <dbl>     <dbl>  <dbl>  <dbl>     <dbl>    <dbl> <dbl>    <dbl>    <dbl>
##  1 lp__     -5780.    -5780.    7.26   7.35   -5792.    -5.77e+3  1.00    1370.    2125.
##  2 thetaM       1.49      1.49  0.0664 0.0678     1.38   1.60e+0  1.00    7644.    3557.
##  3 thetaSD      0.637     0.634 0.0523 0.0526     0.557  7.27e-1  1.00    5220.    3381.
##  4 theta[1]     0.663     0.661 0.184  0.188      0.366  9.68e-1  1.00    8209.    2723.
##  5 theta[2]     0.909     0.909 0.190  0.195      0.604  1.22e+0  1.00   10277.    2844.
##  6 theta[3]     1.28      1.27  0.216  0.213      0.932  1.64e+0  1.00    9117.    2544.
##  7 theta[4]     2.16      2.15  0.274  0.279      1.73   2.62e+0  1.00    8381.    2508.
##  8 theta[5]     1.51      1.50  0.217  0.214      1.16   1.86e+0  1.00    8492.    2303.
##  9 theta[6]     2.32      2.31  0.281  0.273      1.88   2.80e+0  1.00    9372.    2814.
## 10 theta[7]     2.10      2.09  0.275  0.267      1.66   2.57e+0  1.00    9292.    2740.
## # ℹ 99 more rows
draws_df <- as_draws_df(samples$draws()) 

ggplot(draws_df, aes(.iteration, thetaM, group = .chain, color = .chain)) +
  geom_line(alpha = 0.5) +
  theme_classic()

ggplot(draws_df, aes(.iteration, thetaSD, group = .chain, color = .chain)) +
  geom_line(alpha = 0.5) +
  theme_classic()

ggplot(draws_df) +
  geom_histogram(aes(prior_preds), color = "darkblue", fill = "blue", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Prior Density") +
  theme_classic()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

ggplot(draws_df) +
  geom_density(aes(thetaM), fill = "blue", alpha = 0.3) +
  geom_density(aes(thetaM_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 1.386) +
  xlab("Mean Rate") +
  ylab("Posterior Density") +
  theme_classic()

ggplot(draws_df) +
  geom_density(aes(thetaSD), fill = "blue", alpha = 0.3) +
  geom_density(aes(thetaSD_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 0.65) +
  xlab("Variance of Rate") +
  ylab("Posterior Density") +
  theme_classic()

ggplot(draws_df) +
  geom_density(aes(theta_posterior), fill = "blue", alpha = 0.3) +
  geom_density(aes(theta_prior), fill = "red", alpha = 0.3) +
  xlab("Overall Rate") +
  ylab("Posterior Density") +
  theme_classic()

ggplot(draws_df) +
  geom_histogram(aes(prior_preds), color = "darkblue", fill = "lightblue", alpha = 0.3) +
  geom_histogram(aes(posterior_preds), color = "darkblue", fill = "blue", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Predictive Density") +
  theme_classic()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

ggplot(draws_df) +
  geom_density(aes(inv_logit_scaled(`theta[1]`)), fill = "blue", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`theta[15]`)), fill = "green", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`theta[21]`)), fill = "lightblue", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`theta[31]`)), fill = "darkblue", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`theta[41]`)), fill = "yellow", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`theta[51]`)), fill = "darkgreen", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`theta[61]`)), fill = "lightgreen", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(thetaM_prior)), fill = "pink", alpha = 0.3) +
  geom_density(aes(theta_prior), fill = "purple", alpha = 0.3) +
  xlab("Mean Rate") +
  ylab("Posterior Density") +
  theme_classic()

draws_df <- draws_df %>% mutate(
  preds1 = rbinom(4000,120, inv_logit_scaled(`theta[1]`)),
  preds11 = rbinom(4000,120, inv_logit_scaled(`theta[11]`)),
  preds21 = rbinom(4000,120, inv_logit_scaled(`theta[21]`)),
  preds31 = rbinom(4000,120, inv_logit_scaled(`theta[31]`)),
  preds41 = rbinom(4000,120, inv_logit_scaled(`theta[41]`)),
  preds51 = rbinom(4000,120, inv_logit_scaled(`theta[51]`)),
  preds61 = rbinom(4000,120, inv_logit_scaled(`theta[61]`)),
  preds71 = rbinom(4000,120, inv_logit_scaled(`theta[71]`)),
  preds81 = rbinom(4000,120, inv_logit_scaled(`theta[81]`)),
  preds91 = rbinom(4000,120, inv_logit_scaled(`theta[91]`)),
)

d2 <- d %>% group_by(agent) %>% dplyr::summarise(right = sum(randomChoice))

ggplot(draws_df) +
  geom_density(aes(posterior_preds), color = "skyblue1", alpha = 0.3) +
  geom_density(data = d2, aes(right),  color = "darkblue",alpha = 0.8) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Posterior Density") +
  theme_classic()

p1 <- ggplot(draws_df) +
  geom_density(aes(preds1), color = "skyblue1", alpha = 0.3) +
  geom_point(x = subset(d2, agent == 1)$right, y = 0, shape = 23, color = "darkblue", fill = "darkblue") +
  theme_classic()

p2 <- ggplot(draws_df) +
  geom_density(aes(preds11), color = "skyblue1", alpha = 0.3) +
  geom_point(x = subset(d2, agent == 11)$right, y = 0, shape = 23, color = "darkblue", fill = "darkblue") +
  theme_classic()
  
p3 <- ggplot(draws_df) +
  geom_density(aes(preds21), color = "skyblue1", alpha = 0.3) +
  geom_point(x = subset(d2, agent == 21)$right, y = 0, shape = 23, color = "darkblue", fill = "darkblue") +
  theme_classic()

library(patchwork)
p1 + p2 + p3

6.5.3 Multilevel memory

[MISSING: DAGS] [MISSING: EXPLAIN NEW STAN CODE] [MISSING: POP VS IND LEVEL PREDICTIONS]

Prep the data

## Create the data 
d1 <- d %>% 
  subset(select = c(agent, memoryChoice)) %>% 
  mutate(row = row_number()) %>% 
  pivot_wider(names_from = agent, values_from = memoryChoice)

d2 <- d %>% 
  subset(select = c(agent, randomChoice)) %>% 
  mutate(row = row_number()) %>% 
  pivot_wider(names_from = agent, values_from = randomChoice)


data <- list(
  trials = trials,
  agents = agents,
  h = as.matrix(d1[1:120,2:101]),
  other = as.matrix(d2[1:120,2:101])
)

Code, compile and fit the model

stan_model <- "
//
//
functions{
  real normal_lb_rng(real mu, real sigma, real lb) {
    real p = normal_cdf(lb | mu, sigma);  // cdf for bounds
    real u = uniform_rng(p, 1);
    return (sigma * inv_Phi(u)) + mu;  // inverse cdf for value
  }
}

// The input (data) for the model. 
data {
 int<lower = 1> trials;
 int<lower = 1> agents;
 array[trials, agents] int h;
 array[trials, agents] int other;
}

// The parameters accepted by the model. 
parameters {
  real biasM;
  real<lower = 0> biasSD;
  real betaM;
  real<lower = 0> betaSD;
  array[agents] real bias;
  array[agents] real beta;
}

transformed parameters {
  array[trials, agents] real memory;
  
  for (agent in 1:agents){
    for (trial in 1:trials){
      if (trial == 1) {
        memory[trial, agent] = 0.5;
      } 
      if (trial < trials){
        memory[trial + 1, agent] = memory[trial, agent] + ((other[trial, agent] - memory[trial, agent]) / trial);
        if (memory[trial + 1, agent] == 0){memory[trial + 1, agent] = 0.01;}
        if (memory[trial + 1, agent] == 1){memory[trial + 1, agent] = 0.99;}
      }
    }
  }
 }


// The model to be estimated. 
model {
  target += normal_lpdf(biasM | 0, 1);
  target += normal_lpdf(biasSD | 0, .3)  -
    normal_lccdf(0 | 0, .3);
  target += normal_lpdf(betaM | 0, .3);
  target += normal_lpdf(betaSD | 0, .3)  -
    normal_lccdf(0 | 0, .3);

  target += normal_lpdf(bias | biasM, biasSD); 
  target += normal_lpdf(beta | betaM, betaSD); 
 
  for (agent in 1:agents)
    for (trial in 1:trials){
      target += bernoulli_logit_lpmf(h[trial,agent] | 
            bias[agent] +  logit(memory[trial, agent]) * (beta[agent]));
    }
}

generated quantities{
   real biasM_prior;
   real<lower=0> biasSD_prior;
   real betaM_prior;
   real<lower=0> betaSD_prior;
   
   real bias_prior;
   real beta_prior;
   
   int<lower=0, upper = trials> prior_preds0;
   int<lower=0, upper = trials> prior_preds1;
   int<lower=0, upper = trials> prior_preds2;
   int<lower=0, upper = trials> posterior_preds0;
   int<lower=0, upper = trials> posterior_preds1;
   int<lower=0, upper = trials> posterior_preds2;
   array[agents] int<lower=0, upper = trials> posterior_predsID0;
   array[agents] int<lower=0, upper = trials> posterior_predsID1;
   array[agents] int<lower=0, upper = trials> posterior_predsID2;
   
   biasM_prior = normal_rng(0,1);
   biasSD_prior = normal_lb_rng(0,0.3,0);
   betaM_prior = normal_rng(0,1);
   betaSD_prior = normal_lb_rng(0,0.3,0);
   
   bias_prior = normal_rng(biasM_prior, biasSD_prior);
   beta_prior = normal_rng(betaM_prior, betaSD_prior);
   
   prior_preds0 = binomial_rng(trials, inv_logit(bias_prior + 0 * beta_prior));
   prior_preds1 = binomial_rng(trials, inv_logit(bias_prior + 1 * beta_prior));
   prior_preds2 = binomial_rng(trials, inv_logit(bias_prior + 2 * beta_prior));
   posterior_preds0 = binomial_rng(trials, inv_logit(biasM + 0 * betaM));
   posterior_preds1 = binomial_rng(trials, inv_logit(biasM + 1 * betaM));
   posterior_preds2 = binomial_rng(trials, inv_logit(biasM + 2 * betaM));
    

  for (agent in 1:agents){
    posterior_predsID0[agent] = binomial_rng(trials, inv_logit(bias[agent] +  0 * beta[agent]));
      posterior_predsID1[agent] = binomial_rng(trials, inv_logit(bias[agent] +  1 * beta[agent]));
      posterior_predsID2[agent] = binomial_rng(trials, inv_logit(bias[agent] +  2 * beta[agent]));
    }
   
}

"


write_stan_file(
  stan_model,
  dir = "stan/",
  basename = "W5_MultilevelMemory.stan")

file <- file.path("stan/W5_MultilevelMemory.stan")
mod <- cmdstan_model(file, 
                     cpp_options = list(stan_threads = TRUE),
                     stanc_options = list("O1"))

# The following command calls Stan with specific options.
samples <- mod$sample(
  data = data,
  seed = 123,
  chains = 2,
  parallel_chains = 2,
  threads_per_chain = 2,
  iter_warmup = 2000,
  iter_sampling = 2000,
  refresh = 500,
  max_treedepth = 20,
  adapt_delta = 0.99,
)

samples$save_object(file = "simmodels/W5_MultilevelMemory_centered.RDS")

6.5.4 Assessing multilevel memory

samples <- readRDS("simmodels/W5_MultilevelMemory_centered.RDS")

samples$cmdstan_diagnose()
## File /var/folders/lt/zspkqnxd5yg92kybm5f433_cfjr0d6/T/RtmpTP5vj3/W5_MultilevelMemory-202303101235-1-8e8f81.csv not found
## File /var/folders/lt/zspkqnxd5yg92kybm5f433_cfjr0d6/T/RtmpTP5vj3/W5_MultilevelMemory-202303101235-2-8e8f81.csv not found
## No valid input files, exiting.
samples$summary(c("biasM", "betaM", "biasSD", "betaSD"))
## # A tibble: 4 × 10
##   variable  mean median     sd    mad    q5   q95  rhat ess_bulk ess_tail
##   <chr>    <dbl>  <dbl>  <dbl>  <dbl> <dbl> <dbl> <dbl>    <dbl>    <dbl>
## 1 biasM    0.539  0.537 0.0872 0.0859 0.400 0.686  1.00     324.     718.
## 2 betaM    1.02   1.02  0.0700 0.0694 0.906 1.14   1.00     460.    1066.
## 3 biasSD   0.283  0.282 0.0672 0.0689 0.176 0.394  1.01     269.     277.
## 4 betaSD   0.410  0.407 0.0493 0.0499 0.332 0.494  1.00    1438.    2248.
draws_df <- as_draws_df(samples$draws()) 

p1 <- ggplot(draws_df, aes(.iteration, biasM, group = .chain, color = .chain)) +
  geom_line() +
  theme_classic()

p2 <- ggplot(draws_df, aes(.iteration, biasSD, group = .chain, color = .chain)) +
  geom_line() +
  theme_classic()

p3 <- ggplot(draws_df, aes(.iteration, betaM, group = .chain, color = .chain)) +
  geom_line() +
  theme_classic()

p4 <- ggplot(draws_df, aes(.iteration, betaSD, group = .chain, color = .chain)) +
  geom_line() +
  theme_classic()

p1 + p2 + p3 + p4

6.5.4.1 Predictive prior checks

##
ggplot(draws_df) +
  geom_histogram(aes(`prior_preds0`), color = "darkblue", fill = "blue", alpha = 0.3) +
  geom_histogram(aes(`prior_preds1`), color = "darkblue", fill = "green", alpha = 0.3) +
  geom_histogram(aes(`prior_preds2`), color = "darkblue", fill = "red", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Posterior Density") +
  theme_classic()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

6.5.4.2 Prior posterior update checks

biasM <- 0 biasSD <- 0.1 betaM <- 1.5 betaSD <- 0.3

##
p1 <- ggplot(draws_df) +
  geom_density(aes(biasM), fill = "blue", alpha = 0.3) +
  geom_density(aes(biasM_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 0) +
  xlab("Mean bias") +
  ylab("Posterior Density") +
  theme_classic()

p2 <- ggplot(draws_df) +
  geom_density(aes(biasSD), fill = "blue", alpha = 0.3) +
  geom_density(aes(biasSD_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 0.1) +
  xlab("Variance of bias") +
  ylab("Posterior Density") +
  theme_classic()

p3 <- ggplot(draws_df) +
  geom_density(aes(betaM), fill = "blue", alpha = 0.3) +
  geom_density(aes(betaM_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 1.5) +
  xlab("Mean Beta") +
  ylab("Posterior Density") +
  theme_classic()

p4 <- ggplot(draws_df) +
  geom_density(aes(betaSD), fill = "blue", alpha = 0.3) +
  geom_density(aes(betaSD_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 0.3) +
  xlab("Variance of beta") +
  ylab("Posterior Density") +
  theme_classic()

p1 + p2 + p3 + p4 

6.5.4.3 Posterior predictive checks

p1 <- ggplot(draws_df) +
  geom_histogram(aes(`prior_preds0`), color = "darkblue", fill = "lightblue", alpha = 0.3) +
  geom_histogram(aes(`posterior_preds0`), color = "darkblue", fill = "blue", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Posterior Density") +
  theme_classic()

p2 <- ggplot(draws_df) +
  geom_histogram(aes(`prior_preds1`), color = "darkblue", fill = "lightblue", alpha = 0.3) +
  geom_histogram(aes(`posterior_preds1`), color = "darkblue", fill = "blue", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Posterior Density") +
  theme_classic()

p3 <- ggplot(draws_df) +
  geom_histogram(aes(`prior_preds2`), color = "darkblue", fill = "lightblue", alpha = 0.3) +
  geom_histogram(aes(`posterior_preds2`), color = "darkblue", fill = "blue", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Posterior Density") +
  theme_classic()

p1 + p2 + p3
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

p1 <- ggplot(draws_df, aes(biasM, biasSD, group = .chain, color = .chain)) +
  geom_point(alpha = 0.1) +
  theme_classic()
p2 <- ggplot(draws_df, aes(betaM, betaSD, group = .chain, color = .chain)) +
  geom_point(alpha = 0.1) +
  theme_classic()
p3 <- ggplot(draws_df, aes(biasM, betaM, group = .chain, color = .chain)) +
  geom_point(alpha = 0.1) +
  theme_classic()
p4 <- ggplot(draws_df, aes(biasSD, betaSD, group = .chain, color = .chain)) +
  geom_point(alpha = 0.1) +
  theme_classic()

p1 + p2 + p3 + p4

6.5.5 Multilevel memory with non centered parameterization

Prep the data

## Create the data 
d1 <- d %>% 
  subset(select = c(agent, memoryChoice)) %>% 
  mutate(row = row_number()) %>% 
  pivot_wider(names_from = agent, values_from = memoryChoice)

d2 <- d %>% 
  subset(select = c(agent, randomChoice)) %>% 
  mutate(row = row_number()) %>% 
  pivot_wider(names_from = agent, values_from = randomChoice)


data <- list(
  trials = trials,
  agents = agents,
  h = as.matrix(d1[1:120,2:101]),
  other = as.matrix(d2[1:120,2:101])
)

Code, compile and and fit the model

## NON-CENTERED PARAMETRIZATION

stan_model_nc <- "

//
// This STAN model is a multilevel memory agent
//
functions{
  real normal_lb_rng(real mu, real sigma, real lb) {
    real p = normal_cdf(lb | mu, sigma);  // cdf for bounds
    real u = uniform_rng(p, 1);
    return (sigma * inv_Phi(u)) + mu;  // inverse cdf for value
  }
}

// The input (data) for the model. 
data {
 int<lower = 1> trials;
 int<lower = 1> agents;
 array[trials, agents] int h;
 array[trials, agents] int other;
}

// The parameters accepted by the model. 
parameters {
  real biasM;
  real<lower = 0> biasSD;
  real betaM;
  real<lower = 0> betaSD;
  vector[agents] biasID_z;
  vector[agents] betaID_z;
}

transformed parameters {
  array[trials, agents] real memory;
  vector[agents] biasID;
  vector[agents] betaID;
  
  for (agent in 1:agents){
    for (trial in 1:trials){
      if (trial == 1) {
        memory[trial, agent] = 0.5;
      } 
      if (trial < trials){
        memory[trial + 1, agent] = memory[trial, agent] + ((other[trial, agent] - memory[trial, agent]) / trial);
        if (memory[trial + 1, agent] == 0){memory[trial + 1, agent] = 0.01;}
        if (memory[trial + 1, agent] == 1){memory[trial + 1, agent] = 0.99;}
      }
    }
  }
  biasID = biasID_z * biasSD;
  betaID = betaID_z * betaSD;
 }

// The model to be estimated. 
model {
  target += normal_lpdf(biasM | 0, 1);
  target += normal_lpdf(biasSD | 0, .3)  -
    normal_lccdf(0 | 0, .3);
  target += normal_lpdf(betaM | 0, .3);
  target += normal_lpdf(betaSD | 0, .3)  -
    normal_lccdf(0 | 0, .3);

  target += std_normal_lpdf(to_vector(biasID_z)); // target += normal_lpdf(to_vector(biasID_z) | 0, 1);
  target += std_normal_lpdf(to_vector(betaID_z)); // target += normal_lpdf(to_vector(betaID_z) | 0, 1);
 
  for (agent in 1:agents){
    for (trial in 1:trials){
      target += bernoulli_logit_lpmf(h[trial,agent] | 
            biasM + biasID[agent] +  logit(memory[trial, agent]) * (betaM + betaID[agent]));
    }
  }
  
  
}

generated quantities{
   real biasM_prior;
   real<lower=0> biasSD_prior;
   real betaM_prior;
   real<lower=0> betaSD_prior;
   
   real bias_prior;
   real beta_prior;
   
   array[agents] int<lower=0, upper = trials> prior_preds0;
   array[agents] int<lower=0, upper = trials> prior_preds1;
   array[agents] int<lower=0, upper = trials> prior_preds2;
   array[agents] int<lower=0, upper = trials> posterior_preds0;
   array[agents] int<lower=0, upper = trials> posterior_preds1;
   array[agents] int<lower=0, upper = trials> posterior_preds2;
   
   biasM_prior = normal_rng(0,1);
   biasSD_prior = normal_lb_rng(0,0.3,0);
   betaM_prior = normal_rng(0,1);
   betaSD_prior = normal_lb_rng(0,0.3,0);
   
   bias_prior = normal_rng(biasM_prior, biasSD_prior);
   beta_prior = normal_rng(betaM_prior, betaSD_prior);
   


for (agent in 1:agents){
    prior_preds0[agent] = binomial_rng(trials, inv_logit(bias_prior + 0 * beta_prior));
    prior_preds1[agent] = binomial_rng(trials, inv_logit(bias_prior + 1 * beta_prior));
    prior_preds2[agent] = binomial_rng(trials, inv_logit(bias_prior + 2 * beta_prior));
      posterior_preds0[agent] = binomial_rng(trials, inv_logit(biasM + biasID[agent] +  0 * (betaM + betaID[agent])));
      posterior_preds1[agent] = binomial_rng(trials, inv_logit(biasM + biasID[agent] +  1 * (betaM + betaID[agent])));
      posterior_preds2[agent] = binomial_rng(trials, inv_logit(biasM + biasID[agent] +  2 * (betaM + betaID[agent])));
    }
}

"

write_stan_file(
  stan_model_nc,
  dir = "stan/",
  basename = "W5_MultilevelMemory_nc.stan")

file <- file.path("stan/W5_MultilevelMemory_nc.stan")
mod_nc <- cmdstan_model(file, 
                     cpp_options = list(stan_threads = TRUE),
                     stanc_options = list("O1"))

# The following command calls Stan with specific options.
samples <- mod_nc$sample(
  data = data,
  seed = 123,
  chains = 2,
  parallel_chains = 2,
  threads_per_chain = 2,
  iter_warmup = 2000,
  iter_sampling = 2000,
  refresh = 500,
  max_treedepth = 20,
  adapt_delta = 0.99,
)

samples$save_object(file = "simmodels/W5_MultilevelMemory_noncentered.RDS")

6.5.6 Assessing multilevel memory

samples <- readRDS("simmodels/W5_MultilevelMemory_noncentered.RDS")

samples$cmdstan_diagnose()
## File /var/folders/lt/zspkqnxd5yg92kybm5f433_cfjr0d6/T/RtmpTP5vj3/W5_MultilevelMemory_nc-202303101250-1-612dbb.csv not found
## File /var/folders/lt/zspkqnxd5yg92kybm5f433_cfjr0d6/T/RtmpTP5vj3/W5_MultilevelMemory_nc-202303101250-2-612dbb.csv not found
## No valid input files, exiting.
samples$summary(c("biasM", "betaM", "biasSD", "betaSD"))
## # A tibble: 4 × 10
##   variable  mean median     sd    mad    q5   q95  rhat ess_bulk ess_tail
##   <chr>    <dbl>  <dbl>  <dbl>  <dbl> <dbl> <dbl> <dbl>    <dbl>    <dbl>
## 1 biasM    0.538  0.537 0.0870 0.0875 0.397 0.683  1.00    1315.    2025.
## 2 betaM    1.02   1.02  0.0726 0.0732 0.901 1.14   1.00    1187.    2168.
## 3 biasSD   0.281  0.281 0.0702 0.0698 0.168 0.401  1.00     630.     956.
## 4 betaSD   0.411  0.409 0.0497 0.0493 0.333 0.499  1.00    1394.    2137.
draws_df <- as_draws_df(samples$draws()) 

p1 <- ggplot(draws_df, aes(.iteration, biasM, group = .chain, color = .chain)) +
  geom_line() +
  theme_classic()

p2 <- ggplot(draws_df, aes(.iteration, biasSD, group = .chain, color = .chain)) +
  geom_line() +
  theme_classic()

p3 <- ggplot(draws_df, aes(.iteration, betaM, group = .chain, color = .chain)) +
  geom_line() +
  theme_classic()

p4 <- ggplot(draws_df, aes(.iteration, betaSD, group = .chain, color = .chain)) +
  geom_line() +
  theme_classic()

p1 + p2 + p3 + p4

6.5.6.1 Predictive prior checks

##
ggplot(draws_df) +
  geom_histogram(aes(`prior_preds0[1]`), color = "darkblue", fill = "blue", alpha = 0.3) +
  geom_histogram(aes(`prior_preds1[1]`), color = "darkblue", fill = "green", alpha = 0.3) +
  geom_histogram(aes(`prior_preds2[1]`), color = "darkblue", fill = "red", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Posterior Density") +
  theme_classic()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

6.5.6.2 Prior posterior update checks

biasM <- 0 biasSD <- 0.1 betaM <- 1.5 betaSD <- 0.3

##
p1 <- ggplot(draws_df) +
  geom_density(aes(logit_scaled(biasM)), fill = "blue", alpha = 0.3) +
  geom_density(aes(biasM_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 0) +
  xlab("Mean bias") +
  ylab("Posterior Density") +
  theme_classic()

p2 <- ggplot(draws_df) +
  geom_density(aes(biasSD), fill = "blue", alpha = 0.3) +
  geom_density(aes(biasSD_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 0.1) +
  xlab("Variance of bias") +
  ylab("Posterior Density") +
  theme_classic()

p3 <- ggplot(draws_df) +
  geom_density(aes(betaM), fill = "blue", alpha = 0.3) +
  geom_density(aes(betaM_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 1.5) +
  xlab("Mean Beta") +
  ylab("Posterior Density") +
  theme_classic()

p4 <- ggplot(draws_df) +
  geom_density(aes(betaSD), fill = "blue", alpha = 0.3) +
  geom_density(aes(betaSD_prior), fill = "red", alpha = 0.3) +
  geom_vline(xintercept = 0.3) +
  xlab("Variance of beta") +
  ylab("Posterior Density") +
  theme_classic()

p1 + p2 + p3 + p4 

6.5.6.3 Posterior predictive checks

p1 <- ggplot(draws_df) +
  geom_histogram(aes(`prior_preds0[1]`), color = "darkblue", fill = "lightblue", alpha = 0.3) +
  geom_histogram(aes(`posterior_preds0[1]`), color = "darkblue", fill = "blue", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Posterior Density") +
  theme_classic()

p2 <- ggplot(draws_df) +
  geom_histogram(aes(`prior_preds1[1]`), color = "darkblue", fill = "lightblue", alpha = 0.3) +
  geom_histogram(aes(`posterior_preds1[1]`), color = "darkblue", fill = "blue", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Posterior Density") +
  theme_classic()

p3 <- ggplot(draws_df) +
  geom_histogram(aes(`prior_preds2[1]`), color = "darkblue", fill = "lightblue", alpha = 0.3) +
  geom_histogram(aes(`posterior_preds2[1]`), color = "darkblue", fill = "blue", alpha = 0.3) +
  xlab("Predicted right hands out of 120 trials") +
  ylab("Posterior Density") +
  theme_classic()

p1 + p2 + p3
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

p1 <- ggplot(draws_df, aes(biasM, biasSD, group = .chain, color = .chain)) +
  geom_point(alpha = 0.1) +
  theme_classic()
p2 <- ggplot(draws_df, aes(betaM, betaSD, group = .chain, color = .chain)) +
  geom_point(alpha = 0.1) +
  theme_classic()
p3 <- ggplot(draws_df, aes(biasM, betaM, group = .chain, color = .chain)) +
  geom_point(alpha = 0.1) +
  theme_classic()
p4 <- ggplot(draws_df, aes(biasSD, betaSD, group = .chain, color = .chain)) +
  geom_point(alpha = 0.1) +
  theme_classic()

p1 + p2 + p3 + p4

ggplot(draws_df) +
  geom_density(aes(inv_logit_scaled(`biasID[1]`)), fill = "blue", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`biasID[15]`)), fill = "green", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`biasID[21]`)), fill = "lightblue", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`biasID[31]`)), fill = "darkblue", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`biasID[41]`)), fill = "yellow", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`biasID[51]`)), fill = "darkgreen", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`biasID[61]`)), fill = "lightgreen", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(biasM_prior)), fill = "pink", alpha = 0.3) +
  geom_density(aes(bias_prior), fill = "purple", alpha = 0.3) +
  xlab("Bias parameter") +
  ylab("Posterior Density") +
  theme_classic()

ggplot(draws_df) +
  geom_density(aes(inv_logit_scaled(`betaID[1]`)), fill = "blue", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`betaID[15]`)), fill = "green", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`betaID[21]`)), fill = "lightblue", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`betaID[31]`)), fill = "darkblue", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`betaID[41]`)), fill = "yellow", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`betaID[51]`)), fill = "darkgreen", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(`betaID[61]`)), fill = "lightgreen", alpha = 0.3) +
  geom_density(aes(inv_logit_scaled(betaM_prior)), fill = "pink", alpha = 0.3) +
  geom_density(aes(beta_prior), fill = "purple", alpha = 0.3) +
  xlab("Beta parameter") +
  ylab("Posterior Density") +
  theme_classic()

6.5.7 Multilevel memory with correlation between parameters

stan_model_nc_cor <- "
//
// This STAN model infers a random bias from a sequences of 1s and 0s (heads and tails)
//
functions{
  real normal_lb_rng(real mu, real sigma, real lb) {
    real p = normal_cdf(lb | mu, sigma);  // cdf for bounds
    real u = uniform_rng(p, 1);
    return (sigma * inv_Phi(u)) + mu;  // inverse cdf for value
  }
}

// The input (data) for the model. 
data {
 int<lower = 1> trials;
 int<lower = 1> agents;
 array[trials, agents] int h;
 array[trials, agents] int other;
}

// The parameters accepted by the model. 
parameters {
  real biasM;
  real betaM;
  vector<lower = 0>[2] tau;
  matrix[2, agents] z_IDs;
  cholesky_factor_corr[2] L_u;
}

transformed parameters {
  array[trials, agents] real memory;
  matrix[agents,2] IDs;
  IDs = (diag_pre_multiply(tau, L_u) * z_IDs)';
  
  for (agent in 1:agents){
    for (trial in 1:trials){
      if (trial == 1) {
        memory[trial, agent] = 0.5;
      } 
      if (trial < trials){
        memory[trial + 1, agent] = memory[trial, agent] + ((other[trial, agent] - memory[trial, agent]) / trial);
        if (memory[trial + 1, agent] == 0){memory[trial + 1, agent] = 0.01;}
        if (memory[trial + 1, agent] == 1){memory[trial + 1, agent] = 0.99;}
      }
    }
  }
}

// The model to be estimated. 
model {
  target += normal_lpdf(biasM | 0, 1);
  target += normal_lpdf(tau[1] | 0, .3)  -
    normal_lccdf(0 | 0, .3);
  target += normal_lpdf(betaM | 0, .3);
  target += normal_lpdf(tau[2] | 0, .3)  -
    normal_lccdf(0 | 0, .3);
  target += lkj_corr_cholesky_lpdf(L_u | 2);

  target += std_normal_lpdf(to_vector(z_IDs));
  for (agent in 1:agents){
    for (trial in 1:trials){
      target += bernoulli_logit_lpmf(h[trial, agent] | biasM + IDs[agent, 1] +  memory[trial, agent] * (betaM + IDs[agent, 2]));
    }
  }
    
}


generated quantities{
   real biasM_prior;
   real<lower=0> biasSD_prior;
   real betaM_prior;
   real<lower=0> betaSD_prior;
   
   real bias_prior;
   real beta_prior;
   
   array[agents] int<lower=0, upper = trials> prior_preds0;
   array[agents] int<lower=0, upper = trials> prior_preds1;
   array[agents] int<lower=0, upper = trials> prior_preds2;
   array[agents] int<lower=0, upper = trials> posterior_preds0;
   array[agents] int<lower=0, upper = trials> posterior_preds1;
   array[agents] int<lower=0, upper = trials> posterior_preds2;
   
   biasM_prior = normal_rng(0,1);
   biasSD_prior = normal_lb_rng(0,0.3,0);
   betaM_prior = normal_rng(0,1);
   betaSD_prior = normal_lb_rng(0,0.3,0);
   
   bias_prior = normal_rng(biasM_prior, biasSD_prior);
   beta_prior = normal_rng(betaM_prior, betaSD_prior);
   
   for (i in 1:agents){
      prior_preds0[i] = binomial_rng(trials, inv_logit(bias_prior + 0 * beta_prior));
      prior_preds1[i] = binomial_rng(trials, inv_logit(bias_prior + 1 * beta_prior));
      prior_preds2[i] = binomial_rng(trials, inv_logit(bias_prior + 2 * beta_prior));
      posterior_preds0[i] = binomial_rng(trials, inv_logit(biasM + IDs[i,1] +  0 * (betaM + IDs[i,2])));
      posterior_preds1[i] = binomial_rng(trials, inv_logit(biasM + IDs[i,1] +  1 * (betaM + IDs[i,2])));
      posterior_preds2[i] = binomial_rng(trials, inv_logit(biasM + IDs[i,1] +  2 * (betaM + IDs[i,2])));
      
  }
  
}
"

write_stan_file(
  stan_model_nc_cor,
  dir = "stan/",
  basename = "W5_MultilevelMemory_nc_cor.stan")

file <- file.path("stan/W5_MultilevelMemory_nc_cor.stan")
mod <- cmdstan_model(file, cpp_options = list(stan_threads = TRUE),
                     stanc_options = list("O1"))

# The following command calls Stan with specific options.
samples <- mod$sample(
  data = data,
  seed = 123,
  chains = 2,
  parallel_chains = 2,
  threads_per_chain = 2,
  iter_warmup = 2000,
  iter_sampling = 2000,
  refresh = 500,
  max_treedepth = 20,
  adapt_delta = 0.99,
)

samples$save_object(file = "simmodels/Memory_noncentered_corr.RDS")

6.5.8 Assessing multilevel memory

[MISSING LOTS OF EVALUATION]

samples <- readRDS("simmodels/W5_MultilevelMemory_noncentered_corr.RDS")

samples$cmdstan_diagnose()
## File /var/folders/lt/zspkqnxd5yg92kybm5f433_cfjr0d6/T/RtmpTP5vj3/W5_MultilevelMemory_nc_cor-202303100657-1-969904.csv not found
## File /var/folders/lt/zspkqnxd5yg92kybm5f433_cfjr0d6/T/RtmpTP5vj3/W5_MultilevelMemory_nc_cor-202303100657-2-969904.csv not found
## No valid input files, exiting.

6.5.9 Multilevel memory no pooling

[MISSING: EXPLANATION OF NO POOLING]

stan_model <- "

// The input (data) for the model. n of trials and h of heads
data {
 int<lower = 1> trials;
 int<lower = 1> agents;
 array[trials, agents] int h;
 array[trials, agents] int other;
}

// The parameters accepted by the model. 
parameters {
  array[trials] real bias;
  array[trials] real beta;
}


transformed parameters {
  array[trials, agents] real memory;
  
  for (agent in 1:agents){
    for (trial in 1:trials){
      if (trial == 1) {
        memory[trial, agent] = 0.5;
      } 
      if (trial < trials){
        memory[trial + 1, agent] = memory[trial, agent] + ((other[trial, agent] - memory[trial, agent]) / trial);
        if (memory[trial + 1, agent] == 0){memory[trial + 1, agent] = 0.01;}
        if (memory[trial + 1, agent] == 1){memory[trial + 1, agent] = 0.99;}
      }
    }
  }
}

// The model to be estimated. 
model {
  target += normal_lpdf(bias | 0, 1);
  target += normal_lpdf(beta | 0, 1);

  for (agent in 1:agents){
    for (trial in 1:trials){
      target += bernoulli_logit_lpmf(h[trial, agent] | bias[agent] +  memory[trial, agent] * (beta[agent]));
    }
  }
    
}


generated quantities{
   real bias_prior;
   real beta_prior;
   
   int<lower=0, upper = trials> prior_preds0;
   int<lower=0, upper = trials> prior_preds1;
   int<lower=0, upper = trials> prior_preds2;
   array[agents] int<lower=0, upper = trials> posterior_preds0;
   array[agents] int<lower=0, upper = trials> posterior_preds1;
   array[agents] int<lower=0, upper = trials> posterior_preds2;
   
   bias_prior = normal_rng(0,1);
   beta_prior = normal_rng(0,1);
   
   prior_preds0 = binomial_rng(trials, inv_logit(bias_prior + 0 * beta_prior));
   prior_preds1 = binomial_rng(trials, inv_logit(bias_prior + 1 * beta_prior));
   prior_preds2 = binomial_rng(trials, inv_logit(bias_prior + 2 * beta_prior));
   
   for (i in 1:agents){
      posterior_preds0[i] = binomial_rng(trials, inv_logit(bias[i] +  0 * (beta[i])));
      posterior_preds1[i] = binomial_rng(trials, inv_logit(bias[i] +  1 * (beta[i])));
      posterior_preds2[i] = binomial_rng(trials, inv_logit(bias[i] +  2 * (beta[i])));
  }
  
}
"

write_stan_file(
  stan_model,
  dir = "stan/",
  basename = "W5_MultilevelMemory_nopooling.stan")

file <- file.path("stan/W5_MultilevelMemory_nopooling.stan")
mod <- cmdstan_model(file, cpp_options = list(stan_threads = TRUE),
                     stanc_options = list("O1"))

# The following command calls Stan with specific options.
samples <- mod$sample(
  data = data,
  seed = 123,
  chains = 2,
  parallel_chains = 2,
  threads_per_chain = 2,
  iter_warmup = 2000,
  iter_sampling = 2000,
  refresh = 500,
  max_treedepth = 20,
  adapt_delta = 0.99,
)

samples$save_object(file = "simmodels/W5_MultilevelMemory_nopooling.RDS")

[MISSING: Evaluation of NO POOLING]

6.6 Multilevel full pooling

[MISSING: EXPLANATION OF FULL POOLING]

stan_model <- "

// The input (data) for the model. n of trials and h of heads
data {
 int<lower = 1> trials;
 int<lower = 1> agents;
 array[trials, agents] int h;
 array[trials, agents] int other;
}

// The parameters accepted by the model. 
parameters {
  real bias;
  real beta;
}


transformed parameters {
  array[trials, agents] real memory;
  
  for (agent in 1:agents){
    for (trial in 1:trials){
      if (trial == 1) {
        memory[trial, agent] = 0.5;
      } 
      if (trial < trials){
        memory[trial + 1, agent] = memory[trial, agent] + ((other[trial, agent] - memory[trial, agent]) / trial);
        if (memory[trial + 1, agent] == 0){memory[trial + 1, agent] = 0.01;}
        if (memory[trial + 1, agent] == 1){memory[trial + 1, agent] = 0.99;}
      }
    }
  }
}

// The model to be estimated. 
model {
  target += normal_lpdf(bias | 0, 1);
  target += normal_lpdf(beta | 0, 1);

  for (agent in 1:agents){
    for (trial in 1:trials){
      target += bernoulli_logit_lpmf(h[trial, agent] | bias +  memory[trial, agent] * beta);
    }
  }
    
}


generated quantities{
   real bias_prior;
   real beta_prior;
   
   int<lower=0, upper = trials> prior_preds0;
   int<lower=0, upper = trials> prior_preds1;
   int<lower=0, upper = trials> prior_preds2;
   int<lower=0, upper = trials> posterior_preds0;
   int<lower=0, upper = trials> posterior_preds1;
   int<lower=0, upper = trials> posterior_preds2;
   
   bias_prior = normal_rng(0,1);
   beta_prior = normal_rng(0,1);
   
   prior_preds0 = binomial_rng(trials, inv_logit(bias_prior + 0 * beta_prior));
   prior_preds1 = binomial_rng(trials, inv_logit(bias_prior + 1 * beta_prior));
   prior_preds2 = binomial_rng(trials, inv_logit(bias_prior + 2 * beta_prior));
   
   posterior_preds0 = binomial_rng(trials, inv_logit(bias +  0 * (beta)));
   posterior_preds1 = binomial_rng(trials, inv_logit(bias +  1 * (beta)));
   posterior_preds2 = binomial_rng(trials, inv_logit(bias +  2 * (beta)));
  
}
"

write_stan_file(
  stan_model,
  dir = "stan/",
  basename = "W5_MultilevelMemory_fullpooling.stan")

file <- file.path("stan/W5_MultilevelMemory_fullpooling.stan")
mod <- cmdstan_model(file, cpp_options = list(stan_threads = TRUE),
                     stanc_options = list("O1"))

# The following command calls Stan with specific options.
samples <- mod$sample(
  data = data,
  seed = 123,
  chains = 2,
  parallel_chains = 2,
  threads_per_chain = 2,
  iter_warmup = 2000,
  iter_sampling = 2000,
  refresh = 500,
  max_treedepth = 20,
  adapt_delta = 0.99,
)

samples$save_object(file = "simmodels/W5_MultilevelMemory_fullpooling.RDS")

[MISSING: Evaluation of FULL POOLING]

[MISSING: PARAMETER RECOVERY IN A MULTILEVEL FRAMEWORK (IND VS POP)]