An example using PyStan
Here we show a standalone example of using PyStan 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 emcee to fit the parameters of a straight line.
"""
from __future__ import print_function, division
import os
import sys
import numpy as np
import matplotlib as mpl
mpl.use("Agg") # force Matplotlib backend to Agg
# import PyStan
import pystan
# import model and data
from createdata import *
# Create model code
line_code = """
data {{
int<lower=0> N; // number of data points
real y[N]; // observed data points
real x[N]; // abscissa points
real<lower=0> sigma; // standard deviation
}}
parameters {{
// parameters for the fit
real m;
real c;
}}
transformed parameters {{
real theta[N];
for (j in 1:N)
theta[j] = m * x[j] + c; // straight line model
}}
model {{
m ~ normal({mmu}, {msigma}); // prior on m (gradient)
c ~ uniform({clower}, {cupper}); // prior on c (y-intercept)
y ~ normal(theta, sigma); // likelihood of the data given the model
}}
"""
# set the data and the abscissa
linear_data = {'N': M, # number of data points
'y': data, # observed data (converted from numpy array to a list)
'x': x, # abscissa points (converted from numpy array to a list)
'sigma': sigma} # standard deviation
Nsamples = 1000 # set the number of iterations of the sampler
chains = 4 # set the number of chains to run with
# dictionary for inputs into line_code
linedict = {}
linedict['mmu'] = 0.0 # mean of Gaussian prior distribution for m
linedict['msigma'] = 10 # standard deviation of Gaussian prior distribution for m
linedict['clower'] = -10 # lower bound on uniform prior distribution for c
linedict['cupper'] = 10 # upper bound on uniform prior distribution for c
sm = pystan.StanModel(model_code=line_code.format(**linedict)); # compile model
fit = sm.sampling(data=linear_data, iter=Nsamples, chains=chains); # perform sampling
la = fit.extract(permuted=True) # return a dictionary of arrays
# extract the samples
postsamples = np.vstack((la['m'], la['c'])).T
# plot posterior samples (if corner.py is installed)
try:
import corner # import corner.py
except ImportError:
sys.exit(1)
print('Number of posterior samples is {}'.format(postsamples.shape[0]))
fig = corner.corner(postsamples, labels=[r"$m$", r"$c$"], truths=[m, c])
fig.savefig('PyStan.png')
Running the code
A description of installing PyStan is given here. If you have downloaded the createdata.py
and test_PyStan.py
scripts into the directory ${HOME}
, then you can run it using:
python test_PyStan.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 PyStan 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_PyStan.py