-
-
Save simeoncarstens/ab1a0bc6f00a4403783b0bfc860573d3 to your computer and use it in GitHub Desktop.
| from numpy import sin, cos, arctan, sqrt, exp, random, pi, linspace | |
| import matplotlib.pyplot as plt | |
| def draw_sample(xold, sigma): | |
| t = 3.0 | |
| vold = random.normal() | |
| phi = arctan(-vold / xold * sigma) | |
| A = vold * sigma * sqrt(xold ** 2 / sigma ** 2 / vold ** 2 + 1) | |
| xnew = A * cos(t / sigma + phi) | |
| vnew = -A / sigma * sin(t / sigma + phi) | |
| E = lambda x: 0.5 * x ** 2 / sigma ** 2 | |
| K = lambda v: 0.5 * v ** 2 | |
| H = lambda x, v: E(x) + K(v) | |
| p_acc = min(1, exp(-(H(xnew, vnew) - H(xold, vold)))) | |
| if random.random() < p_acc: | |
| return xnew, True | |
| else: | |
| return xold, False | |
| sigma = 2.0 | |
| samples = [2.0] | |
| accepted = 0 | |
| n_samples = 100000 | |
| for _ in range(n_samples): | |
| new_state, acc = draw_sample(samples[-1], sigma) | |
| samples.append(new_state) | |
| accepted += acc | |
| fig, ax = plt.subplots() | |
| ax.hist(samples, bins=40, density=True) | |
| gaussian = lambda x: exp(-0.5 * x ** 2 / sigma ** 2) / sqrt(2 * pi * sigma ** 2) | |
| xspace = linspace(-5, 5, 300) | |
| ax.plot(xspace, list(map(gaussian, xspace))) | |
| plt.show() | |
| print("Acceptante rate:", accepted / n_samples) |
| #!/bin/bash | |
| img_list=$(ls -v output*.png) | |
| b=$(<$2) | |
| while read strA <&3 && read strB <&4; do | |
| rstring="..\/..\/img\/posts\/${strB}" | |
| echo $rstring | |
| sed -i "s/${strA}/${rstring}/g" $1 | |
| mv $strA $strB | |
| # cp $strB ~/projects/tweag/www/app/assets/img/posts/ | |
| done 3<<<"$img_list" 4<<<"$b" | |
| # cp $1 ~/projects/tweag/www/app/views/posts/ |
| #!/usr/bin/env python3 | |
| import sys | |
| from itertools import cycle | |
| import re | |
| with open(sys.argv[1]) as ipf: | |
| lines = ipf.readlines() | |
| # ## replace \{ with \\{ and \} with \\} | |
| lines = [l.replace('\\{', r'\\{') for l in lines] | |
| lines = [l.replace('\\}', r'\\}') for l in lines] | |
| ## replace \\ with \\\\ | |
| lines = [l.replace(r' \\', r' \\\\') for l in lines] | |
| ## replace ^* with ^\* | |
| lines = [l.replace(r'^*', r'^\*') for l in lines] | |
| ## alternatingly replace $ with \\( and \\) | |
| ## if it's not part of $$ | |
| lines2 = [] | |
| for line in lines: | |
| if '$$' in line: | |
| lines2.append(line) | |
| continue | |
| else: | |
| cycler = cycle((True, False)) | |
| matches = re.finditer('\$', line) | |
| offset = 0 | |
| for match in matches: | |
| replacement = '\\\(' if next(cycler) else '\\\)' | |
| line = line[:match.start()+offset] + replacement + line[match.start()+1+offset:] | |
| offset += 2 | |
| lines2.append(line) | |
| with open(sys.argv[2]) as ipf: | |
| header = ipf.readlines() | |
| with open(sys.argv[3], 'w') as opf: | |
| for line in header + lines2[2:]: | |
| opf.write(line) |
Thanks for your feedback, @MMesch and @feuerbach! Highly appreciated!
For now I mostly worked on the MH part and put it into a separate notebook, where I addressed some of @MMesch's points.
@MMesch: I fear the \pi is indeed somewhat standard - as p often denotes other probabilities such as p_acc.
@feuerbach: This is very interesting - and you're right. The background to this example is that, a few years ago, I did something like that to sample from a different kind of mixture model and back then we used to call it Gibbs sampling. Looking this up, it seems like a very common method to sample from Gaussian (and other) mixture models (where you can easily marginalize out x to obtain p(k)). It seems to be called "Collapsed Gibbs sampling". I will rewrite this part to feature an actual Gibbs sampler. I just need to think of a nice, concise example where you can sample from the conditional distributions without resorting to MCMC. And as for being stuck in one of the mixture components: highly correlated samples often are a problem when using Gibbs sampling and I should discuss this.
I am also thinking of discussing how to assess convergence for MCMC methods, but this is a very difficult topic. It would make the series much more complete, but is also a really ugly rock to look under...
@feuerbach: Just FYI, I implemented the actual Gibbs sampler for this problem and it turns out that
you'd have the same problem of being stuck in one of the mixture components, because p(k|x) would very likely give you the same k as the one that generated that x.
is a slight understatement. If the sampler starts in the mode on the right, there's (on average) a ~1/1e6 chance for it to jump to the mode on the left. That was fun and very instructive and might even serve in a next version of that blog post / notebook as a negative example.
Finished reading — very nice! I corrected a few typos here: https://gist.github.com/feuerbach/5ccaeee166b45be13a8e375f980f405a.
Maybe one day I'll make a similar post except everything is done in Stan :)