Algorithm 6.1 MCMC for the Posterior Distribution
import numpy as np
import matplotlib.pyplot as plt
def propose(x):
u = delta*np.random.uniform(-1,1)
y = x+u
# keep it in [0,1]
if( y<0 ):
y = -y
elif( y > 1 ):
y = 2 - y
return y
def lny(t,m):
return m*(t-1)+0.01
def sumSquares(m):
acc = 0
for i in range(len(tdat)):
acc += (ydat[i] - lny(tdat[i],m))**2
return acc
def prior(m):
y = (1/((2*np.pi)**0.5*sigma_m))*np.exp(-0.5*((m-mu_m)/sigma_m)**2)
return y
def prob_obsGiven_m(m):
y = (1/((2*np.pi)**0.5*sigma_l)**5)*np.exp(-sumSquares(m)/(2*sigma_l**2))
return y
def f(m):
y = prob_obsGiven_m(m)
y *= prior(m)
return y
delta = 0.05
tdat = [1,5,10,15,20] #in days
ydat = [.01,0.1,0.9,4,9] #in ln(increase in gm)
## normal prior with a known sigma
mu_m = 0.20
sigma_m = 0.04
## normal likelihood, fixed sigma
sigma_l = 0.6
trace = []
x = np.random.normal(mu_m,sigma_m)
fx = f(x)
burnin = 1000
for i in range(100000):
y = propose(x)
fy = f(y)
h = fy/fx
u = np.random.uniform()
if( u < h ):
x = y
fx = fy
if( i > burnin):
trace.append(x)
meanValue = np.mean(trace)
variance = np.var(trace)
print("mean",meanValue,"var",variance)
plt.hist(trace,bins=60,density=True)
plt.show()
Algorithm 6.2 Pymc3 for the Coin Tossing Problem
import numpy as np
import pymc3 as pm
import scipy.stats as stats
from scipy.stats import beta
import matplotlib.pyplot as plt
data=np.array([1,1,1,1,1,1,1,0,0,0]) #our observation
#print(sum(data)/float(len(data)))
with pm.Model() as model:
# set a Beta prior on the Bernoulli parameter
theta=pm.Beta('theta', alpha=3, beta=3)
# set a Bernoulli likelihood for the data
y = pm.Bernoulli("obs", p = theta, observed = data)
# inference step
step=pm.Metropolis()
trace=pm.sample(18000, step=step,random_seed=123)
burned_trace=trace[1000:]
plt.hist(burned_trace["theta"], bins=40, histtype='stepfilled',
density=True,color="darkgrey")
x=np.arange(0,1.04,0.04)
y = beta.pdf(x,10,6) #plot beta(10,6)
plt.plot(x, y, color='#FF7F00')
xmax = 0.642
plt.vlines(xmax,0.3, 3.5, linestyle='--', label=r"MAP estimate", color='red')
plt.text(xmax+0.025,0.40, "MAP", color='red', fontsize=12)
plt.text(xmax-0.04,0.08,str(xmax), color='red', fontsize=12)
plt.text(0.82, 2.1, "beta(10,6)", color='black')
plt.hlines(2.15,0.755,0.80)
plt.title(
"Pymc3 MCMC histogram for heads probability theta",pad=10,fontsize=14)
plt.xlabel("theta")
#plt.savefig("pymcSeventenfig.png")
# Plot a simple line chart without any feature
plt.plot(x, y)
plt.show()
Algorithm 6.3 Pymc3 for the Wheat Growth Problem
import numpy as np
import pymc3 as pm
import arviz as az
import matplotlib.pyplot as plt
#import scipy.stats as stats
#from scipy.stats import norm
mu_m = 0.20; sig_m = 0.04;
tdat = np.array([1.,5.,10.,15.,20.]) #in days
ydat = np.array([0.01,0.1,0.9,4.,9.]) #in ln(increase in gm)
sigma_l = 0.6 # normal likelihood, fixed sigma
with pm.Model() as model:
# set a normal prior on the parameter m
m = pm.Normal('m',mu_m,sig_m)
# set the likelihood for the data
lny = 0.01+m*(tdat-1)
y = pm.Normal('y',mu=lny,sd=sigma_l,observed=ydat)
# inference step
step=pm.Metropolis()
trace=pm.sample(20000, step=step,random_seed=123)
with model:
az.plot_posterior(trace,var_names=['m'])
plt.title(
"Pymc3 MCMC histogram for Growth Rate m",pad=10,fontsize=14)
plt.savefig("pymcGrowthfig.png")
plt.show()
Algorithm 6.4 Gibbs Sampling
import numpy as np
import matplotlib.pyplot as plt
def fXY(y):
return np.random.normal(rho*y,var)
def fYX(x):
return np.random.normal(rho*x,var)
np.random.seed(227)
rho = 0.5
var = 1-rho**2
x=[]; y=[]
x.append(1); y.append(1)
for i in range(20):
x.append(fXY(y[i])); #sample x given current y
y.append(fYX(x[i+1])); #sample y given new x
xa = np.linspace(-3,3,100)
ya = np.linspace(-3,3,100)
X,Y = np.meshgrid(xa,ya)
Z = (1/(2*np.pi*np.sqrt(var)))*np.exp((-1/(2*var))*(X**2-2*rho*X*Y+Y**2))
#do axes
plt.hlines(0,-3,3, color='k'); #x-axis
plt.vlines(0,-3,3, color='k'); #y-axis
plt.contour(X, Y, Z, colors='black')
#plot a few points
plt.scatter(x,y,color='red')
#plot two steps
plt.scatter(x[0],y[0],color='orange')
plt.scatter(x[1],y[0],color='orange');
plt.hlines(y[0],x[0],x[1],color='blue');
plt.scatter(x[1],y[1],color='orange');
plt.vlines(x[1],y[0],y[1],color='blue')
plt.suptitle("Density plot generated by Gibbs sampling")
#plt.savefig("gibbsfig")
plt.show()
Algorithm 6.5 Sample Mean Estimator
import numpy as np
import matplotlib.pyplot as plt
def f1(x): # on [0,infty)
return 1/((x+1)**2)
def f2(x):
return -2+(x-2)**2 + 1/np.sqrt(x)
def exponDen(x,lam):
return lam*np.exp(-lam*x)
def exponSample(lam):
U = np.random.uniform()
return (-1/lam)*np.log(1-U)
nTrials = 1000
lam = 0.1
acc = 0; # accumulator
for i in range(nTrials):
U = exponSample(lam)
acc += f1(U)/exponDen(U,lam)
print("est=",acc/float(nTrials))
acc = 0
for i in range(nTrials):
U = np.random.uniform(0,4)
acc += 4*f2(U); # b-a=4
print("est=",acc/float(nTrials))
fig = plt.figure(figsize=(6.5,2.5))
x = np.linspace(0,40,100)
y = f1(x)
ax0=fig.add_subplot(121)
ax0.plot(x,y)
y = exponDen(x,lam)
ax0.plot(x,y)
plt.title("f(x)={\scriptsize\$}1/(x+1)\^{}2{\scriptsize\$}")
x = np.linspace(0,4,100)
y = f2(x)
ax1=fig.add_subplot(122)
ax1.plot(x,y)
y = [0.25]*len(x)
ax1.plot(x,y)
plt.title("f(x)={\scriptsize\$}-2+(x-2)\^{}2+\
(1/\\sqrt{\scriptsize\{}x{\scriptsize\}}){\scriptsize\$}")
plt.show()
Algorithm 6.6 Estimating a Double Integral
import numpy as np
import matplotlib.pyplot as plt
def fcn(x,y):
return np.sqrt(1-(x*x+y*y))
def q(x,y):
return 4/np.pi
def sample1(): #uniform over [0,1]x[0,1]
x = np.random.uniform()
y = np.random.uniform()
return x,y
def sample2(): #uniform over x^2+y^2<1 with rejection
while( True):
x,y = sample1()
if( x*x+y*y < 1):
break
return x,y
def sample3(): #uniform over x^2+y^2<1 directly
u1 = np.random.uniform()
u2 = np.random.uniform()
r = np.sqrt(u1); th = np.pi*u2/2
x = r*np.cos(th); y = r*np.sin(th)
return x,y
def integral(nTrials):
acc = 0
for i in range(nTrials):
x,y = sample3()
if( x*x + y*y > 1): #only used for sample2()
nTrials -= 1
continue
acc += fcn(x,y)/q(x,y)
est = acc/float(nTrials)
error = abs(est - np.pi/6)
return est,error
n = [1000,3000,5000,7000,9000,110000]
err = [0]*len(n)
for i in range(len(n)):
navg = 20
acc = 0
for j in range(navg):
est,error = integral(n[i])
acc += error
err[i] = np.log(acc/navg)
print(".",end="",flush=True)
#pcError = 100*err[i]/(np.pi/6)
#print("est=",est,"cf 1, pcError=",pcError)
ln = np.log(n)
plt.plot(ln,err)
plt.xlabel("log(n)")
plt.ylabel("log(error)")
plt.title("Error chart for $f(x)=\sqrt{1-(x*x+y*y)}$")
a,b = np.polyfit(ln,err,1)
print("a=",a)
ye = []
y5 = []
for i in range(len(n)):
ye.append(a*ln[i]+b)
y5.append(-0.5*ln[i]+b)
plt.plot(ln,ye)
plt.plot(ln,y5)
plt.show()
#pcError = 100*error/(np.pi/6)
#print("est=",est,"cf pi/6=",np.pi/6,"pcError=",pcError)
Algorithm 6.7 Estimating the Triple Integral for the 4-Sphere
import numpy as np
import matplotlib.pyplot as plt
def rho(x,y,z):
return 6/np.pi
def sample3():
r = (np.random.uniform())**0.333
phi = np.arccos(np.random.uniform())
theta = np.random.uniform(0,np.pi/2.)
x = r*np.sin(phi)*np.cos(theta)
y = r* np.sin(phi)*np.sin(theta)
z = r*np.cos(phi)
return x,y,z
def integral(nTrials):
acc = 0
for i in range(nTrials):
x,y,z = sample3()
acc += fcn2(x,y,z)/rho(x,y,z)
est = acc/nTrials
error = abs(est - exact)
return est,error
exact = 0.308552;
n = [1000,3000,5000,7000,9000,110000]
err = [0]*len(n)
for i in range(len(n)):
navg = 20; #number to average error over
acc = 0
for j in range(navg):
est,error = integral(n[i])
acc += error
err[i] = np.log(acc/navg)
print(".",end="",flush=True)
pcError = 100*error/exact
print("n=",n[i],"est=",est,"cf ",exact,"pcError=",pcError)
ln = np.log(n)
plt.plot(ln,err)
plt.xlabel("log(n)")
plt.ylabel("log(error)")
plt.title("Error chart for $f(x)=\sqrt{1-(x*x+y*y+z*z)}$")
a,b = np.polyfit(ln,err,1)
print("a=",a)
ye = []
y5 = []
for i in range(len(n)):
ye.append(a*ln[i]+b)
y5.append(-0.5*ln[i]+b)
plt.plot(ln,ye)
plt.plot(ln,y5)
plt.show()
Algorithm 6.8 Control Vaiate Method
##
# use cauchy on [-2,2] to approximate normal [-2,2]
##
import numpy as np
import matplotlib.pyplot as plt
def h1(x): #uniform on [-2,2]
return 0.25
def samp1():
u = np.random.uniform(-2,2)
return u
def normal(x,sigma):
a = 1/(sigma*np.sqrt(2*np.pi))
b = np.exp(-0.5*(x/sigma)**2)
return a*b
def cauchy(x):
return 1/(np.pi*(1+x*x))
sigma = 1
nTrials = 4000
acc = 0
for i in range(nTrials):
u = samp1()
acc += normal(u,sigma)/h1(u)
acc /= float(nTrials)
est = acc;
error = abs(est - 0.9545)
percentError = 100*(error/0.9545)
#print("straight est=",est,"cf. ",0.9545,"error=",error)
print("straight est=",est,"cf. ",0.9545,"percenterror=",percentError)
G = (2/np.pi)*np.arctan(2); #0.70483
acc = 0
for i in range(nTrials):
u = samp1()
acc += (normal(u,sigma) - cauchy(u))/h1(u)
acc /= float(nTrials)
est = G + acc;
error = abs(est - 0.9545)
percentError = 100*(error/0.9545)
#print("est=",est,"cf. ",0.9545,"error=",error)
print("est=",est,"cf. ",0.9545,"percenterror=",percentError)
"""
x = np.linspace(-2,2,100)
y = normal(x,sigma)
plt.plot(x,y,label="normal density")
y = cauchy(x)
plt.plot(x,y,label="Cauchy density")
y = [h1(x)]*len(x)
plt.plot(x,y,label="uniform density")
plt.legend()
plt.suptitle("The Cauchy density as control variate for the normal");
#plt.savefig("cauchyasCVfig.png")
plt.show()
"""
Algorithm 6.9 Importance Sampling Method in 1d
##
# use normal to estimate integral of cauchy on [-2,2]
##
import numpy as np
import matplotlib.pyplot as plt
def qu(x): #uniform on [-2,2]
return 0.25
def sampU(): #uniform on [-2,2=]
u = np.random.uniform(-2,2)
return u
def qn(x): #normal density on [-2,2]
a = 1/(sigma*np.sqrt(2*np.pi))
b = np.exp(-0.5*(x/sigma)**2)
c = 0.9545; # integral normal(x) [-2,2]
return a*b/c
def sampN(): #from normal on [-2,2]
while( True ):
x = np.random.normal()
if( x<2 and x > -2 ):
break
return x
def normal(x,sigma):
a = 1/(sigma*np.sqrt(2*np.pi))
b = np.exp(-0.5*(x/sigma)**2)
return a*b
def cauchy(x):
return 1/(np.pi*(1+x*x))
delta = 0.1
def mcmcNormal(x): #mcmc normal samples from [-2,2]
y = x-delta + 2*delta*np.random.uniform()
if( y>2 ):
y = 4-y
elif( y < -2 ):
y = -4-y
h = normal(y,sigma)/normal(x,sigma)
u = np.random.uniform()
if( u < h):
x = y
return x
sigma = 1
exact = (2/np.pi)*np.arctan(2)
nTrials = 40000
Q = 0
for i in range(nTrials):
x = np.random.uniform(-2,2)
Q += normal(x,sigma)
Q = 4*Q/float(nTrials)
print("Q=",Q,"cf. 0.9545")
nTrials = 400
acc = 0
for i in range(nTrials):
u = sampU()
acc += cauchy(u)/qu(u)
est = acc/float(nTrials)
error = abs(est - exact)
pcError = 100*error/exact
print(nTrials,"trials uniform sampling:",'%.6f'%est,"cf. ",
round(exact,6),"percenterror=",round(pcError,6))
acc = 0
for i in range(nTrials):
u = sampN()
acc += cauchy(u)/qn(u)
est = acc/float(nTrials)
error = abs(est - exact)
pcError = 100*error/exact
print(nTrials,"trials normal sampling:",'%.6f'%est,"cf. ",
round(exact,6),"percenterror=",round(pcError,6))
nTrials = 4000
acc = 0
x = 0
for i in range(nTrials):
x = mcmcNormal(x)
acc += cauchy(x)/qn(x)
est = acc/float(nTrials)
error = abs(est - exact)
pcError = 100*error/exact
print(nTrials,"trials mcmc w/exact Q:",'%.6f'%est,"cf. ",
round(exact,6),"percenterror=",round(pcError,6))
acc = 0; Q = 0
x = 0
for i in range(nTrials):
x = mcmcNormal(x)
acc += cauchy(x)/normal(x,sigma)
u = np.random.uniform(-2,2)
Q += normal(u,sigma)
Q = 4*Q/float(nTrials); #b-a = 4
print("Q=",Q,"cf. 0.9545")
est = Q*acc/float(nTrials)
error = abs(est - exact)
pcError = 100*error/exact
print(nTrials,"trials mcmc w/estimated Q:",'%.6f'%est,"cf. ",
round(exact,6),"percenterror=",round(pcError,6))
Algorithm 6.10 Importance Sampling Method in 2D
#
# with 30000 iterates: slant est=0.7644 cf 0.7627, pcError= 0.2261
#
import numpy as np
import matplotlib.pyplot as plt
def fcnR(x,y): # defined on triangle
return -1+1/np.sqrt(x*x+y*y)
def hUniform(x,y): #(1/2)*base*height = 1
return 1
def sampleUniform():
u1 = np.random.uniform()
u2 = np.random.uniform()
X = np.sqrt(2)*(1 - np.sqrt(u1))
Y = (np.sqrt(2)-X)*u2
return X,Y
def hSlant(x,y):
return np.sqrt(2)-x-y
def qSlant(x,y):
c = 6/2**1.5
return c*hSlant(x,y)
def sampleSlant():
u1 = np.random.uniform()
u2 = np.random.uniform()
X = np.sqrt(2)*(1 - u1**0.334)
Y = (np.sqrt(2)-X)*(1-u2**0.5)
return X,Y
delta = 0.1
def sampM(x,y):
while( True ):
ux = np.random.uniform()
uy = np.random.uniform()
xn = x-delta + 2*delta*ux
yn = y-delta + 2*delta*uy
if( xn < 0):
xn = -xn
if( yn < 0):
yn = -yn
if( xn+yn > np.sqrt(2)):
continue
break; #new point in D
h = hSlant(xn,yn)/hSlant(x,y)
u = np.random.uniform()
if( u < h):
x = xn; y = yn;
return x,y
## mmm ##
n = 30000;
x = [0.01,0,np.sqrt(2),0]
y = [0,np.sqrt(2),0,0.01]
#plt.plot(x,y)
uni = 0;
slant = 1;
mcmc = 0;
if( uni+slant+mcmc != 1 ):
print("exactly one of uni,slant,mcmc = 1 please")
quit()
acc=0; Q = 0;
x = 0.7; y = 0.7;
for i in range(n):
if( uni == 1 ):
x,y = sampleUniform()
acc += fcnR(x,y)/hUniform(x,y)
elif( slant== 1 ):
x,y = sampleSlant()
acc += fcnR(x,y)/qSlant(x,y)
else:
x,y = sampM(x,y)
acc += fcnR(x,y)/hSlant(x,y)
u,v = sampleUniform()
Q += hSlant(u,v); #area of triange = 1
#plt.scatter(x,y,color='black',s=8)
if( i%1000 == 0 ):
print(".",end="",flush=True)
if( mcmc == 1 ):
Q /= float(n)
print("Q=",Q,"cf ",2**1.5/6)
else:
Q = 1
est = Q*acc/float(n)
exact = 0.7627
error = abs(est - exact)
pcError = 100*error/exact
if( uni == 1 ):
print("unif est=",end="")
if( slant == 1 ):
print("slant est=",end="")
else:
print("mcmc est=",end="")
print(round(est,4),"cf 0.7627, pcError=",round(pcError,4))
#plt.show()
Algorithm 6.11 Estimating Against a Weight Function
import numpy as np
def f(x):
return x*x
def expWeight(x):
return np.exp(-0.5*x)
delta = 1
def sampM(x): # Metropolis sampling
u = np.random.uniform()
y = x-delta + 2*delta*u
if( y < 0 ):
y = -y
h = expWeight(y)/expWeight(x)
u = np.random.uniform()
if( u < h):
x = y
return x
nTrials = 100000
acc = 0; W = 0;
x = 1; # MCMC starter
for i in range(nTrials):
x = sampM(x)
acc += f(x)
u = np.random.uniform(0,10)
W += expWeight(u)
W = 10*W/float(nTrials); #b-a=10
print("W=",W,"cf. 2")
est = W*acc/float(nTrials)
exact = 16
error = abs(est - exact)
pcError = 100*error/exact
print("est=",est,"cf ",
exact," pcError",pcError)
Algorithm 6.12 Using an Arbitrary Non-negative Function
import numpy as np
def fcnR(x,y): #defined on triangle
return -1+1/np.sqrt(x*x+y*y)
def hUniform(x,y):
return 1; #(1/2)*base*height = 1
def sampleUniform():
u1 = np.random.uniform()
u2 = np.random.uniform()
X = np.sqrt(2)*(1 - np.sqrt(u1))
Y = (np.sqrt(2)-X)*u2
return X,Y
def hSlant(x,y):
return np.sqrt(2)-x-y
delta = 0.1
def sampleM(x,y): #MCMC sample
while( True ):
ux = np.random.uniform()
uy = np.random.uniform()
xn = x-delta + 2*delta*ux
yn = y-delta + 2*delta*uy
if( xn < 0):
xn = -xn
if( yn < 0):
yn = -yn
if( xn+yn > np.sqrt(2)):
continue; # outside D
break; #new point in D
h = hSlant(xn,yn)/hSlant(x,y)
u = np.random.uniform()
if( u < h): #accept new
x = xn; y = yn;
return x,y
nTrials = 200000;
acc=0; Q = 0;
x = 0.7; y = 0.7; #starter points
for i in range(nTrials):
x,y = sampleM(x,y)
acc += fcnR(x,y)/hSlant(x,y)
u,v = sampleUniform()
Q += hSlant(u,v)/hUniform(u,v)
Q /= float(nTrials)
print("Q=",Q,"cf ",2**1.5/6)
est = Q*acc/float(nTrials)
exact = 0.7627
pcError = 100*abs(est - exact)/exact
print("mcmc est=",end="")
print(round(est,4),"cf 0.7627,pcError=",round(pcError,4))