Blist Multilingual Theme
*

Gibbs Sampling

Posted on *  •  2 minutes  • 412 words

Gibbs Sampling

Gibbs sampling is a Markov Chain Monte Carlo algorithm and a special case of the Metropolis-Hastings algorithm.

Gibbs Sampler can draw samples from any distribution, The Gibbs sampler draws iteratively from posterior conditional distributions rather than drawing directly from the joint posterior distribution. So it is useful in cases where joint distributions may be complex but one may be able to sample directly from less complicated conditional distributions.

Starting values are needed to initiate the Gibbs sampling process.The sampling depends on the values in the previous iteration; however, the sampling procedure is known to converge on to the final distribution, desired posterior, and that the process does on depend on the initial starting values.

Example: Bivariate Normal Distribution

With $\textbf{x} = (x_1, x_2)$, $\mu = (\mu_1, \mu_2)$ and $\Sigma$ being a $2 × 2$ covariance matrix with diagonal entries $\sigma_{1}^2$, $\sigma_{2}^2$ and off-diagonals $\sigma_{1,2}$.

$$f(\textbf{x} | \mu,\Sigma) \propto \left| \Sigma \right|^{-1/2}exp\left( -\frac{1}{2}(\textbf{x} - \mu)^{t} \Sigma^{-1}(\textbf{x}-\mu) \right)$$

$$f(x_1 | x_2) = N(\mu_1 + (\sigma_{1,2}/\sigma_{2}^2)(x_2 - \mu_2), \sigma_{1}^2 -(\sigma_{1,2}/ \sigma_{2})^{2} )$$ and, $$f(x_2 | x_1) = N(\mu_2 + (\sigma_{1,2}/\sigma_{1}^2)(x_1 - \mu_1), \sigma_{2}^2 -(\sigma_{1,2} / \sigma_{1})^{2} )$$

Python Implementation

Following is python implementation of Gibbs Sampling in case of 2D Gaussian distribution

def gibbs_sampling(joint_mu, joint_cov):
    def conditional_sampler(point, var_index):
        A = joint_cov[var_index, var_index]
        B = joint_cov[var_index, ~var_index]  #
        C = joint_cov[~var_index, ~var_index]       
        mu = joint_mu[var_index] + B / C * (point[~var_index] - joint_mu[~var_index])
        sigma = A - B / C * B
        return np.random.normal(mu, sigma)
    return conditional_sampler

joint_mu = np.array([0, 1])
joint_cov = np.array([[1, -0.8], [-0.8, 1.5]])
sampler = gibbs_sampling(joint_mu, joint_cov)

define function that takes an inital point and number of smaples.

def generate_samples(initial_point, num_samples):
    point = np.array(initial_point)
    samples = np.zeros((num_samples, 2))
    samples[0] = point
    
    for i in range(1, num_samples):        
        samples[i, :] = samples[i - 1, :]
        d = i % 2  #alternate between x2 and x1
        x = sampler(samples[i], d)
        samples[i,d] = x
    return samples

The main call - choose an initial point and call generate_samples

initial_point = [-3.5, 3.0]
num_samples = 25
samples = generate_samples(initial_point, num_samples)

Plottting generated samples

The figure on left shows the path taken by the generated samples, the next point depending on pevious one. As can be seen from the right panel, after a lot of iteration ($N = 1000$), it then converges to approximately the exact distribution being sampled. alt text

References:

Follow me

I work on everything - molecular simulations, data science and coding