Metropolis sampling from discrete distributions using proposal matrices.
mcmc
sampling
Demonstrates how to use Metropolis MCMC to sample from discrete distributions. Shows that MCMC handles discrete state spaces using proposal matrices that satisfy detailed balance, applied to sampling from a Poisson distribution.
Published
April 16, 2025
Sampling from a discrete distribution
%matplotlib inlineimport numpy as npfrom scipy import statsfrom scipy.stats import normimport matplotlib.pyplot as pltimport seaborn as snssns.set_style("whitegrid")
//anaconda/envs/py35/lib/python3.5/site-packages/matplotlib/__init__.py:872: UserWarning: axes.color_cycle is deprecated and replaced with axes.prop_cycle; please use the latter.
warnings.warn(self.msg_depr % (key, alt_key))
In simulated annealing, we carried out combinatorical oprimization by sampling from a state space where each state was a vector of baseball simulation features.
Since Metropolis MCMC is the same algorithm, it should be clear that its possible to simulate discrete possibilities in MCMC as long as you choose proposals which satisfy detailed balance.
As an example, consider simulating a poisson distribution. Since its discrete, the proposal wont be a continuous \(q(x,y)\) (the proposal probability to go from y to x), but rather a matrix indexed by a variable that corresponds to (indexes) the various states that can be obtained.
from scipy.stats import poissonxxx= np.arange(1,20,1)plt.plot(xxx, poisson.pmf(xxx, mu=5), 'o');
To sample from this distribution, we must create a proposal matrix which allows us to go from any integer output to any other in a finite number of steps. This matrix must be symmetric, since we wish to use Metropolis.
A simple such matrix, which is although a bit slow, would be one which has immediate off-diagonal elements (from Stats 580 at Iowa state..)
Symmetric random-walk proposal matrix Q for discrete MCMC: each state proposes to stay or move to an adjacent state with equal probability.
def prop_pdf(ito, ifrom):if ito == ifrom -1:return0.5elif ito == ifrom +1:return0.5elif ito == ifrom and ito ==0:#needed to make first row sum to 1return0.5else:return0
def prop_draw(ifrom): u = np.random.uniform()if ifrom !=0:if u <1/2: ito = ifrom -1else: ito = ifrom +1else:if u <1/2: ito=0else: ito=1return ito