Chapter 6 MCMC
Casal2 MCMC estimation for a single model should be done using “multiple chains”. A chain in this case is a seperate MCMC run, ideally starting from a different set of starting locations and with a different seed number. It is advised to create at least three chains per model. Most of the MCMC diagnostics in this package are designed for multiple chains. These include calculating Rhats (within and between chain variation in parameters) (Vehtari et al. 2021) and effective sample sizes which is a measure of effeciency in your mcmc sampler.
6.1 Read in models
## extra packages
library(purrr)
library(bayesplot)
= system.file("extdata", "multi_chain_mcmc", package = "r4Casal2", mustWork = TRUE)
cas2_file_dir = extract.mcmc(path = cas2_file_dir, samples.file = "samples.4", objectives.file = "objectives.4")
mcmc_1 = extract.mcmc(path = cas2_file_dir, samples.file = "samples.5", objectives.file = "objectives.5")
mcmc_2 = extract.mcmc(path = cas2_file_dir, samples.file = "samples.6", objectives.file = "objectives.6")
mcmc_3 ## assign chain label
$chain = "1"
mcmc_1$chain = "2"
mcmc_2$chain = "3"
mcmc_3## Remove Burnin
= mcmc_1 %>% filter(state == "mcmc")
mcmc_post_1 = mcmc_2 %>% filter(state == "mcmc")
mcmc_post_2 = mcmc_3 %>% filter(state == "mcmc")
mcmc_post_3 ## combine
= rbind(mcmc_1, mcmc_2, mcmc_3)
mcmc_all = mcmc_all %>% filter(state == "mcmc")
mcmc_non_burn_in = nrow(mcmc_post_1) + nrow(mcmc_post_2) + nrow(mcmc_post_3)
n_posterior_samples ## do some modifying so we have just parameters available
## TODO: change parameter labels so they are not so large and easier to read on figures
= colnames(mcmc_post_1[,12:(ncol(mcmc_non_burn_in) - 1)])
pars = max(nrow(mcmc_post_1), nrow(mcmc_post_2), nrow(mcmc_post_3))
iters = array(dim = c(iters, 3, length(pars)), dimnames = list(1:iters, 1:3, pars))
bayes_array 1:nrow(mcmc_post_1),1,] = as.matrix(mcmc_post_1[,12:(ncol(mcmc_non_burn_in) - 1)])
bayes_array[1:nrow(mcmc_post_2),2,] = as.matrix(mcmc_post_2[,12:(ncol(mcmc_non_burn_in) - 1)])
bayes_array[1:nrow(mcmc_post_3),3,] = as.matrix(mcmc_post_3[,12:(ncol(mcmc_non_burn_in) - 1)])
bayes_array[## cut off at min
= min(nrow(mcmc_post_1), nrow(mcmc_post_2), nrow(mcmc_post_3))
min_cutoff = bayes_array[1:min_cutoff, ,] bayes_array
6.2 Diagnostics
## get Rhats
= apply(bayes_array, MARGIN = 3, Rhat)
rhats ## get effective sample sizes
= apply(bayes_array, MARGIN = 3, ess_bulk)
n_eff_bulk = apply(bayes_array, MARGIN = 3, ess_tail)
n_eff_tail ## TODO: need to think about what is a good general rule of thumb.
## I was thinking you would want n_eff of at least 200.
The Rhat
function produces R-hat convergence diagnostic, which compares the between- and within-chain estimates for model parameters and other univariate quantities of interest. Chains that have not mixed well (i.e., the between-and within-chain estimates don’t agree) will result in R-hat larger than 1.1. The ess_bulk
function produces an estimated Bulk Effective Sample Size (bulk-ESS) using rank normalized draws. Bulk-ESS is useful measure for sampling efficiency in the bulk of the distribution (related e.g. to efficiency of mean and median estimates), and is well defined even if the chains do not have finite mean or variance. The ess_tail
function produces an estimated Tail Effective Sample Size (tail-ESS) by computing the minimum of effective sample sizes for 5% and 95% quantiles. Tail-ESS is useful measure for sampling efficiency in the tails of the distribution (related e.g. to efficiency of variance and tail quantile estimates).
Once you have calculated these quantities you can use bayesplot
plotting functions. Need to work on changing parameter labels from the Casal2 model. They make some of these plots difficult to read
mcmc_rhat(rhats)
## Warning: Dropped 6 NAs from 'new_rhat(rhat)'.
#mcmc_neff(n_eff_bulk)
#mcmc_neff(n_eff_tail)
6.3 Plotting quantities
## This function helps create 95% CIs for quantities
<- c(0.025, 0.5, 0.975) ## confidence intervals
p <- map_chr(p, ~paste0(.x*100, "%"))
p_names <- map(p, ~partial(quantile, probs = .x, na.rm = TRUE)) %>%
p_funs ::set_names(nm = c("low", "mid", "upp"))
rlang#p_funs
## Bring in derived quantities
= system.file("extdata", "tabular.log", package = "r4Casal2", mustWork = TRUE)
cas2_file_name = extract.tabular(file = cas2_file_name, quiet = T)
cas2_tab ## cut off burn-in the first 50 samples
= burn.in.tabular(cas2_tab, Row = 50) cas2_tab
6.3.1 selectivities
= get_selectivities(cas2_tab)
selectivity_df = selectivity_df %>%
quantile_selectivity_df group_by(bin, selectivity_label) %>%
summarize_at(vars(selectivity), p_funs)
ggplot(quantile_selectivity_df, aes(x = bin)) +
geom_ribbon(aes(ymax = low, ymin = upp, alpha = 0.5, col = selectivity_label, fill = selectivity_label), lwd=0) +
geom_line(aes(y = mid, col = selectivity_label, group = selectivity_label), size =2, alpha = 1) +
facet_wrap(~selectivity_label) +
labs(x = "Age", y = "Ogive", col = "Model", linetype = "Model")
6.3.2 Derived quantities
# plot Ssbs
= get_derived_quanitites(model = cas2_tab) ssbs
## getting values for SSB_E
## getting values for SSB_W
#ssbs_mpd = get_derived_quanitites(model = mpd)
#head(ssbs)
#ssbs_mpd$years = as.numeric(ssbs_mpd$years)
$years[ssbs$years == "initialisation_phase_1"] = 1971
ssbs
= ssbs %>%
quantile_ssb_df group_by(years, dq_label) %>%
summarize_at(vars(values), p_funs)
$years = as.numeric(quantile_ssb_df$years)
quantile_ssb_df##
= ggplot(quantile_ssb_df, aes(x = years)) +
quant_ssb_plot geom_ribbon(aes(ymax = low, ymin = upp, alpha = 0.5, col = dq_label, fill = dq_label), lwd=0) +
theme_bw() +
geom_line(aes(y = mid, col = dq_label, group = dq_label), size =2, alpha = 1) +
xlab("Years") +
ylab("SSB") +
ylim(0, 2500000) +
xlim(1970, 2020) +
scale_alpha(guide = 'none') +
#geom_line(data = ssbs_mpd, aes(x = years, y = values), inherit.aes = F, col = "black", size = 1.5) +
facet_wrap(~dq_label)
quant_ssb_plot