Building a logistic regression model: wells in Bangladesh. See Chapter 13 in Regression and Other Stories.

This version uses algorithm='optimizing', which finds the posterior mode, computes Hessian and uses a normal distribution approximation of the posterior. This can work well for non-hierarchical generalized linear models when the number of observations is much higher than the number of covariates.


Load packages

library("rprojroot")
root<-has_file(".ROS-Examples-root")$make_fix_file()
library("rstanarm")
library("loo")
invlogit <- plogis

Load data

wells <- read.csv(root("Arsenic/data","wells.csv"))
wells$y <- wells$switch
n <- nrow(wells)

Null model

Log-score for coin flipping

prob <- 0.5
round(log(prob)*sum(wells$y) + log(1-prob)*sum(1-wells$y),1)
[1] -2093.3

Log-score for intercept model

round(prob <- mean(wells$y),2)
[1] 0.58
round(log(prob)*sum(wells$y) + log(1-prob)*sum(1-wells$y),1)
[1] -2059

A single predictor

Fit a model using distance to the nearest safe well

fit_1 <- stan_glm(y ~ dist, family = binomial(link = "logit"), data=wells, algorithm='optimizing')
print(fit_1, digits=3)
stan_glm
 family:       binomial [logit]
 formula:      y ~ dist
 observations: 3020
 predictors:   2
------
            Median MAD_SD
(Intercept)  0.609  0.063
dist        -0.006  0.001

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_1, digits=3)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ dist
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   2

Estimates:
              Median   MAD_SD   10%    50%    90% 
(Intercept)  0.609    0.063    0.529  0.609  0.689
dist        -0.006    0.001   -0.007 -0.006 -0.005

Monte Carlo diagnostics
            mcse  khat  n_eff
(Intercept) 0.002 0.224 738  
dist        0.000 0.360 752  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo1 <- loo(fit_1))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -2040.1 10.4
p_loo         2.0  0.0
looic      4080.3 20.9
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Histogram of distances

hist(wells$dist, breaks=seq(0,10+max(wells$dist),10), freq=TRUE,
     xlab="Distance (in meters) to nearest safe well", ylab="", main="", mgp=c(2,.5,0))

Scale distance in meters to distance in 100 meters

wells$dist100 <- wells$dist/100

Fit a model using scaled distance to the nearest safe well

fit_2 <- stan_glm(y ~ dist100, family = binomial(link = "logit"), data=wells, algorithm='optimizing')
print(fit_2, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100
 observations: 3020
 predictors:   2
------
            Median MAD_SD
(Intercept)  0.61   0.07 
dist100     -0.63   0.11 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_2, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   2

Estimates:
              Median   MAD_SD   10%   50%   90%
(Intercept)  0.61     0.07     0.53  0.61  0.69
dist100     -0.63     0.11    -0.76 -0.63 -0.48

Monte Carlo diagnostics
            mcse khat n_eff
(Intercept) 0.00 0.18 761  
dist100     0.00 0.17 717  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo2 <- loo(fit_2, save_psis = TRUE))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -2040.3 10.4
p_loo         2.1  0.1
looic      4080.5 20.8
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Plot model fit

jitter_binary <- function(a, jitt=.05){
  a + (1-2*a)*runif(length(a),0,jitt)
}
plot(c(0,max(wells$dist, na.rm=TRUE)*1.02), c(0,1),
     xlab="Distance (in meters) to nearest safe well", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
curve(invlogit(coef(fit_1)[1]+coef(fit_1)[2]*x), lwd=1, add=TRUE)
points(wells$dist, jitter_binary(wells$y), pch=20, cex=.1)

Plot uncertainty in the estimated coefficients

sims <- as.matrix(fit_2)
par(pty="s")
plot(sims[1:500,1], sims[1:500,2], xlim=c(.4,.8), ylim=c(-1,0),
     xlab=expression(beta[0]), ylab=expression(beta[1]), mgp=c(1.5,.5,0),
     pch=20, cex=.5, xaxt="n", yaxt="n")
axis(1, seq(.4,.8,.2), mgp=c(1.5,.5,0))
axis(2, seq(-1,0,.5), mgp=c(1.5,.5,0))

Plot uncertainty in the estimated predictions

plot(c(0,max(wells$dist, na.rm=T)*1.02), c(0,1),
     xlab="Distance (in meters) to nearest safe well", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
for (j in 1:20) {
    curve (invlogit(sims[j,1]+sims[j,2]*x/100), lwd=.5,
           col="darkgray", add=TRUE)
}
curve(invlogit(coef(fit_2)[1]+coef(fit_2)[2]*x/100), lwd=1, add=T)
points(wells$dist, jitter_binary(wells$y), pch=20, cex=.1)

Two predictors

Histogram of arsenic levels

hist(wells$arsenic, breaks=seq(0,.25+max(wells$arsenic),.25), freq=TRUE,
     xlab="Arsenic concentration in well water", ylab="", main="", mgp=c(2,.5,0))

Fit a model using scaled distance and arsenic level

fit_3 <- stan_glm(y ~ dist100 + arsenic, family = binomial(link = "logit"),
                  data=wells, algorithm='optimizing')
print(fit_3, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + arsenic
 observations: 3020
 predictors:   3
------
            Median MAD_SD
(Intercept)  0.01   0.08 
dist100     -0.90   0.11 
arsenic      0.46   0.04 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_3, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + arsenic
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   3

Estimates:
              Median   MAD_SD   10%   50%   90%
(Intercept)  0.01     0.08    -0.10  0.01  0.10
dist100     -0.90     0.11    -1.03 -0.90 -0.76
arsenic      0.46     0.04     0.41  0.46  0.51

Monte Carlo diagnostics
            mcse khat n_eff
(Intercept) 0.00 0.24 704  
dist100     0.00 0.14 762  
arsenic     0.00 0.20 765  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo3 <- loo(fit_3, save_psis = TRUE))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1968.4 15.6
p_loo         3.1  0.1
looic      3936.7 31.3
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo2, loo3)
      elpd_diff se_diff
fit_3   0.0       0.0  
fit_2 -71.9      12.1  

Average improvement in LOO predictive probabilities

from dist100 to dist100 + arsenic

pred2 <- loo_predict(fit_2, psis_object = loo2$psis_object)$value
pred3 <- loo_predict(fit_3, psis_object = loo3$psis_object)$value
round(mean(c(pred3[wells$y==1]-pred2[wells$y==1],pred2[wells$y==0]-pred3[wells$y==0])),3)
[1] 0.022

Plot model fits

plot(c(0,max(wells$dist,na.rm=T)*1.02), c(0,1),
     xlab="Distance (in meters) to nearest safe well", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
points(wells$dist, jitter_binary(wells$y), pch=20, cex=.1)
curve(invlogit(coef(fit_3)[1]+coef(fit_3)[2]*x/100+coef(fit_3)[3]*.50), lwd=.5, add=T)
curve(invlogit(coef(fit_3)[1]+coef(fit_3)[2]*x/100+coef(fit_3)[3]*1.00), lwd=.5, add=T)
text(50, .27, "if As = 0.5", adj=0, cex=.8)
text(75, .50, "if As = 1.0", adj=0, cex=.8)

plot(c(0,max(wells$arsenic,na.rm=T)*1.02), c(0,1),
     xlab="Arsenic concentration in well water", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
points(wells$arsenic, jitter_binary(wells$y), pch=20, cex=.1)
curve(invlogit(coef(fit_3)[1]+coef(fit_3)[2]*0+coef(fit_3)[3]*x), from=0.5, lwd=.5, add=T)
curve(invlogit(coef(fit_3)[1]+coef(fit_3)[2]*0.5+coef(fit_3)[3]*x), from=0.5, lwd=.5, add=T)
text(.5, .78, "if dist = 0", adj=0, cex=.8)
text(2, .6, "if dist = 50", adj=0, cex=.8)

Interaction

Fit a model using scaled distance, arsenic level, and an interaction

fit_4 <- stan_glm(y ~ dist100 + arsenic + dist100:arsenic,
                  family = binomial(link="logit"), data = wells, algorithm='optimizing')
print(fit_4, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + arsenic + dist100:arsenic
 observations: 3020
 predictors:   4
------
                Median MAD_SD
(Intercept)     -0.14   0.12 
dist100         -0.59   0.21 
arsenic          0.56   0.07 
dist100:arsenic -0.17   0.10 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_4, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + arsenic + dist100:arsenic
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   4

Estimates:
                  Median   MAD_SD   10%   50%   90%
(Intercept)     -0.14     0.12    -0.28 -0.14  0.01
dist100         -0.59     0.21    -0.86 -0.59 -0.31
arsenic          0.56     0.07     0.47  0.56  0.65
dist100:arsenic -0.17     0.10    -0.31 -0.17 -0.06

Monte Carlo diagnostics
                mcse khat n_eff
(Intercept)     0.00 0.22 762  
dist100         0.01 0.39 745  
arsenic         0.00 0.20 778  
dist100:arsenic 0.00 0.28 762  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo4 <- loo(fit_4))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1968.1 15.9
p_loo         4.5  0.3
looic      3936.2 31.8
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo3, loo4)
      elpd_diff se_diff
fit_4  0.0       0.0   
fit_3 -0.2       1.9   

Centering the input variables

wells$c_dist100 <- wells$dist100 - mean(wells$dist100)
wells$c_arsenic <- wells$arsenic - mean(wells$arsenic)
fit_5 <- stan_glm(y ~ c_dist100 + c_arsenic + c_dist100:c_arsenic,
                  family = binomial(link="logit"), data = wells, algorithm='optimizing')
print(fit_5, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ c_dist100 + c_arsenic + c_dist100:c_arsenic
 observations: 3020
 predictors:   4
------
                    Median MAD_SD
(Intercept)          0.35   0.04 
c_dist100           -0.88   0.10 
c_arsenic            0.47   0.04 
c_dist100:c_arsenic -0.17   0.10 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_5, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ c_dist100 + c_arsenic + c_dist100:c_arsenic
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   4

Estimates:
                      Median   MAD_SD   10%   50%   90%
(Intercept)          0.35     0.04     0.30  0.35  0.40
c_dist100           -0.88     0.10    -1.01 -0.88 -0.75
c_arsenic            0.47     0.04     0.42  0.47  0.52
c_dist100:c_arsenic -0.17     0.10    -0.31 -0.17 -0.04

Monte Carlo diagnostics
                    mcse khat n_eff
(Intercept)         0.00 0.26 776  
c_dist100           0.00 0.19 818  
c_arsenic           0.00 0.21 785  
c_dist100:c_arsenic 0.00 0.20 779  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

Plot model fits

plot(c(0,max(wells$dist,na.rm=T)*1.02), c(0,1),
     xlab="Distance (in meters) to nearest safe well", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
points(wells$dist, jitter_binary(wells$y), pch=20, cex=.1)
curve(invlogit(coef(fit_4)[1]+coef(fit_4)[2]*x/100+coef(fit_4)[3]*.50+coef(fit_4)[4]*x/100*.50), lwd=.5, add=T)
curve(invlogit(coef(fit_4)[1]+coef(fit_4)[2]*x/100+coef(fit_4)[3]*1.00+coef(fit_4)[4]*x/100*1.00), lwd=.5, add=T)
text (50, .29, "if As = 0.5", adj=0, cex=.8)
text (75, .50, "if As = 1.0", adj=0, cex=.8)

plot(c(0,max(wells$arsenic,na.rm=T)*1.02), c(0,1),
     xlab="Arsenic concentration in well water", ylab="Pr (switching)",
     type="n", xaxs="i", yaxs="i", mgp=c(2,.5,0))
points(wells$arsenic, jitter_binary(wells$y), pch=20, cex=.1)
curve(invlogit(coef(fit_4)[1]+coef(fit_4)[2]*0+coef(fit_4)[3]*x+coef(fit_4)[4]*0*x), from=0.5, lwd=.5, add=T)
curve(invlogit(coef(fit_4)[1]+coef(fit_4)[2]*0.5+coef(fit_4)[3]*x+coef(fit_4)[4]*0.5*x), from=0.5, lwd=.5, add=T)
text (.5, .78, "if dist = 0", adj=0, cex=.8)
text (2, .6, "if dist = 50", adj=0, cex=.8)

More predictors

Adding social predictors

fit_6 <- stan_glm(y ~ dist100 + arsenic + educ4 + assoc,
                  family = binomial(link="logit"), data = wells, algorithm='optimizing')
print(fit_6, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + arsenic + educ4 + assoc
 observations: 3020
 predictors:   5
------
            Median MAD_SD
(Intercept) -0.16   0.11 
dist100     -0.90   0.10 
arsenic      0.47   0.04 
educ4        0.17   0.04 
assoc       -0.13   0.07 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_6, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + arsenic + educ4 + assoc
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   5

Estimates:
              Median   MAD_SD   10%   50%   90%
(Intercept) -0.16     0.11    -0.29 -0.16 -0.03
dist100     -0.90     0.10    -1.03 -0.90 -0.77
arsenic      0.47     0.04     0.42  0.47  0.52
educ4        0.17     0.04     0.12  0.17  0.22
assoc       -0.13     0.07    -0.22 -0.13 -0.03

Monte Carlo diagnostics
            mcse khat n_eff
(Intercept) 0.00 0.26 719  
dist100     0.00 0.28 732  
arsenic     0.00 0.27 738  
educ4       0.00 0.25 734  
assoc       0.00 0.26 722  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo6 <- loo(fit_6))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1959.0 16.1
p_loo         5.2  0.1
looic      3918.0 32.3
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo4, loo6)
      elpd_diff se_diff
fit_6  0.0       0.0   
fit_4 -9.1       5.1   

Remove assoc

fit_7 <- stan_glm(y ~ dist100 + arsenic + educ4,
                  family = binomial(link="logit"), data = wells, algorithm='optimizing')
print(fit_7, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + arsenic + educ4
 observations: 3020
 predictors:   4
------
            Median MAD_SD
(Intercept) -0.21   0.09 
dist100     -0.90   0.10 
arsenic      0.47   0.04 
educ4        0.17   0.04 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_7, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + arsenic + educ4
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   4

Estimates:
              Median   MAD_SD   10%   50%   90%
(Intercept) -0.21     0.09    -0.33 -0.21 -0.09
dist100     -0.90     0.10    -1.02 -0.90 -0.76
arsenic      0.47     0.04     0.42  0.47  0.52
educ4        0.17     0.04     0.12  0.17  0.22

Monte Carlo diagnostics
            mcse khat n_eff
(Intercept) 0.00 0.31 775  
dist100     0.00 0.27 768  
arsenic     0.00 0.40 790  
educ4       0.00 0.36 790  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo7 <- loo(fit_7))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1959.4 16.0
p_loo         4.2  0.1
looic      3918.7 32.0
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo4, loo7)
      elpd_diff se_diff
fit_7  0.0       0.0   
fit_4 -8.7       4.8   
loo_compare(loo6, loo7)
      elpd_diff se_diff
fit_6  0.0       0.0   
fit_7 -0.4       1.6   

Add interactions with education

wells$c_educ4 <- wells$educ4 - mean(wells$educ4)
fit_8 <- stan_glm(y ~ c_dist100 + c_arsenic + c_educ4 +
                      c_dist100:c_educ4 + c_arsenic:c_educ4,
                  family = binomial(link="logit"), data = wells, algorithm='optimizing')
print(fit_8, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ c_dist100 + c_arsenic + c_educ4 + c_dist100:c_educ4 + c_arsenic:c_educ4
 observations: 3020
 predictors:   6
------
                  Median MAD_SD
(Intercept)        0.35   0.04 
c_dist100         -0.92   0.11 
c_arsenic          0.49   0.04 
c_educ4            0.19   0.04 
c_dist100:c_educ4  0.33   0.11 
c_arsenic:c_educ4  0.08   0.04 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_8, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ c_dist100 + c_arsenic + c_educ4 + c_dist100:c_educ4 + c_arsenic:c_educ4
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   6

Estimates:
                    Median   MAD_SD   10%   50%   90%
(Intercept)        0.35     0.04     0.29  0.35  0.40
c_dist100         -0.92     0.11    -1.06 -0.92 -0.78
c_arsenic          0.49     0.04     0.44  0.49  0.54
c_educ4            0.19     0.04     0.14  0.19  0.24
c_dist100:c_educ4  0.33     0.11     0.20  0.33  0.48
c_arsenic:c_educ4  0.08     0.04     0.02  0.08  0.13

Monte Carlo diagnostics
                  mcse khat n_eff
(Intercept)       0.00 0.37 726  
c_dist100         0.00 0.54 689  
c_arsenic         0.00 0.40 743  
c_educ4           0.00 0.52 780  
c_dist100:c_educ4 0.00 0.36 714  
c_arsenic:c_educ4 0.00 0.44 732  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo8 <- loo(fit_8, save_psis=TRUE))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1952.8 16.5
p_loo         6.5  0.3
looic      3905.7 33.0
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo3, loo8)
      elpd_diff se_diff
fit_8   0.0       0.0  
fit_3 -15.5       6.3  
loo_compare(loo7, loo8)
      elpd_diff se_diff
fit_8  0.0       0.0   
fit_7 -6.5       4.3   

Average improvement in LOO predictive probabilities

from dist100 + arsenic to dist100 + arsenic + educ4 + dist100:educ4 + arsenic:educ4

pred8 <- loo_predict(fit_8, psis_object = loo8$psis_object)$value
round(mean(c(pred8[wells$y==1]-pred3[wells$y==1],pred3[wells$y==0]-pred8[wells$y==0])),3)
[1] 0.005

Transformation of variable

Fit a model using scaled distance and log arsenic level

wells$log_arsenic <- log(wells$arsenic)
fit_3a <- stan_glm(y ~ dist100 + log_arsenic, family = binomial(link = "logit"),
                   data = wells, algorithm='optimizing')
print(fit_3a, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + log_arsenic
 observations: 3020
 predictors:   3
------
            Median MAD_SD
(Intercept)  0.52   0.06 
dist100     -0.97   0.10 
log_arsenic  0.88   0.07 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_3a, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + log_arsenic
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   3

Estimates:
              Median   MAD_SD   10%   50%   90%
(Intercept)  0.52     0.06     0.45  0.52  0.61
dist100     -0.97     0.10    -1.12 -0.97 -0.85
log_arsenic  0.88     0.07     0.79  0.88  0.97

Monte Carlo diagnostics
            mcse khat n_eff
(Intercept) 0.00 0.02 782  
dist100     0.00 0.07 801  
log_arsenic 0.00 0.01 779  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo3a <- loo(fit_3a))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1952.3 16.3
p_loo         3.1  0.1
looic      3904.6 32.7
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo3, loo3a)
       elpd_diff se_diff
fit_3a   0.0       0.0  
fit_3  -16.1       4.4  

Fit a model using scaled distance, log arsenic level, and an interaction

fit_4a <- stan_glm(y ~ dist100 + log_arsenic + dist100:log_arsenic,
                  family = binomial(link = "logit"), data = wells, algorithm='optimizing')
print(fit_4a, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + log_arsenic + dist100:log_arsenic
 observations: 3020
 predictors:   4
------
                    Median MAD_SD
(Intercept)          0.49   0.07 
dist100             -0.87   0.13 
log_arsenic          0.98   0.10 
dist100:log_arsenic -0.23   0.17 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_4a, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ dist100 + log_arsenic + dist100:log_arsenic
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   4

Estimates:
                      Median   MAD_SD   10%   50%   90%
(Intercept)          0.49     0.07     0.41  0.49  0.58
dist100             -0.87     0.13    -1.06 -0.87 -0.70
log_arsenic          0.98     0.10     0.85  0.98  1.12
dist100:log_arsenic -0.23     0.17    -0.46 -0.23  0.00

Monte Carlo diagnostics
                    mcse khat n_eff
(Intercept)         0.00 0.29 758  
dist100             0.00 0.27 767  
log_arsenic         0.00 0.21 714  
dist100:log_arsenic 0.01 0.28 750  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo4a <- loo(fit_4a))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1952.5 16.4
p_loo         4.1  0.1
looic      3904.9 32.8
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo3a, loo4a)
       elpd_diff se_diff
fit_3a  0.0       0.0   
fit_4a -0.2       1.2   

Add interactions with education

wells$c_log_arsenic <- wells$log_arsenic - mean(wells$log_arsenic)
fit_8a <- stan_glm(y ~ c_dist100 + c_log_arsenic + c_educ4 +
                      c_dist100:c_educ4 + c_log_arsenic:c_educ4,
                  family = binomial(link="logit"), data = wells, algorithm='optimizing')
print(fit_8a, digits=2)
stan_glm
 family:       binomial [logit]
 formula:      y ~ c_dist100 + c_log_arsenic + c_educ4 + c_dist100:c_educ4 + 
       c_log_arsenic:c_educ4
 observations: 3020
 predictors:   6
------
                      Median MAD_SD
(Intercept)            0.34   0.04 
c_dist100             -1.01   0.11 
c_log_arsenic          0.91   0.07 
c_educ4                0.18   0.04 
c_dist100:c_educ4      0.35   0.11 
c_log_arsenic:c_educ4  0.07   0.07 

------
* For help interpreting the printed output see ?print.stanreg
* For info on the priors used see ?prior_summary.stanreg
summary(fit_8a, digits=2)

Model Info:
 function:     stan_glm
 family:       binomial [logit]
 formula:      y ~ c_dist100 + c_log_arsenic + c_educ4 + c_dist100:c_educ4 + 
       c_log_arsenic:c_educ4
 algorithm:    optimizing
 priors:       see help('prior_summary')
 observations: 3020
 predictors:   6

Estimates:
                        Median   MAD_SD   10%   50%   90%
(Intercept)            0.34     0.04     0.28  0.34  0.38
c_dist100             -1.01     0.11    -1.15 -1.01 -0.88
c_log_arsenic          0.91     0.07     0.82  0.91  1.00
c_educ4                0.18     0.04     0.13  0.18  0.23
c_dist100:c_educ4      0.35     0.11     0.20  0.35  0.49
c_log_arsenic:c_educ4  0.07     0.07    -0.03  0.07  0.15

Monte Carlo diagnostics
                      mcse khat n_eff
(Intercept)           0.00 0.31 700  
c_dist100             0.00 0.29 758  
c_log_arsenic         0.00 0.26 717  
c_educ4               0.00 0.31 736  
c_dist100:c_educ4     0.00 0.30 705  
c_log_arsenic:c_educ4 0.00 0.25 765  

For each parameter, mcse is Monte Carlo standard error, n_eff is a crude measure of effective sample size, and khat is the Pareto k diagnostic for importance sampling (perfomance is usually good when khat < 0.7).

LOO log score

(loo8a <- loo(fit_8a, save_psis=TRUE))

Computed from 1000 by 3020 log-likelihood matrix

         Estimate   SE
elpd_loo  -1938.0 17.2
p_loo         6.2  0.2
looic      3876.1 34.3
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Compare models

loo_compare(loo8, loo8a)
       elpd_diff se_diff
fit_8a   0.0       0.0  
fit_8  -14.8       4.3  
LS0tCnRpdGxlOiAiUmVncmVzc2lvbiBhbmQgT3RoZXIgU3RvcmllczogQXJzZW5pYyIKYXV0aG9yOiAiQW5kcmV3IEdlbG1hbiwgSmVubmlmZXIgSGlsbCwgQWtpIFZlaHRhcmkiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSlgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDIKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KQnVpbGRpbmcgYSBsb2dpc3RpYyByZWdyZXNzaW9uIG1vZGVsOiB3ZWxscyBpbiBCYW5nbGFkZXNoLiBTZWUKQ2hhcHRlciAxMyBpbiBSZWdyZXNzaW9uIGFuZCBPdGhlciBTdG9yaWVzLgoKVGhpcyB2ZXJzaW9uIHVzZXMgYWxnb3JpdGhtPSdvcHRpbWl6aW5nJywgd2hpY2ggZmluZHMgdGhlIHBvc3Rlcmlvcgptb2RlLCBjb21wdXRlcyBIZXNzaWFuIGFuZCB1c2VzIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBhcHByb3hpbWF0aW9uCm9mIHRoZSBwb3N0ZXJpb3IuIFRoaXMgY2FuIHdvcmsgd2VsbCBmb3Igbm9uLWhpZXJhcmNoaWNhbApnZW5lcmFsaXplZCBsaW5lYXIgbW9kZWxzIHdoZW4gdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaXMgbXVjaApoaWdoZXIgdGhhbiB0aGUgbnVtYmVyIG9mIGNvdmFyaWF0ZXMuCgotLS0tLS0tLS0tLS0tCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRSwgd2FybmluZz1GQUxTRSwgY29tbWVudD1OQSkKIyBzd2l0Y2ggdGhpcyB0byBUUlVFIHRvIHNhdmUgZmlndXJlcyBpbiBzZXBhcmF0ZSBmaWxlcwpzYXZlZmlncyA8LSBGQUxTRQpgYGAKCiMjIyMgTG9hZCBwYWNrYWdlcwoKYGBge3IgfQpsaWJyYXJ5KCJycHJvanJvb3QiKQpyb290PC1oYXNfZmlsZSgiLlJPUy1FeGFtcGxlcy1yb290IikkbWFrZV9maXhfZmlsZSgpCmxpYnJhcnkoInJzdGFuYXJtIikKbGlicmFyeSgibG9vIikKaW52bG9naXQgPC0gcGxvZ2lzCmBgYAoKIyMjIyBMb2FkIGRhdGEKCmBgYHtyIH0Kd2VsbHMgPC0gcmVhZC5jc3Yocm9vdCgiQXJzZW5pYy9kYXRhIiwid2VsbHMuY3N2IikpCndlbGxzJHkgPC0gd2VsbHMkc3dpdGNoCm4gPC0gbnJvdyh3ZWxscykKYGBgCgojIyBOdWxsIG1vZGVsCgojIyMjIExvZy1zY29yZSBmb3IgY29pbiBmbGlwcGluZwoKYGBge3IgfQpwcm9iIDwtIDAuNQpyb3VuZChsb2cocHJvYikqc3VtKHdlbGxzJHkpICsgbG9nKDEtcHJvYikqc3VtKDEtd2VsbHMkeSksMSkKYGBgCgojIyMjIExvZy1zY29yZSBmb3IgaW50ZXJjZXB0IG1vZGVsCgpgYGB7ciB9CnJvdW5kKHByb2IgPC0gbWVhbih3ZWxscyR5KSwyKQpyb3VuZChsb2cocHJvYikqc3VtKHdlbGxzJHkpICsgbG9nKDEtcHJvYikqc3VtKDEtd2VsbHMkeSksMSkKYGBgCgojIyBBIHNpbmdsZSBwcmVkaWN0b3IKCiMjIyMgRml0IGEgbW9kZWwgdXNpbmcgZGlzdGFuY2UgdG8gdGhlIG5lYXJlc3Qgc2FmZSB3ZWxsCgpgYGB7ciByZXN1bHRzPSdoaWRlJ30KZml0XzEgPC0gc3Rhbl9nbG0oeSB+IGRpc3QsIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YT13ZWxscywgYWxnb3JpdGhtPSdvcHRpbWl6aW5nJykKYGBgCgoKCmBgYHtyIH0KcHJpbnQoZml0XzEsIGRpZ2l0cz0zKQpzdW1tYXJ5KGZpdF8xLCBkaWdpdHM9MykKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzEgPC0gbG9vKGZpdF8xKSkKYGBgCgojIyMjIEhpc3RvZ3JhbSBvZiBkaXN0YW5jZXMKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcG9zdHNjcmlwdChyb290KCJBcnNlbmljL2ZpZ3MiLCJhcnNlbmljLmRpc3RhbmNlcy5ibmV3LnBzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQ9Mywgd2lkdGg9NCwgaG9yaXpvbnRhbD1UUlVFKQpgYGAKYGBge3IgfQpoaXN0KHdlbGxzJGRpc3QsIGJyZWFrcz1zZXEoMCwxMCttYXgod2VsbHMkZGlzdCksMTApLCBmcmVxPVRSVUUsCiAgICAgeGxhYj0iRGlzdGFuY2UgKGluIG1ldGVycykgdG8gbmVhcmVzdCBzYWZlIHdlbGwiLCB5bGFiPSIiLCBtYWluPSIiLCBtZ3A9YygyLC41LDApKQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBkZXYub2ZmKCkKYGBgCgojIyMjIFNjYWxlIGRpc3RhbmNlIGluIG1ldGVycyB0byBkaXN0YW5jZSBpbiAxMDAgbWV0ZXJzCgpgYGB7ciB9CndlbGxzJGRpc3QxMDAgPC0gd2VsbHMkZGlzdC8xMDAKYGBgCgojIyMjIEZpdCBhIG1vZGVsIHVzaW5nIHNjYWxlZCBkaXN0YW5jZSB0byB0aGUgbmVhcmVzdCBzYWZlIHdlbGwKCmBgYHtyIHJlc3VsdHM9J2hpZGUnfQpmaXRfMiA8LSBzdGFuX2dsbSh5IH4gZGlzdDEwMCwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCBkYXRhPXdlbGxzLCBhbGdvcml0aG09J29wdGltaXppbmcnKQpgYGAKCgoKYGBge3IgfQpwcmludChmaXRfMiwgZGlnaXRzPTIpCnN1bW1hcnkoZml0XzIsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgTE9PIGxvZyBzY29yZQoKYGBge3IgfQoobG9vMiA8LSBsb28oZml0XzIsIHNhdmVfcHNpcyA9IFRSVUUpKQpgYGAKCiMjIyMgUGxvdCBtb2RlbCBmaXQKCmBgYHtyIH0Kaml0dGVyX2JpbmFyeSA8LSBmdW5jdGlvbihhLCBqaXR0PS4wNSl7CiAgYSArICgxLTIqYSkqcnVuaWYobGVuZ3RoKGEpLDAsaml0dCkKfQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBwb3N0c2NyaXB0KHJvb3QoIkFyc2VuaWMvZmlncyIsImFyc2VuaWMubG9naXRmaXQuMW5ldy5hLnBzIiksCiAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQ9My41LCB3aWR0aD00LCBob3Jpem9udGFsPVRSVUUpCmBgYApgYGB7ciB9CnBsb3QoYygwLG1heCh3ZWxscyRkaXN0LCBuYS5ybT1UUlVFKSoxLjAyKSwgYygwLDEpLAogICAgIHhsYWI9IkRpc3RhbmNlIChpbiBtZXRlcnMpIHRvIG5lYXJlc3Qgc2FmZSB3ZWxsIiwgeWxhYj0iUHIgKHN3aXRjaGluZykiLAogICAgIHR5cGU9Im4iLCB4YXhzPSJpIiwgeWF4cz0iaSIsIG1ncD1jKDIsLjUsMCkpCmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzEpWzFdK2NvZWYoZml0XzEpWzJdKngpLCBsd2Q9MSwgYWRkPVRSVUUpCnBvaW50cyh3ZWxscyRkaXN0LCBqaXR0ZXJfYmluYXJ5KHdlbGxzJHkpLCBwY2g9MjAsIGNleD0uMSkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZGV2Lm9mZigpCmBgYAoKIyMjIyBQbG90IHVuY2VydGFpbnR5IGluIHRoZSBlc3RpbWF0ZWQgY29lZmZpY2llbnRzCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIHBvc3RzY3JpcHQocm9vdCgiQXJzZW5pYy9maWdzIiwiYXJzZW5pYy5sb2dpdGZpdC5zY2F0dGVycGxvdC5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMuNSwgd2lkdGg9My41LCBob3Jpem9udGFsPVRSVUUpCmBgYApgYGB7ciB9CnNpbXMgPC0gYXMubWF0cml4KGZpdF8yKQpwYXIocHR5PSJzIikKcGxvdChzaW1zWzE6NTAwLDFdLCBzaW1zWzE6NTAwLDJdLCB4bGltPWMoLjQsLjgpLCB5bGltPWMoLTEsMCksCiAgICAgeGxhYj1leHByZXNzaW9uKGJldGFbMF0pLCB5bGFiPWV4cHJlc3Npb24oYmV0YVsxXSksIG1ncD1jKDEuNSwuNSwwKSwKICAgICBwY2g9MjAsIGNleD0uNSwgeGF4dD0ibiIsIHlheHQ9Im4iKQpheGlzKDEsIHNlcSguNCwuOCwuMiksIG1ncD1jKDEuNSwuNSwwKSkKYXhpcygyLCBzZXEoLTEsMCwuNSksIG1ncD1jKDEuNSwuNSwwKSkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZGV2Lm9mZigpCmBgYAoKIyMjIyBQbG90IHVuY2VydGFpbnR5IGluIHRoZSBlc3RpbWF0ZWQgcHJlZGljdGlvbnMKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgcG9zdHNjcmlwdChyb290KCJBcnNlbmljL2ZpZ3MiLCJhcnNlbmljLmxvZ2l0Zml0LjFuZXcuYi5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMuNSwgd2lkdGg9NCwgaG9yaXpvbnRhbD1UUlVFKQpgYGAKYGBge3IgfQpwbG90KGMoMCxtYXgod2VsbHMkZGlzdCwgbmEucm09VCkqMS4wMiksIGMoMCwxKSwKICAgICB4bGFiPSJEaXN0YW5jZSAoaW4gbWV0ZXJzKSB0byBuZWFyZXN0IHNhZmUgd2VsbCIsIHlsYWI9IlByIChzd2l0Y2hpbmcpIiwKICAgICB0eXBlPSJuIiwgeGF4cz0iaSIsIHlheHM9ImkiLCBtZ3A9YygyLC41LDApKQpmb3IgKGogaW4gMToyMCkgewogICAgY3VydmUgKGludmxvZ2l0KHNpbXNbaiwxXStzaW1zW2osMl0qeC8xMDApLCBsd2Q9LjUsCiAgICAgICAgICAgY29sPSJkYXJrZ3JheSIsIGFkZD1UUlVFKQp9CmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzIpWzFdK2NvZWYoZml0XzIpWzJdKngvMTAwKSwgbHdkPTEsIGFkZD1UKQpwb2ludHMod2VsbHMkZGlzdCwgaml0dGVyX2JpbmFyeSh3ZWxscyR5KSwgcGNoPTIwLCBjZXg9LjEpCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIGRldi5vZmYoKQpgYGAKCiMjIFR3byBwcmVkaWN0b3JzCgojIyMjIEhpc3RvZ3JhbSBvZiBhcnNlbmljIGxldmVscwoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBwb3N0c2NyaXB0KHJvb3QoIkFyc2VuaWMvZmlncyIsImFyc2VuaWMubGV2ZWxzLmEucHMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodD0zLCB3aWR0aD00LCBob3Jpem9udGFsPVRSVUUpCmBgYApgYGB7ciB9Cmhpc3Qod2VsbHMkYXJzZW5pYywgYnJlYWtzPXNlcSgwLC4yNSttYXgod2VsbHMkYXJzZW5pYyksLjI1KSwgZnJlcT1UUlVFLAogICAgIHhsYWI9IkFyc2VuaWMgY29uY2VudHJhdGlvbiBpbiB3ZWxsIHdhdGVyIiwgeWxhYj0iIiwgbWFpbj0iIiwgbWdwPWMoMiwuNSwwKSkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZGV2Lm9mZigpCmBgYAoKIyMjIyBGaXQgYSBtb2RlbCB1c2luZyBzY2FsZWQgZGlzdGFuY2UgYW5kIGFyc2VuaWMgbGV2ZWwKCmBgYHtyIHJlc3VsdHM9J2hpZGUnfQpmaXRfMyA8LSBzdGFuX2dsbSh5IH4gZGlzdDEwMCArIGFyc2VuaWMsIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwKICAgICAgICAgICAgICAgICAgZGF0YT13ZWxscywgYWxnb3JpdGhtPSdvcHRpbWl6aW5nJykKYGBgCgoKCmBgYHtyIH0KcHJpbnQoZml0XzMsIGRpZ2l0cz0yKQpzdW1tYXJ5KGZpdF8zLCBkaWdpdHM9MikKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzMgPC0gbG9vKGZpdF8zLCBzYXZlX3BzaXMgPSBUUlVFKSkKYGBgCgojIyMjIENvbXBhcmUgbW9kZWxzCgpgYGB7ciB9Cmxvb19jb21wYXJlKGxvbzIsIGxvbzMpCmBgYAoKIyMjIyBBdmVyYWdlIGltcHJvdmVtZW50IGluIExPTyBwcmVkaWN0aXZlIHByb2JhYmlsaXRpZXM8YnI+CmZyb20gZGlzdDEwMCB0byBkaXN0MTAwICsgYXJzZW5pYwoKYGBge3IgfQpwcmVkMiA8LSBsb29fcHJlZGljdChmaXRfMiwgcHNpc19vYmplY3QgPSBsb28yJHBzaXNfb2JqZWN0KSR2YWx1ZQpwcmVkMyA8LSBsb29fcHJlZGljdChmaXRfMywgcHNpc19vYmplY3QgPSBsb28zJHBzaXNfb2JqZWN0KSR2YWx1ZQpyb3VuZChtZWFuKGMocHJlZDNbd2VsbHMkeT09MV0tcHJlZDJbd2VsbHMkeT09MV0scHJlZDJbd2VsbHMkeT09MF0tcHJlZDNbd2VsbHMkeT09MF0pKSwzKQpgYGAKCiMjIyMgUGxvdCBtb2RlbCBmaXRzCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIHBvc3RzY3JpcHQocm9vdCgiQXJzZW5pYy9maWdzIiwiYXJzZW5pYy4ydmFyaWFibGVzLmEucHMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodD0zLjUsIHdpZHRoPTQsIGhvcml6b250YWw9VFJVRSkKYGBgCmBgYHtyIH0KcGxvdChjKDAsbWF4KHdlbGxzJGRpc3QsbmEucm09VCkqMS4wMiksIGMoMCwxKSwKICAgICB4bGFiPSJEaXN0YW5jZSAoaW4gbWV0ZXJzKSB0byBuZWFyZXN0IHNhZmUgd2VsbCIsIHlsYWI9IlByIChzd2l0Y2hpbmcpIiwKICAgICB0eXBlPSJuIiwgeGF4cz0iaSIsIHlheHM9ImkiLCBtZ3A9YygyLC41LDApKQpwb2ludHMod2VsbHMkZGlzdCwgaml0dGVyX2JpbmFyeSh3ZWxscyR5KSwgcGNoPTIwLCBjZXg9LjEpCmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzMpWzFdK2NvZWYoZml0XzMpWzJdKngvMTAwK2NvZWYoZml0XzMpWzNdKi41MCksIGx3ZD0uNSwgYWRkPVQpCmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzMpWzFdK2NvZWYoZml0XzMpWzJdKngvMTAwK2NvZWYoZml0XzMpWzNdKjEuMDApLCBsd2Q9LjUsIGFkZD1UKQp0ZXh0KDUwLCAuMjcsICJpZiBBcyA9IDAuNSIsIGFkaj0wLCBjZXg9LjgpCnRleHQoNzUsIC41MCwgImlmIEFzID0gMS4wIiwgYWRqPTAsIGNleD0uOCkKYGBgCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmlmIChzYXZlZmlncykgZGV2Lm9mZigpCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIHBvc3RzY3JpcHQocm9vdCgiQXJzZW5pYy9maWdzIiwiYXJzZW5pYy4ydmFyaWFibGVzLmIucHMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodD0zLjUsIHdpZHRoPTQsIGhvcml6b250YWw9VFJVRSkKYGBgCmBgYHtyIH0KcGxvdChjKDAsbWF4KHdlbGxzJGFyc2VuaWMsbmEucm09VCkqMS4wMiksIGMoMCwxKSwKICAgICB4bGFiPSJBcnNlbmljIGNvbmNlbnRyYXRpb24gaW4gd2VsbCB3YXRlciIsIHlsYWI9IlByIChzd2l0Y2hpbmcpIiwKICAgICB0eXBlPSJuIiwgeGF4cz0iaSIsIHlheHM9ImkiLCBtZ3A9YygyLC41LDApKQpwb2ludHMod2VsbHMkYXJzZW5pYywgaml0dGVyX2JpbmFyeSh3ZWxscyR5KSwgcGNoPTIwLCBjZXg9LjEpCmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzMpWzFdK2NvZWYoZml0XzMpWzJdKjArY29lZihmaXRfMylbM10qeCksIGZyb209MC41LCBsd2Q9LjUsIGFkZD1UKQpjdXJ2ZShpbnZsb2dpdChjb2VmKGZpdF8zKVsxXStjb2VmKGZpdF8zKVsyXSowLjUrY29lZihmaXRfMylbM10qeCksIGZyb209MC41LCBsd2Q9LjUsIGFkZD1UKQp0ZXh0KC41LCAuNzgsICJpZiBkaXN0ID0gMCIsIGFkaj0wLCBjZXg9LjgpCnRleHQoMiwgLjYsICJpZiBkaXN0ID0gNTAiLCBhZGo9MCwgY2V4PS44KQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBkZXYub2ZmKCkKYGBgCgojIyBJbnRlcmFjdGlvbgoKIyMjIyBGaXQgYSBtb2RlbCB1c2luZyBzY2FsZWQgZGlzdGFuY2UsIGFyc2VuaWMgbGV2ZWwsIGFuZCBhbiBpbnRlcmFjdGlvbgoKYGBge3IgcmVzdWx0cz0naGlkZSd9CmZpdF80IDwtIHN0YW5fZ2xtKHkgfiBkaXN0MTAwICsgYXJzZW5pYyArIGRpc3QxMDA6YXJzZW5pYywKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluaz0ibG9naXQiKSwgZGF0YSA9IHdlbGxzLCBhbGdvcml0aG09J29wdGltaXppbmcnKQpgYGAKCgoKYGBge3IgfQpwcmludChmaXRfNCwgZGlnaXRzPTIpCnN1bW1hcnkoZml0XzQsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgTE9PIGxvZyBzY29yZQoKYGBge3IgfQoobG9vNCA8LSBsb28oZml0XzQpKQpgYGAKCiMjIyMgQ29tcGFyZSBtb2RlbHMKCmBgYHtyIH0KbG9vX2NvbXBhcmUobG9vMywgbG9vNCkKYGBgCgojIyMjIENlbnRlcmluZyB0aGUgaW5wdXQgdmFyaWFibGVzCgpgYGB7ciB9CndlbGxzJGNfZGlzdDEwMCA8LSB3ZWxscyRkaXN0MTAwIC0gbWVhbih3ZWxscyRkaXN0MTAwKQp3ZWxscyRjX2Fyc2VuaWMgPC0gd2VsbHMkYXJzZW5pYyAtIG1lYW4od2VsbHMkYXJzZW5pYykKZml0XzUgPC0gc3Rhbl9nbG0oeSB+IGNfZGlzdDEwMCArIGNfYXJzZW5pYyArIGNfZGlzdDEwMDpjX2Fyc2VuaWMsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IiksIGRhdGEgPSB3ZWxscywgYWxnb3JpdGhtPSdvcHRpbWl6aW5nJykKYGBgCgoKCmBgYHtyIH0KcHJpbnQoZml0XzUsIGRpZ2l0cz0yKQpzdW1tYXJ5KGZpdF81LCBkaWdpdHM9MikKYGBgCgojIyMjIFBsb3QgbW9kZWwgZml0cwoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBwb3N0c2NyaXB0KHJvb3QoIkFyc2VuaWMvZmlncyIsImFyc2VuaWMuaW50ZXJhY3QuYS5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMuNSwgd2lkdGg9NCwgaG9yaXpvbnRhbD1UUlVFKQpgYGAKYGBge3IgfQpwbG90KGMoMCxtYXgod2VsbHMkZGlzdCxuYS5ybT1UKSoxLjAyKSwgYygwLDEpLAogICAgIHhsYWI9IkRpc3RhbmNlIChpbiBtZXRlcnMpIHRvIG5lYXJlc3Qgc2FmZSB3ZWxsIiwgeWxhYj0iUHIgKHN3aXRjaGluZykiLAogICAgIHR5cGU9Im4iLCB4YXhzPSJpIiwgeWF4cz0iaSIsIG1ncD1jKDIsLjUsMCkpCnBvaW50cyh3ZWxscyRkaXN0LCBqaXR0ZXJfYmluYXJ5KHdlbGxzJHkpLCBwY2g9MjAsIGNleD0uMSkKY3VydmUoaW52bG9naXQoY29lZihmaXRfNClbMV0rY29lZihmaXRfNClbMl0qeC8xMDArY29lZihmaXRfNClbM10qLjUwK2NvZWYoZml0XzQpWzRdKngvMTAwKi41MCksIGx3ZD0uNSwgYWRkPVQpCmN1cnZlKGludmxvZ2l0KGNvZWYoZml0XzQpWzFdK2NvZWYoZml0XzQpWzJdKngvMTAwK2NvZWYoZml0XzQpWzNdKjEuMDArY29lZihmaXRfNClbNF0qeC8xMDAqMS4wMCksIGx3ZD0uNSwgYWRkPVQpCnRleHQgKDUwLCAuMjksICJpZiBBcyA9IDAuNSIsIGFkaj0wLCBjZXg9LjgpCnRleHQgKDc1LCAuNTAsICJpZiBBcyA9IDEuMCIsIGFkaj0wLCBjZXg9LjgpCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIGRldi5vZmYoKQpgYGAKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KaWYgKHNhdmVmaWdzKSBwb3N0c2NyaXB0KHJvb3QoIkFyc2VuaWMvZmlncyIsImFyc2VuaWMuaW50ZXJhY3QuYi5wcyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PTMuNSwgd2lkdGg9NCwgaG9yaXpvbnRhbD1UUlVFKQpgYGAKYGBge3IgfQpwbG90KGMoMCxtYXgod2VsbHMkYXJzZW5pYyxuYS5ybT1UKSoxLjAyKSwgYygwLDEpLAogICAgIHhsYWI9IkFyc2VuaWMgY29uY2VudHJhdGlvbiBpbiB3ZWxsIHdhdGVyIiwgeWxhYj0iUHIgKHN3aXRjaGluZykiLAogICAgIHR5cGU9Im4iLCB4YXhzPSJpIiwgeWF4cz0iaSIsIG1ncD1jKDIsLjUsMCkpCnBvaW50cyh3ZWxscyRhcnNlbmljLCBqaXR0ZXJfYmluYXJ5KHdlbGxzJHkpLCBwY2g9MjAsIGNleD0uMSkKY3VydmUoaW52bG9naXQoY29lZihmaXRfNClbMV0rY29lZihmaXRfNClbMl0qMCtjb2VmKGZpdF80KVszXSp4K2NvZWYoZml0XzQpWzRdKjAqeCksIGZyb209MC41LCBsd2Q9LjUsIGFkZD1UKQpjdXJ2ZShpbnZsb2dpdChjb2VmKGZpdF80KVsxXStjb2VmKGZpdF80KVsyXSowLjUrY29lZihmaXRfNClbM10qeCtjb2VmKGZpdF80KVs0XSowLjUqeCksIGZyb209MC41LCBsd2Q9LjUsIGFkZD1UKQp0ZXh0ICguNSwgLjc4LCAiaWYgZGlzdCA9IDAiLCBhZGo9MCwgY2V4PS44KQp0ZXh0ICgyLCAuNiwgImlmIGRpc3QgPSA1MCIsIGFkaj0wLCBjZXg9LjgpCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQppZiAoc2F2ZWZpZ3MpIGRldi5vZmYoKQpgYGAKCiMjIE1vcmUgcHJlZGljdG9ycwoKIyMjIyBBZGRpbmcgc29jaWFsIHByZWRpY3RvcnMKCmBgYHtyIHJlc3VsdHM9J2hpZGUnfQpmaXRfNiA8LSBzdGFuX2dsbSh5IH4gZGlzdDEwMCArIGFyc2VuaWMgKyBlZHVjNCArIGFzc29jLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rPSJsb2dpdCIpLCBkYXRhID0gd2VsbHMsIGFsZ29yaXRobT0nb3B0aW1pemluZycpCmBgYAoKCgpgYGB7ciB9CnByaW50KGZpdF82LCBkaWdpdHM9MikKc3VtbWFyeShmaXRfNiwgZGlnaXRzPTIpCmBgYAoKIyMjIyBMT08gbG9nIHNjb3JlCgpgYGB7ciB9Cihsb282IDwtIGxvbyhmaXRfNikpCmBgYAoKIyMjIyBDb21wYXJlIG1vZGVscwoKYGBge3IgfQpsb29fY29tcGFyZShsb280LCBsb282KQpgYGAKCiMjIyMgUmVtb3ZlIGFzc29jCgpgYGB7ciByZXN1bHRzPSdoaWRlJ30KZml0XzcgPC0gc3Rhbl9nbG0oeSB+IGRpc3QxMDAgKyBhcnNlbmljICsgZWR1YzQsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IiksIGRhdGEgPSB3ZWxscywgYWxnb3JpdGhtPSdvcHRpbWl6aW5nJykKYGBgCgoKCmBgYHtyIH0KcHJpbnQoZml0XzcsIGRpZ2l0cz0yKQpzdW1tYXJ5KGZpdF83LCBkaWdpdHM9MikKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzcgPC0gbG9vKGZpdF83KSkKYGBgCgojIyMjIENvbXBhcmUgbW9kZWxzCgpgYGB7ciB9Cmxvb19jb21wYXJlKGxvbzQsIGxvbzcpCmxvb19jb21wYXJlKGxvbzYsIGxvbzcpCmBgYAoKIyMjIyBBZGQgaW50ZXJhY3Rpb25zIHdpdGggZWR1Y2F0aW9uCgpgYGB7ciByZXN1bHRzPSdoaWRlJ30Kd2VsbHMkY19lZHVjNCA8LSB3ZWxscyRlZHVjNCAtIG1lYW4od2VsbHMkZWR1YzQpCmZpdF84IDwtIHN0YW5fZ2xtKHkgfiBjX2Rpc3QxMDAgKyBjX2Fyc2VuaWMgKyBjX2VkdWM0ICsKICAgICAgICAgICAgICAgICAgICAgIGNfZGlzdDEwMDpjX2VkdWM0ICsgY19hcnNlbmljOmNfZWR1YzQsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IiksIGRhdGEgPSB3ZWxscywgYWxnb3JpdGhtPSdvcHRpbWl6aW5nJykKYGBgCgoKCmBgYHtyIH0KcHJpbnQoZml0XzgsIGRpZ2l0cz0yKQpzdW1tYXJ5KGZpdF84LCBkaWdpdHM9MikKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzggPC0gbG9vKGZpdF84LCBzYXZlX3BzaXM9VFJVRSkpCmBgYAoKIyMjIyBDb21wYXJlIG1vZGVscwoKYGBge3IgfQpsb29fY29tcGFyZShsb28zLCBsb284KQpsb29fY29tcGFyZShsb283LCBsb284KQpgYGAKCiMjIyMgQXZlcmFnZSBpbXByb3ZlbWVudCBpbiBMT08gcHJlZGljdGl2ZSBwcm9iYWJpbGl0aWVzPC9icj4KZnJvbSBkaXN0MTAwICsgYXJzZW5pYyB0byBkaXN0MTAwICsgYXJzZW5pYyArIGVkdWM0ICsgZGlzdDEwMDplZHVjNCArIGFyc2VuaWM6ZWR1YzQKCmBgYHtyIH0KcHJlZDggPC0gbG9vX3ByZWRpY3QoZml0XzgsIHBzaXNfb2JqZWN0ID0gbG9vOCRwc2lzX29iamVjdCkkdmFsdWUKcm91bmQobWVhbihjKHByZWQ4W3dlbGxzJHk9PTFdLXByZWQzW3dlbGxzJHk9PTFdLHByZWQzW3dlbGxzJHk9PTBdLXByZWQ4W3dlbGxzJHk9PTBdKSksMykKYGBgCgojIyBUcmFuc2Zvcm1hdGlvbiBvZiB2YXJpYWJsZQoKIyMjIyBGaXQgYSBtb2RlbCB1c2luZyBzY2FsZWQgZGlzdGFuY2UgYW5kIGxvZyBhcnNlbmljIGxldmVsCgpgYGB7ciB9CndlbGxzJGxvZ19hcnNlbmljIDwtIGxvZyh3ZWxscyRhcnNlbmljKQpgYGAKYGBge3IgcmVzdWx0cz0naGlkZSd9CmZpdF8zYSA8LSBzdGFuX2dsbSh5IH4gZGlzdDEwMCArIGxvZ19hcnNlbmljLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksCiAgICAgICAgICAgICAgICAgICBkYXRhID0gd2VsbHMsIGFsZ29yaXRobT0nb3B0aW1pemluZycpCmBgYAoKCgpgYGB7ciB9CnByaW50KGZpdF8zYSwgZGlnaXRzPTIpCnN1bW1hcnkoZml0XzNhLCBkaWdpdHM9MikKYGBgCgojIyMjIExPTyBsb2cgc2NvcmUKCmBgYHtyIH0KKGxvbzNhIDwtIGxvbyhmaXRfM2EpKQpgYGAKCiMjIyMgQ29tcGFyZSBtb2RlbHMKCmBgYHtyIH0KbG9vX2NvbXBhcmUobG9vMywgbG9vM2EpCmBgYAoKIyMjIyBGaXQgYSBtb2RlbCB1c2luZyBzY2FsZWQgZGlzdGFuY2UsIGxvZyBhcnNlbmljIGxldmVsLCBhbmQgYW4gaW50ZXJhY3Rpb248YnI+CgpgYGB7ciByZXN1bHRzPSdoaWRlJ30KZml0XzRhIDwtIHN0YW5fZ2xtKHkgfiBkaXN0MTAwICsgbG9nX2Fyc2VuaWMgKyBkaXN0MTAwOmxvZ19hcnNlbmljLAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIGRhdGEgPSB3ZWxscywgYWxnb3JpdGhtPSdvcHRpbWl6aW5nJykKYGBgCgoKCmBgYHtyIH0KcHJpbnQoZml0XzRhLCBkaWdpdHM9MikKc3VtbWFyeShmaXRfNGEsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgTE9PIGxvZyBzY29yZQoKYGBge3IgfQoobG9vNGEgPC0gbG9vKGZpdF80YSkpCmBgYAoKIyMjIyBDb21wYXJlIG1vZGVscwoKYGBge3IgfQpsb29fY29tcGFyZShsb28zYSwgbG9vNGEpCmBgYAoKIyMjIyBBZGQgaW50ZXJhY3Rpb25zIHdpdGggZWR1Y2F0aW9uCgpgYGB7ciB9CndlbGxzJGNfbG9nX2Fyc2VuaWMgPC0gd2VsbHMkbG9nX2Fyc2VuaWMgLSBtZWFuKHdlbGxzJGxvZ19hcnNlbmljKQpgYGAKYGBge3IgcmVzdWx0cz0naGlkZSd9CmZpdF84YSA8LSBzdGFuX2dsbSh5IH4gY19kaXN0MTAwICsgY19sb2dfYXJzZW5pYyArIGNfZWR1YzQgKwogICAgICAgICAgICAgICAgICAgICAgY19kaXN0MTAwOmNfZWR1YzQgKyBjX2xvZ19hcnNlbmljOmNfZWR1YzQsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IiksIGRhdGEgPSB3ZWxscywgYWxnb3JpdGhtPSdvcHRpbWl6aW5nJykKYGBgCgoKCmBgYHtyIH0KcHJpbnQoZml0XzhhLCBkaWdpdHM9MikKc3VtbWFyeShmaXRfOGEsIGRpZ2l0cz0yKQpgYGAKCiMjIyMgTE9PIGxvZyBzY29yZQoKYGBge3IgfQoobG9vOGEgPC0gbG9vKGZpdF84YSwgc2F2ZV9wc2lzPVRSVUUpKQpgYGAKCiMjIyMgQ29tcGFyZSBtb2RlbHMKCmBgYHtyIH0KbG9vX2NvbXBhcmUobG9vOCwgbG9vOGEpCmBgYAoK