{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "BwUwrL3Vs6YA" }, "source": [ "## Metropolis Hasting on a Mixture of Gaussians in 1d\n", "$\n", "\\newcommand{\\PP}{\\mathbb P}\n", "\\newcommand{\\PE}{\\mathbb E}\n", "\\newcommand{\\Xset}{\\mathsf{X}}\n", "\\newcommand{\\nset}{\\mathbb{N}}\n", "\\newcommand{\\invcdf}[1]{F_{#1}^{\\leftarrow}}\n", "\\newcommand{\\rmd}{\\mathrm{d}}\n", "\\newcommand{\\rme}{\\mathrm{e}}\n", "$\n", "This jupyter notebook is based on Randal Douc's google colab whose link can be found at the beginning of the course notes: https://wiki.randaldouc.xyz/lib/exe/fetch.php?media=world:polymcmc.pdf.\n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "id": "Yym8_tdfT3nu" }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import numpy.random as npr\n", "import scipy.stats as stats\n", "from scipy.stats import expon, geom, norm\n", "from math import pi\n", "from pylab import *\n", "%matplotlib inline\n", "\n", "from IPython.display import HTML\n", "from matplotlib import animation, rc" ] }, { "cell_type": "markdown", "metadata": { "id": "VUCIQn9ETl-R" }, "source": [ "## Symmetric Random Walk Metropolis Hasting algorithm\n", "\n", "We now consider a target distribution which is the mixing of two gaussian distributions, one centered at $a$ and the other one centered at $-a$\n", "$$\n", "\\pi(x)=\\frac{1}{2}\\left(\\phi(x-a)+\\phi(x+a)\\right)=\\frac{1}{2} \\frac{\\rme^{-(x-a)^2}}{\\sqrt{2\\pi}}+\\frac{1}{2} \\frac{\\rme^{-(x+a)^2}}{\\sqrt{2\\pi}}\n", "$$\n", "where $\\phi$ is the density of the centered standard normal distribution.\n", "\n", "To target this distribution, we sample according to a Symmetric Random Walk Metropolis Hasting algorithm. When the chain is at the state $X_k$, we propose a candidate $Y_{k+1}$ according to $Y_{k+1}=X_k+Z_k$ where $Z_k\\sim {\\mathcal N}(0,1)$ and then we accept $X_{k+1}=Y_{k+1}$ with probability $\\alpha(X_k,Y_{k+1})$, where $\\alpha(x,y)=\\frac{\\pi(y)}{\\pi(x)} \\wedge 1$. Otherwise, $X_{k+1}=X_{k}$." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "colab": { "background_save": true }, "id": "xDS-IcTY0P7-", "outputId": "94bbfa65-9bbe-40b0-c0c6-7ac503dbfbaf" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "
\n", " \n", "
\n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# iterations, position of the means, frequence of recording \n", "p,a,r = 30001,3,200\n", "mc = npr.randn()*np.ones(p)\n", "cible = lambda x,a: (np.exp(-(x-a)**2/2)+np.exp(-(x+a)**2/2))/np.sqrt(8*pi)\n", "\n", "data = []\n", "for i in range(p-1):\n", " v = npr.randn()\n", " alpha = cible(mc[i]+v,a)/cible(mc[i],a)\n", " mc[i+1] = mc[i]\n", " if (npr.rand() < alpha):\n", " mc[i+1] += v\n", " if ((i+1)%r == 0):\n", " data.append(list(mc[0:i]))\n", "\n", "s = np.cumsum(mc)/np.arange(1,p+1)\n", "x = np.linspace(min(mc),max(mc),100)\n", "number_of_frames = int(p/r)\n", "fig, ax = plt.subplots(3,1, figsize=(15,9))\n", "plt.close()\n", "\n", "def update_hist(num,data):\n", " fig.tight_layout(rect = [0, 0, 1, 0.9])\n", " ax[0].cla()\n", " ax[0].set_ylim(0, 0.25)\n", " ax[0].hist(data[num],bins = 40, density = True, edgecolor = \"black\")\n", " ax[0].plot(x,cible(x,a),color=\"red\")\n", " ax[0].plot(mc[num*r],0.005,\"o\",color=\"yellow\")\n", " ax[0].set_title(\"Histogram of a trajectory of the MC. sample nb=\"+str(r*(num+1)))\n", " ax[1].cla()\n", " ax[1].set_xlim(0,p)\n", " ax[1].set_ylim(-6,6)\n", " ax[1].plot(mc[0:num*r])\n", " ax[1].set_title(\"Trajectory of the MC. sample nb=\"+str(r*(num+1)))\n", " ax[2].cla()\n", " ax[2].set_xlim(0,p)\n", " ax[2].set_ylim(-6,6)\n", " ax[2].plot(s[0:num*r])\n", " ax[2].axhline(y=1, color='red')\n", " ax[2].set_title(\"Empirical mean. sample nb=\"+str(r*(num+1)))\n", "\n", "\n", "anim = animation.FuncAnimation(fig, update_hist, number_of_frames, fargs=(data, ),repeat = False)\n", "rc('animation', html='jshtml')\n", "anim" ] }, { "cell_type": "markdown", "metadata": { "id": "dSGUdjYE6UM9" }, "source": [ "## Independent Metropolis Hasting algorithm\n", "\n", "We again consider a target distribution which is the mixing of two gaussian distributions, one centered at $a$ and the other one centered at $-a$\n", "$$\n", "\\pi(x)=\\frac{1}{2}\\left(\\phi(x-a)+\\phi(x+a)\\right)=\\frac{1}{2} \\frac{\\rme^{-(x-a)^2}}{\\sqrt{2\\pi}}+\\frac{1}{2} \\frac{\\rme^{-(x+a)^2}}{\\sqrt{2\\pi}}\n", "$$\n", "where $\\phi$ is the density of the centered standard normal distribution.\n", "\n", "To target this distribution, we sample according to a Metropolis Hasting algorithm with independent proposal. When the chain is at the state $X_k$, we propose a candidate $Y_{k+1}$ according to $Y_{k+1}=Z_k$ where $Z_k\\sim {\\mathcal N}(sft,sig^2)$ and then we accept $X_{k+1}=Y_{k+1}$ with probability $\\alpha(X_k,Y_{k+1})$, where $\\alpha(x,y)=\\frac{\\pi(y)q(x)}{\\pi(x)q(y)} \\wedge 1=\\frac{\\pi(y)/q(y)}{\\pi(x)/q(x)} \\wedge 1$ and $q$ is the density of ${\\mathcal N}(sft,sig^2)$. Otherwise, $X_{k+1}=X_{k}$." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "colab": { "background_save": true }, "id": "8h-UXiS_6Vee" }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", "
\n", " \n", "
\n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
\n", "
\n", "\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "counts = 0\n", "p,a,r,sig,sft = 30001,3,200,2,-2\n", "mc2 = npr.randn()*np.ones(p)\n", "cible = lambda x,a: (np.exp(-(x-a)**2/2)+np.exp(-(x+a)**2/2))/np.sqrt(8*pi)\n", "densi = lambda x,m,s: np.exp(-(x-m)**2/(2*s**2))/np.sqrt(2*pi*s**2)\n", "\n", "data2 = []\n", "for i in range(p-1):\n", " v = sig*npr.randn()+sft\n", " alpha = cible(v,a)*densi(mc2[i],sft,sig)/(cible(mc2[i],a)*densi(v,sft,sig))\n", " mc2[i+1] = mc2[i]\n", " if v>6:\n", " counts += 1\n", " if (npr.rand()