using CairoMakie
using Distributions
using LinearAlgebra
using MCMCChains
using PairPlots
using Statistics
import StatsPlots
set_theme!(
=18,
fontsize=(xgridvisible=false, ygridvisible=false,
Axis=false, rightspinevisible=false),
topspinevisible )
Random walk Metropolis
\[ \begin{align} &p(θ | data) \propto p(data | θ) \cdot p(θ) \\ &r_{M} = min\left(1, \frac{p(θ_{t+1} | data)}{p(θ_{t} | data)}\right) \end{align} \]
1 Setup:
2 Generate data
= 5, 2
μ, σ = rand(Normal(μ, σ), 500)
y hist(y)
3 Define Likelihood and Prior
= [0.01, 0.001]
propσ = truncated(Normal(0, 3), -10, 10)
prior_μ = truncated(Normal(0, 1), 0, 10)
prior_σ
function posterior(θ)
## prior
= logpdf(prior_μ, θ[1])
log_prior += logpdf(prior_σ, θ[2])
log_prior if log_prior == -Inf
return -Inf
end
## likelihood
= 0
log_likelihood for i in eachindex(y)
+= logpdf(Normal(θ[1], θ[2]), y[i])
log_likelihood end
## unnormalized posterior
= log_likelihood + log_prior
p
return p
end
posterior (generic function with 1 method)
4 Run MCMC
= 20_000
n_samples = n_samples ÷ 2
burnin = 6
nchains = 2
nparameter = zeros(nchains, nparameter, n_samples)
accepted_θ = zeros(nchains)
accepted = zeros(nparameter)
θ
for n in 1:nchains
1] = rand(prior_μ)
θ[2] = rand(prior_σ)
θ[= posterior(θ)
post
for k in 1:n_samples
## new proposal
= MvNormal(θ, Diagonal(propσ))
proposal_dist = rand(proposal_dist)
θstar
## evaluate prior + likelihood
= posterior(θstar)
poststar
## M-H ratio
= poststar - post
ratio
if log(rand()) < min(ratio, 1)
+= 1
accepted[n] = θstar
θ = poststar
post end
:, k] = θ
accepted_θ[n, end
end
/ n_samples accepted
6-element Vector{Float64}:
0.6268
0.6307
0.6279
0.63075
0.6265
0.6237
5 Convergence
= Chains(permutedims(accepted_θ, (3,2,1)), [:μ, :σ]) chn
Chains MCMC chain (20000×2×6 Array{Float64, 3}):
Iterations = 1:1:20000
Number of chains = 6
Samples per chain = 20000
parameters = μ, σ
Summary Statistics
parameters mean std mcse ess_bulk ess_tail rhat ⋯
Symbol Float64 Float64 Float64 Float64 Float64 Float64 ⋯
μ 5.0759 0.2907 0.0094 6344.6253 5318.0115 1.0009 ⋯
σ 2.0533 0.0998 0.0026 3695.9014 3685.7343 1.0011 ⋯
1 column omitted
Quantiles
parameters 2.5% 25.0% 50.0% 75.0% 97.5%
Symbol Float64 Float64 Float64 Float64 Float64
μ 4.8948 5.0235 5.0845 5.1470 5.2699
σ 1.9298 2.0132 2.0556 2.1002 2.1903
6 Trace plot and densities of the MCMC samples
6.1 With burnin
function trace_plot(; burnin)
= Figure()
fig
= ["μ", "σ"]
titles for i in 1:2
Axis(fig[i,1]; title = titles[i])
for n in 1:nchains
lines!((burnin:n_samples) .- burnin, accepted_θ[n, i, burnin:end];
=(Makie.wong_colors()[n], 0.5))
colorend
Axis(fig[i,2])
for n in 1:nchains
density!(accepted_θ[n, i, burnin:end];
= (Makie.wong_colors()[n], 0.1),
color = (Makie.wong_colors()[n], 1),
strokecolor = 2, strokearound = false)
strokewidth end
end
rowgap!(fig.layout, 1, 5)
figend
trace_plot(; burnin = 1) # keep all samples
6.2 Without burnin
trace_plot(; burnin) # remove half of the samples
6.2.1 Or use the function fromm StatsPlots
plot(chn[burnin:end, :, :]) StatsPlots.
7 Pair plot
7.1 With burnin
pairplot(chn)
7.2 Without burnin
pairplot(chn[burnin:end, :, :])
8 Posterior predictive check
begin
= Figure()
fig
Axis(fig[1,1]; title="Posterior predictive check")
= vec(accepted_θ[:, 1, burnin:end])
μs = vec(accepted_θ[:, 2, burnin:end])
σs
= 500
npredsamples = sample(1:length(μs), npredsamples;
ns =false)
replace
= minimum(y)-4, maximum(y)+4
minx, maxx = 200
nxvals = LinRange(minx, maxx, nxvals)
xvals = zeros(npredsamples, nxvals)
pred
## calculate and plot each predictive sample
for i in eachindex(ns)
= μs[ns[i]]
μ = σs[ns[i]]
σ = Normal(μ,σ)
post_dist
= pdf.(post_dist, xvals)
yvals :] = yvals
pred[i,
lines!(xvals, yvals;
=(:grey, 0.1))
colorend
## mean of the predicted densities
= vec(mean(pred, dims=1))
meany lines!(xvals, meany;
=3,
linewidth=(:red, 0.8))
color
## histogram of the data
hist!(y;
= :pdf,
normalization = 25,
bins = (:blue, 0.3),
color = (:white, 0.5),
strokecolor = 1)
strokewidth
figend