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.60775
0.61345
0.61275
0.61275
0.6182
0.6232
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 ⋯ μ 4.9236 0.4876 0.0228 6761.4570 3574.8038 1.0009 ⋯ σ 1.9804 0.0950 0.0031 3527.9637 3195.3202 1.0019 ⋯ 1 column omitted Quantiles parameters 2.5% 25.0% 50.0% 75.0% 97.5% Symbol Float64 Float64 Float64 Float64 Float64 μ 4.7698 4.8933 4.9534 5.0139 5.1282 σ 1.8595 1.9349 1.9759 2.0200 2.1108
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];
=20,
bins= (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