Code from Statistical Rethinking modified by R Pruim is shown below. Differences to the oringal include:
ggplot2
(via ggformula
) rather than base graphicstidyverse
for data transformationlibrary(rethinking)
data(chimpanzees)
Chimps <- chimpanzees %>%
mutate( combo = paste0(prosoc_left, "/", condition) ) # used for plotting later
m10.1 <-
map(
alist(pulled_left ~ dbinom(1, p),
logit(p) <- a,
a ~ dnorm(0, 10)),
data = Chimps)
precis(m10.1)
## Mean StdDev 5.5% 94.5%
## a 0.32 0.09 0.18 0.46
# two different ways to get the inverse of the logit function
logistic(c(0.18, 0.46))
## [1] 0.5448789 0.6130142
ilogit(c(0.18, 0.46))
## [1] 0.5448789 0.6130142
m10.2 <-
map(
alist(
pulled_left ~ dbinom(1, p),
logit(p) <- a + bp * prosoc_left,
a ~ dnorm(0, 10),
bp ~ dnorm(0, 10)
),
data = Chimps)
m10.3 <-
map(
alist(
pulled_left ~ dbinom(1, p),
logit(p) <- a + (bp + bpC * condition) * prosoc_left,
a ~ dnorm(0, 10),
bp ~ dnorm(0, 10),
bpC ~ dnorm(0, 10)
),
data = Chimps)
compare(m10.1, m10.2, m10.3)
## WAIC pWAIC dWAIC weight SE dSE
## m10.2 680.4 1.9 0.0 0.71 9.32 NA
## m10.3 682.3 3.0 2.0 0.27 9.28 0.79
## m10.1 687.9 1.0 7.6 0.02 7.20 6.11
precis(m10.3)
## Mean StdDev 5.5% 94.5%
## a 0.05 0.13 -0.15 0.25
## bp 0.61 0.23 0.25 0.97
## bpC -0.10 0.26 -0.53 0.32
exp(0.61)
## [1] 1.840431
logistic(4)
## [1] 0.9820138
logistic(4 + 0.61)
## [1] 0.9901462
# dummy data for predictions across treatments
Chimps.pred <-
data_frame(
prosoc_left = c(0, 1, 0, 1), # right/left/right/left
condition = c(0, 0, 1, 1), # control/control/partner/partner
combo = paste0(prosoc_left, "/", condition) # used for plotting later
)
# build prediction ensemble
chimps.ensemble <- ensemble(m10.1, m10.2, m10.3, data = Chimps.pred, refresh = 0)
## Constructing posterior predictions
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
## Constructing posterior predictions
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
## Constructing posterior predictions
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
# summarize
Chimps.pred <-
Chimps.pred %>%
mutate(
pred.p = apply(chimps.ensemble$link, 2, mean),
pred.p.lo = apply(chimps.ensemble$link, 2, PI)[1,],
pred.p.hi = apply(chimps.ensemble$link, 2, PI)[2,]
)
# stat = "summary", fun.y = mean says use the average y value in each group
gf_line(pulled_left ~ combo + group::actor, data = Chimps,
stat = "summary", fun.y = mean,
alpha = 0.6) %>%
gf_ribbon(pred.p.lo + pred.p.hi ~ combo + fill:"red" + group:"1", data = Chimps.pred) %>%
gf_line(pred.p ~ combo + group:"1" + color:"red", data = Chimps.pred) %>%
gf_labs(x = "prosocial on = left / has partner", y = "proportion pulled left")
# clean NAs from the data
Chimps2 <- Chimps %>% select(-recipient)
# re-use map fit to get the formula
m10.3stan <-
map2stan(
m10.3,
data = Chimps2,
iter = 1e4,
warmup = 1000,
refresh = 0)
##
## Elapsed Time: 0.672495 seconds (Warm-up)
## 5.8845 seconds (Sampling)
## 6.55699 seconds (Total)
##
##
## SAMPLING FOR MODEL 'pulled_left ~ dbinom(1, p)' NOW (CHAIN 1).
## WARNING: No variance estimation is
## performed for num_warmup < 20
##
##
## Chain 1, Iteration: 1 / 1 [100%] (Sampling)
## Elapsed Time: 3e-06 seconds (Warm-up)
## 0.000247 seconds (Sampling)
## 0.00025 seconds (Total)
## Computing WAIC
## Constructing posterior predictions
## [ 900 / 9000 ]
[ 1800 / 9000 ]
[ 2700 / 9000 ]
[ 3600 / 9000 ]
[ 4500 / 9000 ]
[ 5400 / 9000 ]
[ 6300 / 9000 ]
[ 7200 / 9000 ]
[ 8100 / 9000 ]
[ 9000 / 9000 ]
precis(m10.3stan)
## Mean StdDev lower 0.89 upper 0.89 n_eff Rhat
## a 0.05 0.13 -0.16 0.25 4884 1
## bp 0.62 0.23 0.27 1.00 4604 1
## bpC -0.11 0.26 -0.53 0.30 5331 1
pairs(m10.3stan)
m10.4 <- map2stan(
alist(
pulled_left ~ dbinom(1, p),
logit(p) <- a[actor] + (bp + bpC * condition) * prosoc_left,
a[actor] ~ dnorm(0, 10),
bp ~ dnorm(0, 10),
bpC ~ dnorm(0, 10)
),
data = Chimps2,
chains = 2,
iter = 2500,
warmup = 500,
refresh = 0
)
##
## Elapsed Time: 0.630185 seconds (Warm-up)
## 2.19867 seconds (Sampling)
## 2.82885 seconds (Total)
##
##
## Elapsed Time: 0.647648 seconds (Warm-up)
## 2.18752 seconds (Sampling)
## 2.83517 seconds (Total)
## Warning: There were 61 divergent transitions after warmup. Increasing adapt_delta above 0.8 may help. See
## http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
## Warning: Examine the pairs() plot to diagnose sampling problems
##
## SAMPLING FOR MODEL 'pulled_left ~ dbinom(1, p)' NOW (CHAIN 1).
## WARNING: No variance estimation is
## performed for num_warmup < 20
##
##
## Chain 1, Iteration: 1 / 1 [100%] (Sampling)
## Elapsed Time: 5e-06 seconds (Warm-up)
## 0.000375 seconds (Sampling)
## 0.00038 seconds (Total)
## Computing WAIC
## Constructing posterior predictions
## [ 400 / 4000 ]
[ 800 / 4000 ]
[ 1200 / 4000 ]
[ 1600 / 4000 ]
[ 2000 / 4000 ]
[ 2400 / 4000 ]
[ 2800 / 4000 ]
[ 3200 / 4000 ]
[ 3600 / 4000 ]
[ 4000 / 4000 ]
## Warning in map2stan(alist(pulled_left ~ dbinom(1, p), logit(p) <- a[actor] + : There were 61 divergent iterations during sampling.
## Check the chains (trace plots, n_eff, Rhat) carefully to ensure they are valid.
tally(~ actor, data = Chimps)
## actor
## 1 2 3 4 5 6 7
## 72 72 72 72 72 72 72
precis(m10.4, depth = 2)
## Warning in precis(m10.4, depth = 2): There were 61 divergent iterations during sampling.
## Check the chains (trace plots, n_eff, Rhat) carefully to ensure they are valid.
## Mean StdDev lower 0.89 upper 0.89 n_eff Rhat
## a[1] -0.74 0.27 -1.20 -0.33 2502 1
## a[2] 11.09 5.41 3.69 18.71 1900 1
## a[3] -1.05 0.28 -1.47 -0.59 2678 1
## a[4] -1.05 0.28 -1.50 -0.60 2413 1
## a[5] -0.73 0.28 -1.18 -0.31 2703 1
## a[6] 0.22 0.27 -0.20 0.66 3025 1
## a[7] 1.81 0.40 1.11 2.37 2484 1
## bp 0.84 0.26 0.43 1.26 1737 1
## bpC -0.14 0.30 -0.62 0.34 2206 1
m10.4_post <- extract.samples(m10.4)
str(m10.4_post)
## List of 3
## $ a : num [1:4000, 1:7] -0.891 -0.821 -1.058 -0.779 -0.66 ...
## $ bp : num [1:4000(1d)] 0.966 0.951 0.853 0.999 0.999 ...
## $ bpC: num [1:4000(1d)] -0.0648 -0.1311 0.0805 -0.0667 -0.0493 ...
gf_dens(~ (m10.4_post$a[, 2]))
as.data.frame(m10.4_post) %>% head(2)
## a.1 a.2 a.3 a.4 a.5 a.6 a.7
## 1 -0.8910460 9.775388 -1.073532 -1.262073 -0.6483801 0.3301656 0.9398147
## 2 -0.8209078 28.384526 -1.254034 -1.139401 -0.6063624 0.2021648 1.7301476
## bp bpC
## 1 0.9655670 -0.06482745
## 2 0.9513141 -0.13111120
gf_dens(~ a.2, data = m10.4_post %>% as.data.frame())
Chimps.pred <-
expand.grid(
actor = 1:7,
prosoc_left = 0:1,
condition = 0:1) %>%
mutate(
combo = paste0(prosoc_left, "/", condition)
)
m10.4_link <- link(m10.4, data = Chimps.pred)
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
Chimps.pred <-
Chimps.pred %>%
mutate(
pred.p = apply(m10.4_link, 2, mean),
pred.p.lo = apply(m10.4_link, 2, PI)[1,],
pred.p.hi = apply(m10.4_link, 2, PI)[2,]
)
gf_ribbon(pred.p.lo + pred.p.hi ~ combo + group:"1", data = Chimps.pred) %>%
gf_line(pred.p ~ combo + group:"1", data = Chimps.pred) %>%
gf_line(pulled_left ~ combo + group:"1", data = Chimps, color = "red",
stat = "summary", fun.y = mean) %>%
gf_facet_wrap( ~ actor) %>%
gf_labs(x = "prosocial on left / has partner", y = "proportion pulled left") %>%
gf_refine(ylim(0,1))
We can redo the models from the previous section using data that is summarised into counts.
The book only computes x
(because n
is 18 in each case). But in general, both x
and n
might vary. So let’s get in the habbit of keeping both x
and n
in our aggregated data.
Chimps.ag <-
Chimps %>%
group_by(prosoc_left, condition, actor) %>%
summarise(x = sum(pulled_left), n = n()) %>%
arrange(actor, condition, prosoc_left) # put things into same order as in book
Chimps.ag %>% head()
## Source: local data frame [6 x 5]
## Groups: prosoc_left, condition [4]
##
## prosoc_left condition actor x n
## <int> <int> <int> <int> <int>
## 1 0 0 1 6 18
## 2 1 0 1 9 18
## 3 0 1 1 5 18
## 4 1 1 1 10 18
## 5 0 0 2 18 18
## 6 1 0 2 18 18
No reason to assume every chimp has same number of observations (although they do in this case). Let’s put n
in place of 18
.
m10.5 <- map(
alist(
x ~ dbinom(n, p),
logit(p) <- a + (bp + bpC * condition) * prosoc_left,
a ~ dnorm(0, 10),
bp ~ dnorm(0, 10),
bpC ~ dnorm(0, 10)
),
data = Chimps.ag)
data(UCBadmit)
Admit <- UCBadmit %>%
mutate(male = ifelse(applicant.gender == "male", 1, 0))
m10.6 <-
map(
alist(
admit ~ dbinom(applications, p),
logit(p) <- a + bm * male,
a ~ dnorm(0, 10),
bm ~ dnorm(0, 10)
),
data = Admit)
m10.7 <-
map(
alist(admit ~ dbinom(applications, p),
logit(p) <- a,
a ~ dnorm(0, 10)),
data = Admit,
start = list(a = 5))
compare(m10.6, m10.7)
## WAIC pWAIC dWAIC weight SE dSE
## m10.6 5954.7 1.9 0.0 1 35.11 NA
## m10.7 6046.3 1.0 91.6 0 29.87 19.25
precis(m10.6)
## Mean StdDev 5.5% 94.5%
## a -0.83 0.05 -0.91 -0.75
## bm 0.61 0.06 0.51 0.71
m10.6_post <- extract.samples(m10.6, refresh = 0) %>%
mutate(
p.admit.male = logistic(a + bm),
p.admit.female = logistic(a),
p.admit.diff = p.admit.male - p.admit.female
)
gf_dens(~p.admit.diff, data = m10.6_post)
qdata(~ p.admit.diff, c(0.025, 0.5, 0.975), data = m10.6_post)
## quantile p
## 2.5% 0.1126204 0.025
## 50% 0.1417237 0.500
## 97.5% 0.1698590 0.975
quantile(~ p.admit.diff, p = c(0.025, 0.5, 0.975), data = m10.6_post)
## 2.5% 50% 97.5%
## 0.1126204 0.1417237 0.1698590
quantile(m10.6_post$p.admit.diff, c(0.025, 0.5, 0.975))
## 2.5% 50% 97.5%
## 0.1126204 0.1417237 0.1698590
PC <- postcheck(m10.6, n = 1e4)
## [ 1000 / 10000 ]
[ 2000 / 10000 ]
[ 3000 / 10000 ]
[ 4000 / 10000 ]
[ 5000 / 10000 ]
[ 6000 / 10000 ]
[ 7000 / 10000 ]
[ 8000 / 10000 ]
[ 9000 / 10000 ]
[ 10000 / 10000 ]
## [ 1000 / 10000 ]
[ 2000 / 10000 ]
[ 3000 / 10000 ]
[ 4000 / 10000 ]
[ 5000 / 10000 ]
[ 6000 / 10000 ]
[ 7000 / 10000 ]
[ 8000 / 10000 ]
[ 9000 / 10000 ]
[ 10000 / 10000 ]
# draw lines connecting points from same dept
for (i in 1:6) {
x <- 1 + 2 * (i - 1)
y1 <- Admit$admit[x] / Admit$applications[x]
y2 <- Admit$admit[x + 1] / Admit$applications[x + 1]
lines(c(x, x + 1), c(y1, y2), col = rangi2, lwd = 2)
text(x + 0.5,
(y1 + y2) / 2 + 0.05,
Admit$dept[x],
cex = 0.8,
col = rangi2)
}
Here’s a version that displays this information differently and is created from scratch.
m10.6_link <- link(m10.6)
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
m10.6_sim <- sim(m10.6)
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
m10.6_pc <-
Admit %>%
mutate(
p.admit = admit / applications,
pred.admit = apply(m10.6_link, 2, median),
link.admit.lo = apply(m10.6_link, 2, PI,prob = 0.95)[1,],
link.admit.hi = apply(m10.6_link, 2, PI,prob = 0.95)[2,],
sim.admit.lo = apply(m10.6_sim, 2, PI,prob = 0.95)[1,] / applications,
sim.admit.hi = apply(m10.6_sim, 2, PI,prob = 0.95)[2,] / applications
)
gf_point(p.admit ~ dept + color::applicant.gender, data = m10.6_pc,
position = position_dodge(width = 0.4), size = 1.8) %>%
gf_point(pred.admit ~ dept + color::applicant.gender, data = m10.6_pc,
position = position_dodge(width = 0.4), shape = 3, size = 3) %>%
gf_linerange(link.admit.lo + link.admit.hi ~ dept + color::applicant.gender, data = m10.6_pc,
position = position_dodge(width = 0.4), alpha = 0.6, size = 1.5) %>%
gf_linerange(sim.admit.lo + sim.admit.hi ~ dept + color::applicant.gender, data = m10.6_pc,
position = position_dodge(width = 0.4), alpha = 0.6) %>%
gf_labs(title = "posterior check for m10.6") %>%
gf_refine(scale_color_manual(values = c(male = "navy", female = "red")))
# make index
Admit <-
Admit %>%
mutate(
dept_id = coerce_index(dept)
)
# model with unique intercept for each dept
m10.8 <-
map(
alist(
admit ~ dbinom(applications, p),
logit(p) <- a[dept_id],
a[dept_id] ~ dnorm(0, 10)),
data = Admit)
# model with male difference as well
m10.9 <-
map(
alist(
admit ~ dbinom(applications, p),
logit(p) <- a[dept_id] + bm * male,
a[dept_id] ~ dnorm(0, 10),
bm ~ dnorm(0, 10)
),
data = Admit)
compare(m10.6, m10.7, m10.8, m10.9)
## WAIC pWAIC dWAIC weight SE dSE
## m10.9 5200.9 6.7 0.0 0.54 57.07 NA
## m10.8 5201.2 6.1 0.3 0.46 57.03 2.58
## m10.6 5955.0 2.0 754.0 0.00 35.05 49.42
## m10.7 6046.4 1.1 845.5 0.00 29.89 52.44
precis(m10.9, depth = 2)
## Mean StdDev 5.5% 94.5%
## a[1] 0.68 0.10 0.52 0.84
## a[2] 0.64 0.12 0.45 0.82
## a[3] -0.58 0.07 -0.70 -0.46
## a[4] -0.61 0.09 -0.75 -0.48
## a[5] -1.06 0.10 -1.22 -0.90
## a[6] -2.62 0.16 -2.88 -2.37
## bm -0.10 0.08 -0.23 0.03
m10.9stan <-
map2stan(
m10.9,
chains = 2,
iter = 2500,
warmup = 500,
refresh = 0)
## Warning: Variable 'applicant.gender' contains dots '.'.
## Will attempt to remove dots internally.
##
## Elapsed Time: 0.027456 seconds (Warm-up)
## 0.094403 seconds (Sampling)
## 0.121859 seconds (Total)
##
##
## Elapsed Time: 0.022696 seconds (Warm-up)
## 0.095133 seconds (Sampling)
## 0.117829 seconds (Total)
##
##
## SAMPLING FOR MODEL 'admit ~ dbinom(applications, p)' NOW (CHAIN 1).
## WARNING: No variance estimation is
## performed for num_warmup < 20
##
##
## Chain 1, Iteration: 1 / 1 [100%] (Sampling)
## Elapsed Time: 4e-06 seconds (Warm-up)
## 3.5e-05 seconds (Sampling)
## 3.9e-05 seconds (Total)
## Computing WAIC
## Constructing posterior predictions
## [ 400 / 4000 ]
[ 800 / 4000 ]
[ 1200 / 4000 ]
[ 1600 / 4000 ]
[ 2000 / 4000 ]
[ 2400 / 4000 ]
[ 2800 / 4000 ]
[ 3200 / 4000 ]
[ 3600 / 4000 ]
[ 4000 / 4000 ]
## Aggregated binomial counts detected. Splitting to 0/1 outcome for WAIC calculation.
precis(m10.9stan, depth = 2)
## Mean StdDev lower 0.89 upper 0.89 n_eff Rhat
## a[1] 0.68 0.10 0.54 0.85 2250 1
## a[2] 0.64 0.12 0.46 0.83 2476 1
## a[3] -0.58 0.07 -0.71 -0.47 4000 1
## a[4] -0.61 0.09 -0.75 -0.48 4000 1
## a[5] -1.06 0.10 -1.21 -0.89 4000 1
## a[6] -2.63 0.16 -2.90 -2.37 4000 1
## bm -0.10 0.08 -0.23 0.03 1784 1
plot(precis(m10.9, depth = 2))
plot(precis(m10.9stan, depth = 2))
m10.9_link <- link(m10.9)
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
m10.9_sim <- sim(m10.9)
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
m10.9_pc <-
Admit %>%
mutate(
p.admit = admit / applications,
pred.admit = apply(m10.9_link, 2, median),
link.admit.lo = apply(m10.9_link, 2, PI,prob = 0.95)[1,],
link.admit.hi = apply(m10.9_link, 2, PI,prob = 0.95)[2,],
sim.admit.lo = apply(m10.9_sim, 2, PI,prob = 0.95)[1,] / applications,
sim.admit.hi = apply(m10.9_sim, 2, PI,prob = 0.95)[2,] / applications
)
gf_point(p.admit ~ dept + color::applicant.gender, data = m10.9_pc,
position = position_dodge(width = 0.4), size = 1.8) %>%
gf_point(pred.admit ~ dept + color::applicant.gender, data = m10.9_pc,
position = position_dodge(width = 0.4), shape = 3, size = 3) %>%
gf_linerange(link.admit.lo + link.admit.hi ~ dept + color::applicant.gender, data = m10.9_pc,
position = position_dodge(width = 0.4), alpha = 0.6, size = 1.3) %>%
gf_linerange(sim.admit.lo + sim.admit.hi ~ dept + color::applicant.gender, data = m10.9_pc,
position = position_dodge(width = 0.4), alpha = 0.6) %>%
gf_labs(title = "posterior check for m10.9") %>%
gf_refine(scale_color_manual(values = c(male = "navy", female = "red")))
m10.7glm <-
glm(cbind(admit, reject) ~ 1, data = Admit, family = binomial)
m10.6glm <-
glm(cbind(admit, reject) ~ male, data = Admit, family = binomial)
m10.8glm <-
glm(cbind(admit, reject) ~ dept, data = Admit, family = binomial)
m10.9glm <- glm(cbind(admit, reject) ~ male + dept,
data = Admit,
family = binomial)
data(chimpanzees)
m10.4glm <- glm(
pulled_left ~ as.factor(actor) + prosoc_left * condition - condition,
data = chimpanzees,
family = binomial
)
glimmer(pulled_left ~ prosoc_left * condition - condition,
data = chimpanzees,
family = binomial)
## alist(
## pulled_left ~ dbinom( 1 , p ),
## logit(p) <- Intercept +
## b_prosoc_left*prosoc_left +
## b_prosoc_left_X_condition*prosoc_left_X_condition,
## Intercept ~ dnorm(0,10),
## b_prosoc_left ~ dnorm(0,10),
## b_prosoc_left_X_condition ~ dnorm(0,10)
## )
# outcome and predictor almost perfectly associated
y <- c(rep(0, 10), rep(1, 10))
x <- c(rep(-1, 9), rep(1, 11))
# fit binomial GLM
m.bad <- glm(y ~ x, data = list(y = y, x = x), family = binomial)
precis(m.bad)
## Mean StdDev 5.5% 94.5%
## (Intercept) -9.13 2955.06 -4731.89 4713.63
## x 11.43 2955.06 -4711.33 4734.19
m.good <- map(alist(y ~ dbinom(1, p),
logit(p) <- a + b * x,
c(a, b) ~ dnorm(0, 10)), data = list(y = y, x = x))
precis(m.good)
## Mean StdDev 5.5% 94.5%
## a -1.73 2.78 -6.16 2.71
## b 4.02 2.78 -0.42 8.45
m.good.stan <- map2stan(m.good)
##
## SAMPLING FOR MODEL 'y ~ dbinom(1, p)' NOW (CHAIN 1).
##
## Chain 1, Iteration: 1 / 2000 [ 0%] (Warmup)
## Chain 1, Iteration: 200 / 2000 [ 10%] (Warmup)
## Chain 1, Iteration: 400 / 2000 [ 20%] (Warmup)
## Chain 1, Iteration: 600 / 2000 [ 30%] (Warmup)
## Chain 1, Iteration: 800 / 2000 [ 40%] (Warmup)
## Chain 1, Iteration: 1000 / 2000 [ 50%] (Warmup)
## Chain 1, Iteration: 1001 / 2000 [ 50%] (Sampling)
## Chain 1, Iteration: 1200 / 2000 [ 60%] (Sampling)
## Chain 1, Iteration: 1400 / 2000 [ 70%] (Sampling)
## Chain 1, Iteration: 1600 / 2000 [ 80%] (Sampling)
## Chain 1, Iteration: 1800 / 2000 [ 90%] (Sampling)
## Chain 1, Iteration: 2000 / 2000 [100%] (Sampling)
## Elapsed Time: 0.049456 seconds (Warm-up)
## 0.050337 seconds (Sampling)
## 0.099793 seconds (Total)
##
##
## SAMPLING FOR MODEL 'y ~ dbinom(1, p)' NOW (CHAIN 1).
## WARNING: No variance estimation is
## performed for num_warmup < 20
##
##
## Chain 1, Iteration: 1 / 1 [100%] (Sampling)
## Elapsed Time: 4e-06 seconds (Warm-up)
## 7.4e-05 seconds (Sampling)
## 7.8e-05 seconds (Total)
## Computing WAIC
## Constructing posterior predictions
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
precis(m.good.stan)
## Mean StdDev lower 0.89 upper 0.89 n_eff Rhat
## a -5.27 3.95 -10.95 0.77 130 1.01
## b 8.11 3.90 2.78 14.05 127 1.00
pairs(m.good.stan)
y <- rbinom(1e5, 1000, 1 / 1000)
c(mean(y), var(y))
## [1] 0.9978200 0.9958252
data(Kline)
Kline <-
Kline %>%
mutate(
log_pop = log(population),
contact_high = ifelse(contact == "high", 1, 0)
)
m10.10 <-
map(
alist(
total_tools ~ dpois(lambda),
log(lambda) <- a + bp * log_pop +
bc * contact_high + bpc * contact_high * log_pop,
a ~ dnorm(0, 100),
c(bp, bc, bpc) ~ dnorm(0, 1)
),
data = Kline
)
precis(m10.10, corr = TRUE)
## Mean StdDev 5.5% 94.5% a bp bc bpc
## a 0.94 0.36 0.37 1.52 1.00 -0.98 -0.13 0.07
## bp 0.26 0.03 0.21 0.32 -0.98 1.00 0.12 -0.08
## bc -0.09 0.84 -1.43 1.25 -0.13 0.12 1.00 -0.99
## bpc 0.04 0.09 -0.10 0.19 0.07 -0.08 -0.99 1.00
plot(precis(m10.10))
post <-
extract.samples(m10.10) %>%
mutate(
lambda_high = exp(a + bc + (bp + bpc) * 8),
lambda_low = exp(a + bp * 8)
)
diff <- lambda_high - lambda_low
## Error in eval(expr, envir, enclos): object 'lambda_high' not found
sum(diff > 0) / length(diff)
## Error in diff > 0: comparison (6) is possible only for atomic and list types
# no interaction
m10.11 <- map(
alist(
total_tools ~ dpois(lambda),
log(lambda) <- a + bp * log_pop + bc * contact_high,
a ~ dnorm(0, 100),
c(bp, bc) ~ dnorm(0, 1)
),
data = Kline
)
# no contact rate
m10.12 <-
map(
alist(
total_tools ~ dpois(lambda),
log(lambda) <- a + bp * log_pop,
a ~ dnorm(0, 100),
bp ~ dnorm(0, 1)
),
data = Kline)
# no log-population
m10.13 <-
map(
alist(
total_tools ~ dpois(lambda),
log(lambda) <- a + bc * contact_high,
a ~ dnorm(0, 100),
bc ~ dnorm(0, 1)
),
data = Kline)
# intercept only
m10.14 <-
map(
alist(
total_tools ~ dpois(lambda),
log(lambda) <- a,
a ~ dnorm(0, 100)),
data = Kline)
# compare all using WAIC
# adding n=1e4 for more stable WAIC estimates
# will also plot the comparison
(islands.compare <-
compare(m10.10, m10.11, m10.12, m10.13, m10.14, n = 1e4))
## WAIC pWAIC dWAIC weight SE dSE
## m10.11 79.3 4.3 0.0 0.60 11.15 NA
## m10.10 80.3 5.0 1.1 0.36 11.40 1.23
## m10.12 84.6 3.9 5.3 0.04 8.87 8.29
## m10.14 141.6 8.4 62.3 0.00 31.62 34.42
## m10.13 150.9 17.1 71.6 0.00 44.76 46.75
plot(islands.compare)
Kline.pred <-
expand.grid(
log_pop = seq(from = 6, to = 13, by = 0.25),
contact_high = 0L:1L
) %>%
mutate(
contact = ifelse(contact_high == 1, "high", "low")
)
Kline.ens <- ensemble(m10.10, m10.11, m10.12, data = Kline.pred, refresh = 0)
## Constructing posterior predictions
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
## Constructing posterior predictions
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
## Constructing posterior predictions
## [ 100 / 1000 ]
[ 200 / 1000 ]
[ 300 / 1000 ]
[ 400 / 1000 ]
[ 500 / 1000 ]
[ 600 / 1000 ]
[ 700 / 1000 ]
[ 800 / 1000 ]
[ 900 / 1000 ]
[ 1000 / 1000 ]
Kline.pred <-
Kline.pred %>%
mutate(
lambda.med = apply(Kline.ens$link, 2, median),
lambda.link.lo = apply(Kline.ens$link, 2, PI)[1,],
lambda.link.hi = apply(Kline.ens$link, 2, PI)[2,])
gf_point(total_tools ~ log_pop + shape:contact + color:contact, data = Kline) %>%
gf_ribbon(lambda.link.lo + lambda.link.hi ~ log_pop + fill:contact, data = Kline.pred) %>%
gf_line(lambda.med ~ log_pop + color:contact, data = Kline.pred) %>%
gf_refine(scale_shape_manual(values = c(16, 1)))
m10.10stan <-
map2stan(
m10.10,
iter = 3000,
warmup = 1000,
chains = 4,
refresh = 0)
##
## Elapsed Time: 0.291652 seconds (Warm-up)
## 0.296672 seconds (Sampling)
## 0.588324 seconds (Total)
##
##
## Elapsed Time: 0.624632 seconds (Warm-up)
## 0.329524 seconds (Sampling)
## 0.954156 seconds (Total)
##
##
## Elapsed Time: 0.188047 seconds (Warm-up)
## 0.293161 seconds (Sampling)
## 0.481208 seconds (Total)
##
##
## Elapsed Time: 0.188932 seconds (Warm-up)
## 0.330265 seconds (Sampling)
## 0.519197 seconds (Total)
##
##
## SAMPLING FOR MODEL 'total_tools ~ dpois(lambda)' NOW (CHAIN 1).
## WARNING: No variance estimation is
## performed for num_warmup < 20
##
##
## Chain 1, Iteration: 1 / 1 [100%] (Sampling)
## Elapsed Time: 3e-06 seconds (Warm-up)
## 2.4e-05 seconds (Sampling)
## 2.7e-05 seconds (Total)
## Computing WAIC
## Constructing posterior predictions
## [ 800 / 8000 ]
[ 1600 / 8000 ]
[ 2400 / 8000 ]
[ 3200 / 8000 ]
[ 4000 / 8000 ]
[ 4800 / 8000 ]
[ 5600 / 8000 ]
[ 6400 / 8000 ]
[ 7200 / 8000 ]
[ 8000 / 8000 ]
precis(m10.10stan)
## Mean StdDev lower 0.89 upper 0.89 n_eff Rhat
## a 0.94 0.35 0.34 1.46 2898 1
## bp 0.26 0.03 0.21 0.32 2876 1
## bc -0.10 0.86 -1.46 1.27 2822 1
## bpc 0.04 0.09 -0.11 0.19 2823 1
# construct centered predictor
Kline <-
Kline %>%
mutate(log_pop_c = log_pop - mean(log_pop))
# re-estimate
m10.10stan.c <-
map2stan(
alist(
total_tools ~ dpois(lambda),
log(lambda) <- a + bp * log_pop_c + bc * contact_high +
bcp * log_pop_c * contact_high,
a ~ dnorm(0, 10),
bp ~ dnorm(0, 1),
bc ~ dnorm(0, 1),
bcp ~ dnorm(0, 1)
),
data = Kline,
iter = 3000,
warmup = 1000,
chains = 4,
refresh = 0
)
##
## Elapsed Time: 0.031641 seconds (Warm-up)
## 0.060115 seconds (Sampling)
## 0.091756 seconds (Total)
##
##
## Elapsed Time: 0.035005 seconds (Warm-up)
## 0.060652 seconds (Sampling)
## 0.095657 seconds (Total)
##
##
## Elapsed Time: 0.034197 seconds (Warm-up)
## 0.055311 seconds (Sampling)
## 0.089508 seconds (Total)
##
##
## Elapsed Time: 0.030636 seconds (Warm-up)
## 0.053154 seconds (Sampling)
## 0.08379 seconds (Total)
##
##
## SAMPLING FOR MODEL 'total_tools ~ dpois(lambda)' NOW (CHAIN 1).
## WARNING: No variance estimation is
## performed for num_warmup < 20
##
##
## Chain 1, Iteration: 1 / 1 [100%] (Sampling)
## Elapsed Time: 3e-06 seconds (Warm-up)
## 2.5e-05 seconds (Sampling)
## 2.8e-05 seconds (Total)
## Computing WAIC
## Constructing posterior predictions
## [ 800 / 8000 ]
[ 1600 / 8000 ]
[ 2400 / 8000 ]
[ 3200 / 8000 ]
[ 4000 / 8000 ]
[ 4800 / 8000 ]
[ 5600 / 8000 ]
[ 6400 / 8000 ]
[ 7200 / 8000 ]
[ 8000 / 8000 ]
precis(m10.10stan.c)
## Mean StdDev lower 0.89 upper 0.89 n_eff Rhat
## a 3.31 0.09 3.17 3.45 5314 1
## bp 0.26 0.04 0.21 0.32 6010 1
## bc 0.28 0.12 0.09 0.47 5247 1
## bcp 0.07 0.17 -0.20 0.34 6601 1
num_days <- 30
y <- rpois(num_days, 1.5)
num_weeks <- 4
y_new <- rpois(num_weeks, 0.5 * 7)
D <-
data_frame(
y_all = c(y, y_new),
days = c(rep(1, 30), rep(7, 4)),
monastery = c(rep(0, 30), rep(1, 4))
)
# compute the offset
D <- D %>% mutate(log_days = log(days))
# fit the model
m10.15 <-
map(
alist(
y ~ dpois(lambda),
log(lambda) <- log_days + a + b * monastery,
a ~ dnorm(0, 100),
b ~ dnorm(0, 1)
),
data = D)
post <- extract.samples(m10.15) %>%
mutate(
lambda_old = exp(a),
lambda_new = exp(a + b)
)
precis(post %>% select(lambda_old, lambda_new))
## Mean StdDev |0.89 0.89|
## lambda_old 1.47 0.22 1.11 1.80
## lambda_new 0.32 0.11 0.16 0.47
# simulate career choices among 500 individuals
income <- 1:3 # expected income of each career
score <- 0.5 * income # scores for each career, based on income
# next line converts scores to probabilities
p <- softmax(score[1], score[2], score[3])
p
## [1] 0.1863237 0.3071959 0.5064804
# sample chosen career for each individual
career <- sample(1:3, size = 500, prob = p, replace = TRUE)
tally(~career, format = "proportion")
## career
## 1 2 3
## 0.194 0.316 0.490
# fit the model, using dcategorical and softmax link
m10.16 <-
map(
alist(
career ~ dcategorical(softmax(0, s2, s3)),
s2 <- b * 2, # linear model for event type 2
s3 <- b * 3, # linear model for event type 3
b ~ dnorm(0, 5)),
data = list(career = career))
F <-
data_frame(
family_income = runif(100),
career = NA
)
# assign a unique coefficient for each type of event
b <- (1:-1)
for (i in 1:nrow(F)) {
score <- 0.5 * (1:3) + b * F$family_income[i]
p <- softmax(score[1], score[2], score[3])
F$career[i] <- sample(1:3, size = 1, prob = p)
}
m10.17 <- map(
alist(
career ~ dcategorical(softmax(0, s2, s3)),
s2 <- a2 + b2 * family_income,
s3 <- a3 + b3 * family_income,
c(a2, a3, b2, b3) ~ dnorm(0, 5)
),
data = F
)
data(UCBadmit)
Admit <- UCBadmit
# binomial model of overall admission probability
m_binom <-
map(
alist(
admit ~ dbinom(applications, p),
logit(p) <- a,
a ~ dnorm(0, 100)),
data = Admit)
# Poisson model of overall admission rate and rejection rate
Admit <- Admit %>% rename(rej = reject) # 'reject' is a reserved word
m_pois <- map2stan(
alist(
admit ~ dpois(lambda1),
rej ~ dpois(lambda2),
log(lambda1) <- a1,
log(lambda2) <- a2,
c(a1, a2) ~ dnorm(0, 100)
),
data = Admit,
chains = 3,
cores = 3,
refresh = 0
)
## Warning: Variable 'applicant.gender' contains dots '.'.
## Will attempt to remove dots internally.
##
## SAMPLING FOR MODEL 'admit ~ dpois(lambda1)' NOW (CHAIN 1).
## WARNING: No variance estimation is
## performed for num_warmup < 20
##
##
## Chain 1, Iteration: 1 / 1 [100%] (Sampling)
## Elapsed Time: 3e-06 seconds (Warm-up)
## 4.2e-05 seconds (Sampling)
## 4.5e-05 seconds (Total)
## Computing WAIC
## Constructing posterior predictions
## [ 300 / 3000 ]
[ 600 / 3000 ]
[ 900 / 3000 ]
[ 1200 / 3000 ]
[ 1500 / 3000 ]
[ 1800 / 3000 ]
[ 2100 / 3000 ]
[ 2400 / 3000 ]
[ 2700 / 3000 ]
[ 3000 / 3000 ]
logistic(coef(m_binom))
## a
## 0.3877596
k <- as.numeric(coef(m_pois))
exp(k[1]) / (exp(k[1]) + exp(k[2]))
## [1] 0.3876971
# simulate
simData <- function(n = 100) {
data_frame(
x = runif(n),
y = rgeom(n, prob = logistic(-1 + 2 * x))
)
}
# estimate
m10.18 <-
map(
alist(y ~ dgeom(p),
logit(p) <- a + b * x,
a ~ dnorm(0, 10),
b ~ dnorm(0, 1)),
data = simData()
)
precis(m10.18)
## Mean StdDev 5.5% 94.5%
## a -1.24 0.23 -1.60 -0.87
## b 2.26 0.45 1.54 2.97