Slice Sampler
02 Apr 2016In [1]:
import pandas as pd
import numpy as np
from scipy.stats import gamma
import matplotlib.pylab as plt
%matplotlib inline
In [2]:
def SliceSample(log_p, theta, x, bandwidth=1):
"""
Simple implementation of Slice Sampler
Args:
log_p (function): reference to the log-function to sample from
theta (dict): distribution parameters to pass to the log-function
x (float): sample point
bandwidth (optional float): initial guess of the slice width
Returns:
float: sample from the log-distribution
Reference:
Neal, Radford. Ann. Statist. Volume 31, Number 3 (2003), 705-767.
http://projecteuclid.org/euclid.aos/1056562461
"""
# Uniform sample 'vertically' in the range [0,P(x)]
log_z = log_p(x,theta) - np.random.exponential(1)
# Initial slice bounds
L = x - bandwidth * np.random.rand()
R = L + bandwidth
# step the slice out
while log_p(L,theta) > log_z:
L -= bandwidth
while log_p(R,theta) > log_z:
R += bandwidth
# Uniform sample 'horizontally' between [L,R]
xprime = L + (R-L) * np.random.rand()
while log_p(xprime, theta) < log_z: # reject if sample is outside the slice
if xprime < x: # narrow the interval
L = xprime
else:
R = xprime
xprime = L + (R-L) * np.random.rand() # try again
return xprime
In [3]:
def log_gamma(x, theta):
""" Log of the gamma distribution PDF """
alpha = theta['alpha']
beta = theta['beta']
return (alpha - 1) * np.log(x) - beta * x
In [4]:
N = 5000
alpha = 9
beta = 2
samples = [1] # initial guess
for _ in range(N): # sample loop
samples.append( SliceSample(log_gamma, {'alpha':alpha,'beta':beta}, samples[-1]) )
X = np.linspace(0,20,100)
plt.hist(samples, bins=50, normed=True, histtype='stepfilled', alpha=0.4, label="Samples")
plt.plot(X, [gamma(alpha,scale=1./beta).pdf(x) for x in X], color='k', ls='--', label="PDF")
plt.legend(loc="best");