Here is R code you can use to learn about the basic pairwise models for binary outcomes, with simple simulated data. There are combinations of {common effect, random effects} x {contrast-based, arm-based} with examples of heuristic t likelihood and alternative specification of arm likelihoods. This all uses JAGS via rjags.

In keeping with the book, we want this code to be as human-readable as possible, so only base R is used, it may not be the most efficient R, and it certainly is not the most fashionable R.

# rjags test for CE/RE contrast- and arm-based models

library(rjags)
library(meta)


# ----------------- binary outcome data, CE ---------------
set.seed(9876)

risk_ctl <- 0.3
odds_ctl <- risk_ctl/(1-risk_ctl)
lor_ctl <- log(odds_ctl)
true_or <- 0.9
true_lor <- log(true_or)
odds_int <- (risk_ctl/(1-risk_ctl)) * true_or
risk_int <- odds_int / (1+ odds_int)
print(paste0("Control risk: ", risk_ctl))
print(paste0("Control odds: ", odds_ctl))
print(paste0("Control log odds: ", lor_ctl))
print(paste0("Intervention risk: ", risk_int))
print(paste0("True log odds ratio: ", true_lor))
print(paste0("True odds ratio: ", exp(true_lor)))
arm_n <- 80
m <- 25

n1 <- n2 <- rep(arm_n, m)
sim_binary_ce <- data.frame(n1=n1, n2=n2)

sim_binary_ce$d1 <- rbinom(m, size=arm_n, prob=risk_ctl)
sim_binary_ce$d2 <- rbinom(m, size=arm_n, prob=risk_int)
sim_binary_ce$h1 <- sim_binary_ce$n1 - sim_binary_ce$d1
sim_binary_ce$h2 <- sim_binary_ce$n2 - sim_binary_ce$d2
sim_binary_ce$study <- 1:m
sim_binary_ce$study_or <- (sim_binary_ce$d2/sim_binary_ce$h2) / 
                            (sim_binary_ce$d1/sim_binary_ce$h1)
sim_binary_ce$logor = log(sim_binary_ce$study_or)
sim_binary_ce$se2 = (1/sim_binary_ce$d2) + 
                    (1/sim_binary_ce$h2) + 
                    (1/sim_binary_ce$d1) + 
                    (1/sim_binary_ce$h1)




# ------------ frequentist CE MA ---------------

ce_freq <- metabin(d2, n2, d1, n1, 
	               data=sim_binary_ce, 
	               sm="OR",
	               common=TRUE, random=FALSE,
	               method="Inverse")
print(summary(ce_freq))




# --------------- CE, binary, contrast-based ----------------

jagsdata <- list(m=m, 
                 logor=sim_binary_ce$logor,
                 se2 = sim_binary_ce$se2)

jagscode <- '
model{
	theta ~ dnorm(0, 0.111)
	for(j in 1:m){
		prec_logor[j] <- 1 / se2[j]
		logor[j] ~ dnorm(theta, prec_logor[j])
	}
	oddsratio <- exp(theta)
}
'
write(jagscode, "JAGS-simulation-CE.txt")

jagsinits <- list(list(theta=0.5),
                  list(theta=(-0.5)))
                
jagsmod <- jags.model("JAGS-simulation-CE.txt",
                      data=jagsdata,
                      inits=jagsinits,
                      n.chains=2)

update(jagsmod, n.iter=1000)
jagsdraws <- coda.samples(jagsmod,
                        variable.names=c("oddsratio"),
                        n.iter=10000)

summary(jagsdraws)

plot(jagsdraws)






# ------------------ CE/FE, binary, arm-based --------------------

sim_binary_ce_arm <- data.frame(d=c(sim_binary_ce$d1, sim_binary_ce$d2),
	                            n=c(sim_binary_ce$n1, sim_binary_ce$n2),
	                            active=rep(c(0,1), each=m),
	                            study=rep((1:m),2))
jagsdata <- list(m = m,
	             K = 2*m,
	             arm_d = sim_binary_ce_arm$d,
	             arm_n = sim_binary_ce_arm$n,
	             active = sim_binary_ce_arm$active,
	             study = sim_binary_ce_arm$study)


jagscode <- '
model{
  theta ~ dnorm(0, 0.111)
  for(j in 1:m){
    mu[j] ~ dnorm(0, 0.000001)
  }
  for(k in 1:K){
    logit(prob[k]) <- mu[study[k]] + theta*active[k]
    arm_d[k] ~ dbin(prob[k], arm_n[k])
  }
  oddsratio <- exp(theta)
}
'
write(jagscode, "JAGS-simulation-CE-arm.txt")

jagsinits <- list(list(theta=0.5),
                  list(theta=(-0.5)))
                
jagsmod <- jags.model("JAGS-simulation-CE-arm.txt",
                      data=jagsdata,
                      inits=jagsinits,
                      n.chains=2)

update(jagsmod, n.iter=1000)
jagsdraws <- coda.samples(jagsmod,
                        variable.names=c("oddsratio"),
                        n.iter=10000)

summary(jagsdraws)

plot(jagsdraws)




# ------------------ CE/FE, arm-based, equivalent alternative code --------------------

jagsdata <- list(m = m,
	             d1 = sim_binary_ce$d1,
	             n1 = sim_binary_ce$n1,
	             d2 = sim_binary_ce$d2,
	             n2 = sim_binary_ce$n2,
	             study = sim_binary_ce$study)

jagscode <- '
model{
  theta ~ dnorm(0, 0.111)
  for(j in 1:m){
    mu[j] ~ dnorm(0, 0.000001)
  }
  for(j in 1:m){
    logit(prob1[j]) <- mu[study[j]]
    logit(prob2[j]) <- mu[study[j]] + theta
    d1[j] ~ dbin(prob1[j], n1[j])
    d2[j] ~ dbin(prob2[j], n2[j])
  }
  oddsratio <- exp(theta)
}
'
write(jagscode, "JAGS-simulation-CE-arm-alt.txt")

jagsinits <- list(list(theta=0.5),
                  list(theta=(-0.5)))
                
jagsmod <- jags.model("JAGS-simulation-CE-arm-alt.txt",
                      data=jagsdata,
                      inits=jagsinits,
                      n.chains=2)

update(jagsmod, n.iter=1000)
jagsdraws <- coda.samples(jagsmod,
                        variable.names=c("oddsratio"),
                        n.iter=10000)

summary(jagsdraws)

plot(jagsdraws)





# ----------------- binary outcome data, RE ---------------
set.seed(4888)

risk_ctl <- 0.3
odds_ctl <- risk_ctl/(1-risk_ctl)
logodds_ctl <- log(odds_ctl)
true_or <- 0.9
true_lor <- log(true_or)
odds_int <- (risk_ctl/(1-risk_ctl)) * true_or
risk_int <- odds_int / (1+ odds_int)
print(paste0("Control risk: ", risk_ctl))
print(paste0("Control odds: ", odds_ctl))
print(paste0("Control log odds: ", logodds_ctl))
print(paste0("True log odds ratio: ", true_lor))
print(paste0("True odds ratio: ", exp(true_lor)))
true_tau <- 0.15
print(paste0("True tau: ", true_tau))
arm_n <- 80
m <- 25
theta_j <- rnorm(m, true_lor, true_tau)
logodds_int <- logodds_ctl + theta_j
risk_int <- 1 / (1 + exp(-logodds_int))

n1 <- n2 <- rep(arm_n, m)
sim_binary_re <- data.frame(n1=n1, n2=n2, theta_j=theta_j)

sim_binary_re$d1 <- rbinom(m, size=arm_n, prob=risk_ctl)
sim_binary_re$d2 <- rbinom(m, size=arm_n, prob=risk_int)
sim_binary_re$h1 <- sim_binary_re$n1 - sim_binary_re$d1
sim_binary_re$h2 <- sim_binary_re$n2 - sim_binary_re$d2
sim_binary_re$study <- 1:m
sim_binary_re$study_or <- (sim_binary_re$d2/sim_binary_re$h2) / 
                            (sim_binary_re$d1/sim_binary_re$h1)
sim_binary_re$logor = log(sim_binary_re$study_or)
sim_binary_re$se2 = (1/sim_binary_re$d2) + 
                    (1/sim_binary_re$h2) + 
                    (1/sim_binary_re$d1) + 
                    (1/sim_binary_re$h1)



# ------------ frequentist RE MA ---------------

re_freq <- metabin(d2, n2, d1, n1, 
	               data=sim_binary_re, 
	               sm="OR",
	               common=FALSE, random=TRUE,
	               method="Inverse",
	               method.tau="DL")
print(summary(re_freq))




# --------------- RE, binary, contrast-based ----------------

jagsdata <- list(m = m,
	             logor = sim_binary_re$logor,
	             se_logor = sqrt(sim_binary_re$se2))

jagscode <- "
model {
  theta ~ dnorm(0, 0.111)
  tau ~ dgamma(1.2, 1)
  tau_prec <- 1 / (tau*tau)

  for(j in 1:m) {
    u[j] ~ dnorm(0, tau_prec)
    prec_logor[j] <- 1 / (se_logor[j]*se_logor[j])
    logor[j] ~ dnorm(theta+u[j], prec_logor[j])
  }
  oddsratio <- exp(theta)
}
"

write(jagscode, "JAGS-simulation-RE.txt")

jagsinits <- list(list(theta=0.5),
                  list(theta=(-0.5)))
                
jagsmod <- jags.model("JAGS-simulation-RE.txt",
                      data=jagsdata,
                      inits=jagsinits,
                      n.chains=2)

update(jagsmod, n.iter=1000)
jagsdraws <- coda.samples(jagsmod,
                        variable.names=c("oddsratio", "tau"),
                        n.iter=10000)

summary(jagsdraws)

plot(jagsdraws)






# ------------------- RE, binary, contrast-based, heuristic t likelihood ----------------------

jagsdata <- list(m = m,
	             logor = sim_binary_re$logor,
	             se_logor = sqrt(sim_binary_re$se2),
	             n = sim_binary_re$n1 + sim_binary_re$n2)

jagscode <- "
model {
  theta ~ dnorm(0, 0.111)
  tau ~ dgamma(1.2, 1)
  tau_prec <- 1 / (tau*tau)

  for(j in 1:m) {
    u[j] ~ dnorm(0, tau_prec)
    prec_logor[j] <- 1 / (se_logor[j]*se_logor[j])
    logor[j] ~ dt(theta+u[j], 
                  prec_logor[j], 
                  n[j]-2);
  }
  oddsratio <- exp(theta)
}
"
write(jagscode, "JAGS-simulation-RE-exact.txt")

jagsinits <- list(list(theta=0.5),
                  list(theta=(-0.5)))
                
jagsmod <- jags.model("JAGS-simulation-RE-exact.txt",
                      data=jagsdata,
                      inits=jagsinits,
                      n.chains=2)

update(jagsmod, n.iter=1000)
jagsdraws <- coda.samples(jagsmod,
                        variable.names=c("oddsratio", "tau"),
                        n.iter=10000)

summary(jagsdraws)

plot(jagsdraws)






# ------------------ RE/FE, binary, arm-based --------------------

sim_binary_re_arm <- data.frame(d=c(sim_binary_re$d1, sim_binary_re$d2),
	                            n=c(sim_binary_re$n1, sim_binary_re$n2),
	                            active=rep(c(0,1), each=m),
	                            study=rep((1:m),2))
	                            
jagsdata <- list(m = m,
                 K = 2*m,
	             arm_d = sim_binary_re_arm$d,
	             arm_n = sim_binary_re_arm$n,
	             active = sim_binary_re_arm$active,
	             study = sim_binary_re_arm$study)
      
jagscode <- "
model{
  theta ~ dnorm(0, 0.111)
  tau ~ dgamma(1.2, 1)
  tau_prec <- 1 / (tau*tau)

  for(j in 1:m){
    mu[j] ~ dnorm(0, 0.000001) # very diffuse
    u[j] ~ dnorm(0, tau_prec) # heterogeneity
  }

  for(k in 1:K){
    logit(prob[k]) <- mu[study[k]] + (theta+u[study[k]])*active[k]
    arm_d[k] ~ dbin(prob[k], arm_n[k])
  }
  oddsratio <- exp(theta)
}
"
write(jagscode, "JAGS-simulation-RE-arm.txt")

jagsinits <- list(list(theta=0.5),
                  list(theta=(-0.5)))
                
jagsmod <- jags.model("JAGS-simulation-RE-arm.txt",
                      data=jagsdata,
                      inits=jagsinits,
                      n.chains=2)

update(jagsmod, n.iter=1000)
jagsdraws <- coda.samples(jagsmod,
                        variable.names=c("oddsratio", "tau"),
                        n.iter=10000)

summary(jagsdraws)

plot(jagsdraws)





# ------------------ RE/FE, binary, arm-based, equivalent alternative code --------------------


jagsdata <- list(m = m,
	             d1 = sim_binary_re$d1,
	             n1 = sim_binary_re$n1,
	             d2 = sim_binary_re$d2,
	             n2 = sim_binary_re$n2,
	             study = sim_binary_re$study)

jagscode <- "
model{
  theta ~ dnorm(0, 0.111)
  tau ~ dgamma(1.2, 1)
  tau_prec <- 1 / (tau*tau)

  for(j in 1:m){
    mu[j] ~ dnorm(0, 0.000001) # very diffuse
    u[j] ~ dnorm(0, tau_prec) # heterogeneity
    logit(prob1[j]) <- mu[study[j]]
    logit(prob2[j]) <- mu[study[j]] + u[study[j]] + theta
    d1[j] ~ dbin(prob1[j], n1[j])
    d2[j] ~ dbin(prob2[j], n2[j])
  }
  oddsratio <- exp(theta)
}
"
write(jagscode, "JAGS-simulation-RE-arm-alt.txt")

jagsinits <- list(list(theta=0.5),
                  list(theta=(-0.5)))
                
jagsmod <- jags.model("JAGS-simulation-RE-arm-alt.txt",
                      data=jagsdata,
                      inits=jagsinits,
                      n.chains=2)

update(jagsmod, n.iter=1000)
jagsdraws <- coda.samples(jagsmod,
                        variable.names=c("oddsratio", "tau"),
                        n.iter=10000)

summary(jagsdraws)

plot(jagsdraws)

tags: #jags, #jags-repo, #repo


Discover more from The Bayesian Meta-Analysis Network

Subscribe to get the latest posts sent to your email.

Leave a Reply

Discover more from The Bayesian Meta-Analysis Network

Subscribe now to keep reading and get access to the full archive.

Continue reading