library(purrr)
library(ggplot2)
library(stringr)
Specifying the Target and Proposal
# density of the target distribution
dtarget <- partial(dchisq, df=10)
# draws a proposal from uniform +-1 around the previous state
propose <- function(prev){runif(1, min=prev-1, max=prev+1)}
# the density of the proposal (conditional on the previous state)
dproposal <- function(prev, proposal){1/2}
# a boolean that represents rejection/acceptance of the proposal
accept <- function(prev, proposed){
U <- runif(1)
accept_prob <- min(1, dtarget(proposed) / dtarget(prev) *
dproposal(proposed, prev) / dproposal(prev, proposed))
return(U < accept_prob)
}
Running Metropolis-Hastings
# initializing
n <- 100000 # change it if your computer can't handle 1e5 samples.
previous_state <- 1
samples <- numeric(length = n)
# M-H
for (k in 1:n){
proposal <- propose(previous_state)
accepted <- accept(previous_state, proposal)
if (accepted){
previous_state <- proposal
samples[k] <- proposal
} else {
samples[k] <- previous_state
}
}
Plotting the Samples
binwidth <- 0.5 # how fine the density/bar plot should be
ggplot(data = data.frame(samples=samples)) +
geom_histogram(aes(x=samples,
y = after_stat(count / sum(count) / binwidth),
fill="M-H Samples"),
binwidth = binwidth,
alpha=0.6) +
geom_function(aes(color="Target Distribution"),
fun = dtarget) +
labs(x="Sample Value", y="Relative Density") +
scale_fill_manual(name = "", values = c("M-H Samples" = "#233F7E")) +
scale_color_manual(name = "", values = c("Target Distribution" = "#233F7E")) +
ggtitle(str_interp("Distribution of ${n} M-H Samples")) +
theme_minimal() + theme(legend.position="bottom")

LS0tCnRpdGxlOiAiTWV0cm9wb2xpcy1IYXN0aW5ncyBpbiBSIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7cn0KbGlicmFyeShwdXJycikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHN0cmluZ3IpCmBgYAoKIyBTcGVjaWZ5aW5nIHRoZSBUYXJnZXQgYW5kIFByb3Bvc2FsIApgYGB7cn0KIyBkZW5zaXR5IG9mIHRoZSB0YXJnZXQgZGlzdHJpYnV0aW9uCmR0YXJnZXQgPC0gcGFydGlhbChkY2hpc3EsIGRmPTEwKSAKCiMgZHJhd3MgYSBwcm9wb3NhbCBmcm9tIHVuaWZvcm0gKy0xIGFyb3VuZCB0aGUgcHJldmlvdXMgc3RhdGUKcHJvcG9zZSA8LSBmdW5jdGlvbihwcmV2KXtydW5pZigxLCBtaW49cHJldi0xLCBtYXg9cHJldisxKX0gIAoKIyB0aGUgZGVuc2l0eSBvZiB0aGUgcHJvcG9zYWwgKGNvbmRpdGlvbmFsIG9uIHRoZSBwcmV2aW91cyBzdGF0ZSkKZHByb3Bvc2FsIDwtIGZ1bmN0aW9uKHByZXYsIHByb3Bvc2FsKXsxLzJ9CgojIGEgYm9vbGVhbiB0aGF0IHJlcHJlc2VudHMgcmVqZWN0aW9uL2FjY2VwdGFuY2Ugb2YgdGhlIHByb3Bvc2FsCmFjY2VwdCA8LSBmdW5jdGlvbihwcmV2LCBwcm9wb3NlZCl7CiAgVSA8LSBydW5pZigxKQogIGFjY2VwdF9wcm9iIDwtIG1pbigxLCBkdGFyZ2V0KHByb3Bvc2VkKSAvIGR0YXJnZXQocHJldikgKiAKICAgICAgICAgICAgICAgICAgICAgICAgZHByb3Bvc2FsKHByb3Bvc2VkLCBwcmV2KSAvIGRwcm9wb3NhbChwcmV2LCBwcm9wb3NlZCkpCiAgcmV0dXJuKFUgPCBhY2NlcHRfcHJvYikKfQpgYGAKCiMgUnVubmluZyBNZXRyb3BvbGlzLUhhc3RpbmdzCmBgYHtyfQojIGluaXRpYWxpemluZwpuIDwtIDEwMDAwMCAgIyBjaGFuZ2UgaXQgaWYgeW91ciBjb21wdXRlciBjYW4ndCBoYW5kbGUgMWU1IHNhbXBsZXMuCnByZXZpb3VzX3N0YXRlIDwtIDEKc2FtcGxlcyA8LSBudW1lcmljKGxlbmd0aCA9IG4pCgojIE0tSApmb3IgKGsgaW4gMTpuKXsKICBwcm9wb3NhbCA8LSBwcm9wb3NlKHByZXZpb3VzX3N0YXRlKQogIGFjY2VwdGVkIDwtIGFjY2VwdChwcmV2aW91c19zdGF0ZSwgcHJvcG9zYWwpCiAgaWYgKGFjY2VwdGVkKXsKICAgIHByZXZpb3VzX3N0YXRlIDwtIHByb3Bvc2FsCiAgICBzYW1wbGVzW2tdIDwtIHByb3Bvc2FsCiAgfSBlbHNlIHsKICAgIHNhbXBsZXNba10gPC0gcHJldmlvdXNfc3RhdGUKICB9Cn0KYGBgCgojIFBsb3R0aW5nIHRoZSBTYW1wbGVzCmBgYHtyfQpiaW53aWR0aCA8LSAwLjUgICMgaG93IGZpbmUgdGhlIGRlbnNpdHkvYmFyIHBsb3Qgc2hvdWxkIGJlCgpnZ3Bsb3QoZGF0YSA9IGRhdGEuZnJhbWUoc2FtcGxlcz1zYW1wbGVzKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PXNhbXBsZXMsCiAgICAgICAgICAgICAgICAgICAgeSA9IGFmdGVyX3N0YXQoY291bnQgLyBzdW0oY291bnQpIC8gYmlud2lkdGgpLAogICAgICAgICAgICAgICAgICAgIGZpbGw9Ik0tSCBTYW1wbGVzIiksCiAgICAgICAgICAgICAgICAgYmlud2lkdGggPSBiaW53aWR0aCwKICAgICAgICAgICAgICAgICBhbHBoYT0wLjYpICsKICBnZW9tX2Z1bmN0aW9uKGFlcyhjb2xvcj0iVGFyZ2V0IERpc3RyaWJ1dGlvbiIpLAogICAgICAgICAgICAgICAgZnVuID0gZHRhcmdldCkgKwogIGxhYnMoeD0iU2FtcGxlIFZhbHVlIiwgeT0iUmVsYXRpdmUgRGVuc2l0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIiIsIHZhbHVlcyA9IGMoIk0tSCBTYW1wbGVzIiA9ICIjMjMzRjdFIikpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICIiLCB2YWx1ZXMgPSBjKCJUYXJnZXQgRGlzdHJpYnV0aW9uIiA9ICIjMjMzRjdFIikpICsKICBnZ3RpdGxlKHN0cl9pbnRlcnAoIkRpc3RyaWJ1dGlvbiBvZiAke259IE0tSCBTYW1wbGVzIikpICsKICB0aGVtZV9taW5pbWFsKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpCmBgYA==