An example using DNest4
Here we show a standalone example of using DNest4 to
estimate the parameters of a straight line model in data with Gaussian noise. The
data and model used in this example are defined in createdata.py
, which can be downloaded
from here. The
script shown below can be downloaded from here.
Example code
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Example of running DNest4 to fit the parameters of a straight line.
"""
from __future__ import print_function, division
import os
import sys
import numpy as np
# import DNest4
from dnest4 import randh, wrap
import dnest4
# import model and data
from createdata import *
LN2PI = np.log(2.*np.pi)
LNSIGMA = np.log(sigma)
# define prior range values
cmin = -10. # lower range on c (the same as the uniform c prior lower bound)
cmax = 10. # upper range on c (the same as the uniform c prior upper bound)
mmu = 0. # mean of the Gaussian prior on m
msigma = 10. # standard deviation of the Gaussian prior on m
# Create model class
class DNest4Model(object):
"""
Specify the model in Python.
"""
def __init__(self):
"""
Parameter values *are not* stored inside the class
"""
pass
def from_prior(self):
"""
Draw points from the prior distribution.
Returns:
:class:`np.ndarray`: a numpy array containing the parameter values.
"""
m = np.random.normal(mmu, msigma)
c = np.random.uniform(cmin, cmax)
return np.array([m, c])
def perturb(self, params):
"""
Perturb the current parameters by proposing a new position. This takes a numpy array of
parameters as input, and modifies it in-place. In just perturbs one parameter at a time.
Args:
params (:class:`np.ndarray`): the current parameters (this is modified by the function)
Returns:
float: the natural logarithm of the Metropolis-Hastings proposal ratio.
"""
logH = 0.0 # log of the Metropolis-Hastings prior x proposal ratio
# randomly choose which parameter to perturb
which = np.random.randint(len(params))
mmu = 0.
msigma = 10.
if which == 0:
# update H for Gaussian prior
logH -= -0.5*((params[which]-mmu)/msigma)**2
params[which] += 1.*randh() # scale factor of 1. (randh is a heavy-tailed distribution to occasionally sample distant values, although this isn't really required in this case)
if which == 0:
# update H for Gaussian prior
logH += -0.5*((params[which]-mmu)/msigma)**2
else:
# wrap c value so that it stays within the prior range
params[which] = wrap(params[which], cmin, cmax)
return logH
def log_likelihood(self, params):
"""
Gaussian sampling distribution.
"""
m, c = params # unpack parameters
norm = -0.5*M*LN2PI - M*LNSIGMA
chisq = np.sum(((data - straight_line(x, m, c))/sigma)**2)
return norm - 0.5*chisq
# Create a model object and a sampler
model = DNest4Model()
sampler = dnest4.DNest4Sampler(model, backend=dnest4.backends.CSVBackend(".", sep=" "))
# Set up the sampler. The first argument is max_num_levels
gen = sampler.sample(max_num_levels=30, num_steps=1000, new_level_interval=10000,
num_per_step=10000, thread_steps=100, num_particles=5, lam=10, beta=100)
# Do the sampling (one iteration here = one particle save)
for sample in enumerate(gen):
pass
# Run the postprocessing to get marginal likelihood and generate posterior samples
logZdnest4, infogaindnest4, _ = dnest4.postprocess(plot=False);
postsamples = np.loadtxt('posterior_sample.txt')
print('Marginalised evidence is {}'.format(logZdnest4))
print('Number of posterior samples is {}'.format(postsamples.shape[0]))
# plot posterior samples (if corner.py is installed)
try:
import matplotlib as mpl
mpl.use("Agg") # force Matplotlib backend to Agg
import corner # import corner.py
except ImportError:
sys.exit(1)
fig = corner.corner(postsamples, labels=[r"$m$", r"$c$"], truths=[m, c])
fig.savefig('DNest4.png')
Running the code
A description of installing DNest4 is given here. If you have downloaded the createdata.py
and test_DNest4.py
scripts into the directory ${HOME}
, then you can run it using:
python test_DNest4.py
If you have Matplotlib installed then the script will produce a plot of the posterior distributions on the straight line parameters $m$ and $c$.
A Python 3 Docker image with DNest4 installed is available, which can be used with:
docker run -it -v ${HOME}:/work mattpitkin/samplers:python3
to enter an interactive container, and then within the container the test script can be run with:
python test_DNest4.py