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
download
#!/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:
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: