🧠 RMarkdown or Quarto: Make sure it knits, renders, and saves without RStudio crying.
(If it knits, you’re officially a data scientist.)
📝 Markdown Basics — Learn how to make text bold, italic, draw diagrams, or show off anything you want to demonstrate.
🚀 Hello, Quarto by Dr. Mine Çetinkaya-Rundel (Duke University) — From “What’s a chunk?” to “Look, I just published my work on GitHub!”
Markov Chain Monte Carlo(MCMC)
MCMC - Metropolis-Hastings Algorithm
Let’s recap of Key Concepts
Step 1: Propose a candidate sample from the proposal (transition) distribution \[
g(x_{t+1} \mid x_t)
\] For example, if the proposal is Normal, \[
g(x_{t+1} \mid x_t) = \mathcal{N}(x_t, \sigma^2)
\]
Step 2: Accept the proposed value with probability \[
A(x_t \rightarrow x_{t+1})
\]
Detail Balance Condition to reach stationary: \(\quad p(a) T(a \rightarrow b)=p(b) T(b \rightarrow a), \quad \forall a, b\)
\[
\begin{aligned}
\frac{f(a)}{NC} g(b \mid a) A(a \rightarrow b)=\frac{f(b)}{NC } g(a \mid b) A(b \rightarrow a)
\end{aligned}
\]
MCMC - Metropolis-Hastings Algorithm
\[
\begin{aligned}
\frac{f(a)}{NC} g(b \mid a) A(a \rightarrow b)=\frac{f(b)}{NC } g(a \mid b) A(b \rightarrow a)
\end{aligned}
\] Rewrite the balance condition:
Intuition: Since \(\theta^{(t-1)}\) is already in our set, we should include \(\theta^*\) as it has a higher probability than \(\theta^{(t-1)}\).
Procedure: Accept \(\theta^*\) into our set, i.e. set \(\theta^{(s)}=\theta^*\).
If \(r<1\) :
Intuition: The relative frequency of \(\theta\)-values in our set equal to \(\theta^*\) compared to those equal to \(\theta^{(t-1)}\) should be \(p\left(\theta^* \mid y\right) / p\left(\theta^{(t-1)} \mid y\right)=r\). This means that for every instance of \(\theta^{(t-1)}\), we should have only a “fraction” of an instance of a \(\theta^*\) value.
Procedure: Set \(\theta^{(t)}\) equal to either \(\theta^*\) or \(\theta^{(t-1)}\), with probability \(r\) and \(1-r\) respectively.
MCMC - Metropolis-Hastings Algorithm(HW problem 1)
Consider the file school1. dat (from the Book website) which contains data on the amount of times students at a high school spent on studying or homework during an exam period. Suppose we fit the following model:
MCMC - Metropolis-Hastings Algorithm(HW problem 1, contd)
# Run chain with sigma_p = 0.5set.seed(425)chain_small <-mh_sampler(sigma_p =0.5)# Summaries and plotssummary(chain_small)
Iterations = 1:4000
Thinning interval = 1
Number of chains = 1
Sample size per chain = 4000
1. Empirical mean and standard deviation for each variable,
plus standard error of the mean:
Mean SD Naive SE Time-series SE
9.132470 0.193392 0.003058 0.006434
2. Quantiles for each variable:
2.5% 25% 50% 75% 97.5%
8.768 9.002 9.133 9.264 9.505
MCMC - Metropolis-Hastings Algorithm(HW problem 1, contd)
traceplot(chain_small, main ="Trace Plot (sigma_p = 0.5)")
MCMC - Metropolis-Hastings Algorithm(HW problem 1, contd)
densplot(chain_small, main ="Posterior Density (sigma_p = 0.5)")
MCMC - Metropolis-Hastings Algorithm(HW problem 1, contd)
autocorr.plot(chain_small, main ="Autocorrelation (sigma_p = 0.5)")
MCMC - Metropolis-Hastings Algorithm(HW problem 1, contd)
(b) Provide a trace plot and a plot of the histogram and/or kernel density estimate for each chain.
To answer this, you can run the following code and then compare the plots:
I have demonstrated the case when \(\sigma_p=0.5\). Don’t forget to try \(\sigma_p=2\) !
MCMC - Metropolis-Hastings Algorithm(HW problem 1, cont’d)
(c) After removing an appropriate burn-in, evaluate the acceptance rate and the autocorrelation for varying lags. Which value of \(\sigma_p\) provides a better choice for the proposal function?
# Acceptance rate functionacceptance_rate <-function(chain) { draws <-as.numeric(chain)mean(diff(draws) !=0)}acceptance_rate(chain_small)
[1] 0.4211053
(This is just an arbitrary number I came up with — you should check your own chain.)
The pattern is likely to be:
\(\sigma_p=0.5\) accepts \(\sim 82 \%\) proposals \(\rightarrow\) too conservative.
Gibbs sampler. Consider the file school1. dat (from the Book) which contains data on the amount of times students at a high school spent on studying or homework during an exam period. Suppose we fit the following model:
par(mfrow =c(1, 2))acf(mu_samp, main ="ACF of mu")acf(sigma2_samp, main ="ACF of sigma2")
par(mfrow =c(1, 1)) # reset layout
MCMC - Gibbs sampler(HW problem 2, cont’d)
plot(mu_mcmc, main ="Trace & Density of mu")
MCMC - Gibbs sampler(HW problem 2, cont’d)
plot(sigma2_mcmc, main ="Trace & Density of sigma2")
MCMC - Gibbs sampler(HW problem 2, cont’d)
(d) Evaluate the marginal posterior density \(p\left(\sigma^2 \mid \boldsymbol{y}\right)\) analytically up to a normalizing constant and overlay this density on your plot from (c) [Hint: you can perform the comparison by evaluating the unnormalized density on a grid of values].
MCMC - Gibbs sampler & MH(package(coda))
You can technically wrap any numeric vector or matrix(object here) in mcmc_obj <- mcmc(object) , even if it isn’t a “real” MCMC sequence. However - and this is key - doing so doesn’t make it an MCMC chain in a statistical sense. It just labels it as one so that functions like plot(), acf(), and effectiveSize() can run without error.
❌ Non-conjugate — prior and likelihood don’t simplify
❌ No closed-form normalization — integral can’t be solved
Result: \(p(\theta,\sigma|y)\) has no analytic form, no direct sampler, and no closed expression.
🤢 Manual derivation stops here.
What Are BUGS and JAGS?
BUGS (Bayesian inference Using Gibbs Sampling):
Early Bayesian software (1990s, Cambridge) using Gibbs sampling. Versions include Classic BUGS(1990s), WinBUGS(Windows-only), and OpenBUGS(open-source successor).
JAGS (Just Another Gibbs Sampler):
Developed by Martyn Plummer in 2003 as a cross-platform, open-source, and R-integrated version of BUGS.
💡 JAGS keeps the same model syntax as BUGS but adds flexibility, automatic Metropolis–within–Gibbs sampling, and modern extensibility.
Why JAGS
Doing MCMC by hand means:
Writing out priors and likelihood
Deriving full conditional posteriors for Gibbs sampling
Specifying a proposal distribution for Metropolis–Hastings
Tracking the update order for every parameter
As models grow complex, this becomes
🔁 tedious,
🧮 algebraically messy, and
🚫 often intractable.
You want to spend time analyzing, not deriving.
JAGS can help you solve this once you specify the prior and the likelihood!
Enter JAGS
JAGS automates MCMC sampling.
You define your model using BUGS-like syntax.
It automatically:
Constructs the posterior
Performs Gibbs / Metropolis-Hastings sampling
Returns results to R through rjags or R2jags.
How JAGS Samples Behind the Scenes
Even within Gibbs sampling, not all parameters have closed-form conditionals.
JAGS handles this automatically:
Parameter Type
Sampling Strategy
Description
Conjugate blocks
Pure Gibbs
Exact draws from known conditionals
Non-conjugate blocks
Metropolis–within–Gibbs
Uses adaptive random-walk MH inside Gibbs
Difficult continuous nodes
Slice sampling
Efficient for highly nonlinear posteriors
So Gibbs and Metropolis run in parallel:
Each iteration updates some parameters by Gibbs, others by Metropolis
JAGS adapts proposal scales automatically during burn-in
You don’t need to code or tune anything
💡 You define the model; JAGS decides the best sampler for each part.
brew install jags #run this command in terminalbrew list --versions jags #check versionbrew uninstall jags #uninstall jagsbrew upgrade #upgrade
If you download manually, how to remove?
#run this command in terminalwhich jags #if you get this, then JAGS was installed manually/usr/local/bin/jags # To remove it, dosudo rm -rf /usr/local/bin/jagssudo rm -rf /usr/local/lib/JAGSsudo rm -rf /usr/local/share/jagssudo rm -rf /usr/local/include/jags# Verify JAGS is removedwhich jags
# Step 1 — Check if JAGS is installedjags# If JAGS is installed, you will see: Welcome to JAGS 4.3.2 (official binary)# Type "exit" to close JAGSexit# Step 2 — Check the installation path (optional)where jags# Step 3 — To uninstall JAGS# Go to Control Panel → Programs → Programs and Features# Find "JAGS 4.x.x" → Click Uninstall# Or delete manually (if Control Panel fails)rmdir/S/Q"C:\Program Files\JAGS"# Step 4 — Verify removal. It should show: 'jags' is not recognized as an internal or external commandjags
Loading JAGS(library(rjags)) in R
# install.packages(c("rjags", "coda"))# Ensure dependencies are installed# (coda must be loaded before rjags, since rjags depends on it)install.packages("rjags",type ="source",repos ="https://cloud.r-project.org",configure.args ="--with-jags-prefix=/opt/homebrew/opt/jags")# Load required packageslibrary(coda) # For MCMC diagnostics and output handlinglibrary(rjags) # Interface to the JAGS (Just Another Gibbs Sampler) engine
# BUGS syntax (general form) " model { for (i in 1:N) { # Likelihood y[i] ~ distribution(parameter1, parameter2) # stochastic: likelihood for data } # Priors for parameters parameter1 ~ prior_distribution1(hyperparameter_set1) # prior for parameter1 parameter2_raw ~ prior_distribution2(hyperparameter_set2) # prior for parameter2 (before transformation) # Deterministic relationship (if needed) parameter2 <- g(parameter2_raw) # e.g., transformation such as 1 / variance } "
Then, append the model{} block into the R code
# Model specificationmodel_code <-" model { for (i in 1:N) { y[i] ~ dnorm(mu, tau) # likelihood for data } # Priors for parameters mu ~ dnorm(0, 0.01) # Prior: mu ~ N(0, 100), in JAGS, always use precision = 1/100 = 0.01 sigma ~ dunif(0, 10) # Prior: sigma ~ Uniform(0, 10) tau <- pow(sigma, -2) # Precision tau = 1 / sigma^2 }"# Write model to filewriteLines(model_code, "model.txt")
# BUGS syntax (general linear regression form) " model { for (i in 1:N) { # Likelihood y[i] ~ dnorm(mu[i], tau) # stochastic: likelihood for data mu[i] <- beta0 + beta1 * x[i] # deterministic: mean structure } # Priors for regression coefficients beta0 ~ dnorm(0, 0.001) # Prior: β₀ ~ N(0, 1000) beta1 ~ dnorm(0, 0.001) # Prior: β₁ ~ N(0, 1000) # Prior for error variance tau <- 1 / pow(sigma, 2) # Precision = 1 / σ² sigma ~ dunif(0, 100) # Equivalent to Inv-Gamma(0.001, 0.001) } "
Then, append the model{} block into the R code
# Model specificationmodel_code_2 <-" model { for (i in 1:N) { y[i] ~ dnorm(mu[i], tau) # likelihood for data mu[i] <- beta0 + beta1 * x[i] # mean structure } beta0 ~ dnorm(0, 0.001) # prior for intercept beta1 ~ dnorm(0, 0.001) # prior for slope sigma ~ dunif(0, 100) # prior for standard deviation tau <- pow(sigma, -2) # precision = 1 / sigma^2 } "# Write model to filewriteLines(model_code_2, "model_2.txt")
🚀 Hands-On with rjags: Let’s Build a Bayesian Model
Example 1 (Cont’d)
Suppose we would like to run a model to draw inference about the mean for the following model:
\[
y_i \sim N\left(\mu, \sigma^2\right)
\]
where \(y_i\) are the data include 30 observations.
# Ground Truthrm(list=ls())n =30mu =1.12sigma =0.38# Generate values (stochastic part of the model)# In reality, you only observe 30 data points, and the true population mean # and variance are unknown. Our goal is to estimate these parameters.set.seed(425)y =rnorm(n, mean = mu, sd = sigma)
Example 1 (Cont’d)
df =data.frame(y)library(ggplot2)ggplot(df, aes(x = y)) +geom_histogram(bins =30) +labs(title ="Histogram of Simulated y", x ="y", y ="Count") +theme_minimal()
Recall our ground truth: mu = 1.12, sigma = 0.38. What will you conclude about the result from JAGS.
Example 1 (Cont’d) - Trace Plot
# Plot MCMC chainsplot(samples)
Example 1 (Cont’d) - Autocorrelation Plot & Effective Sample Size
autocorr.diag(samples)
mu sigma tau
Lag 0 1.000000000 1.00000000 1.00000000
Lag 1 0.025094240 0.35630290 0.28864584
Lag 5 -0.013925897 0.01981394 0.02119758
Lag 10 -0.006134278 -0.02285756 -0.02325007
Lag 50 0.019639958 -0.01332792 -0.00939205
effectiveSize(samples)
mu sigma tau
5917.557 2854.786 3445.522
# autocorr.plot(samples)
Example 1 (Cont’d) - Gelman-Rubin
#Examine convergence of the Markov chains using the Gelman-Brooks-Rubin diagnosticgelman.plot(samples)
Example 2 (Cont’d)
Simple Linear Regression: We have the data of 48 pigs with body weight measured at 9 successive weeks. Suppose we would like to fit the model: for \(i=1, \cdots, 432\)