Computational Posterior

17. Computational Posterior#

(17.1)#\[\begin{align} \beta &\sim \text{Beta}(2,5) ; \; \gamma \sim \text{Beta}(2,8) \\ S_{0}&=990 ; I_{0} = 10; R_{0} = 0\\ S,I,R,\Delta I &= ODE( [S_{0},I_{0}, R_{0}; \beta, \gamma] ) \\ (\Delta i)_{t} &\sim \text{Pois}( \Delta I_{t} ) \end{align}\]
(17.2)#\[\begin{align} p(\beta, \gamma) &= p(\beta) \times p(\gamma) \\ &= \frac{1}{\text{Beta}(2,5)} \beta^{2-1} (1-\beta)^{5-1} \times \frac{1}{\text{Beta}(2,8)} \gamma^{2-1} (1-\gamma)^{8-1} \end{align}\]
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import beta

# Parameters for the two Beta distributions
a1, b1 = 2, 5  # For X
a2, b2 = 2, 8  # For Y

# Grid over [0,1] x [0,1]
x = np.linspace(0., 0.6, 200)
y = np.linspace(0, 0.6, 200)
X, Y = np.meshgrid(x, y)

# Compute the marginal PDFs
f_X = beta.pdf(X, a1, b1)
f_Y = beta.pdf(Y, a2, b2)

# Compute the joint PDF (independent case)
Z = f_X * f_Y

# Plot
fig = plt.figure(figsize=(8, 6))
cp = plt.contourf(X, Y, Z, levels=20)
plt.colorbar(cp)
plt.title(r'Joint probability density for $\beta$ and $\gamma$')
plt.xlabel(r'$\beta$ ~ Beta(2,5)')
plt.ylabel(r'$\gamma$ ~ Beta(2,8)')
plt.tight_layout()
plt.show()
_images/eb8a27f2d43dc6c296be9f5f97c0d132571be8c6c7553db86fe25bf6b889bd53.png
(17.3)#\[\begin{align} X &\sim f_{X} \\ supp(X) &= [a,b] \\ \end{align}\]
(17.4)#\[\begin{align} P(X < x) &= \int_{a}^{x} f_{X} \; dx \\ &\approx \sum_{x_{i} \in [a, a + (x-a)/N, a + 2*(x-a)/N, \cdots, x] } f(x_{i}) \left( \frac{x-a}{N} \right) \\ \end{align}\]
(17.5)#\[\begin{align} P(X < x) &= \sum_{x_{i} \in [a, a + (x-a)/N, a + 2*(x-a)/N, \cdots, x] } f(x_{i}) \Delta x \\ \Delta x = \frac{x-a}{N} \end{align}\]
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import beta

# Beta distribution parameters
a, b = 2, 5
x_val = 0.6
N = 8

x_grid = np.linspace(0, 1, N)
delta_x = x_grid[1] - x_grid[0]
pdf_vals = beta.pdf(x_grid, a, b)

# Mask for x <= x_val
mask = x_grid <= x_val

# Approximate the CDF with Riemann sum
cdf_approx = np.sum(pdf_vals[mask]) * delta_x
cdf_true = beta.cdf(x_val, a, b)

# --- Plot ---
fig, ax = plt.subplots(figsize=(8, 5))

# Plot PDF as smooth curve
ax.plot(x_grid, pdf_vals, label='True PDF $f(x)$', color='navy', linewidth=2)

# Plot rectangles (left Riemann sum)
for xi, fi in zip(x_grid[mask], pdf_vals[mask]):
    ax.add_patch(plt.Rectangle((xi, 0), delta_x, fi, color='orange', alpha=0.5))

# Vertical line at x = 0.6
ax.axvline(x_val, color='red', linestyle='--', label=r'$x = 0.6$')

# Labels and legend
ax.set_xlabel('x')
ax.set_ylabel('PDF $f(x)$')
ax.set_title('Riemann Sum Approximation of $P(X < 0.6)$ for Beta(2,5)')
ax.legend()
ax.grid(True)


ax2 = ax.twinx()
x_grid = np.linspace(0, 1, 500)

cdf_vals = beta.pdf(x_grid, a, b)
ax2.plot(x_grid, cdf_vals, 'g--', label='True CDF $P(X < x)$')
ax2.set_ylabel('CDF')
ax2.legend(loc='lower right')

plt.tight_layout()
plt.show()
_images/9dc26897ad59590c20afb3fb16fbba9050989734f3ce2b0beb8337e2f5530c54.png
(17.6)#\[\begin{align} p( \beta, \gamma | \mathcal{D} ) = \frac{p(\mathcal{D} |\beta, \gamma ) p(\beta, \gamma)}{ \int_{\beta=0}^{\infty} \int_{\gamma=0}^{\infty} p(\mathcal{D} |\beta, \gamma ) p(\beta, \gamma) \; d \gamma d \beta } \\ \end{align}\]
(17.7)#\[\begin{align} p(\mathcal{D} |\beta, \gamma ) = \text{Pois}( \Delta I_{1} )[(\Delta i)_{1}] \times \text{Pois}( \Delta I_{2} )[(\Delta i)_{2}] \times \cdots \times \text{Pois}( \Delta I_{T} )[(\Delta i)_{T}] = \prod_{t=1}^{T} \text{Pois}( \Delta I_{t} )[(\Delta i)_{t}] \\ \end{align}\]
(17.8)#\[\begin{align} p(\mathcal{D} |\beta, \gamma )p(\beta, \gamma) &= \prod_{t=1}^{T} \text{Pois}( \Delta I_{t} )[(\Delta i)_{t}] \times \left[ \frac{1}{\text{Beta}(2,5)} \beta^{2-1} (1-\beta)^{5-1} \times \frac{1}{\text{Beta}(2,8)} \gamma^{2-1} (1-\gamma)^{8-1} \right] \end{align}\]
(17.9)#\[\begin{align} \int_{\beta=0}^{\infty} \int_{\gamma=0}^{\infty} p(\mathcal{D} |\beta, \gamma ) p(\beta, \gamma) \; d \gamma d \beta & = \int_{\beta=0}^{\infty} \int_{\gamma=0}^{\infty} p(\mathcal{D} |\beta, \gamma ) p(\beta) p(\gamma) \; d \gamma d \beta \\ & = \int_{\beta=0}^{\infty} p(\beta) \left[ \int_{\gamma=0}^{\infty} p(\mathcal{D} |\beta, \gamma ) p(\gamma) \; d \gamma \right] d \beta \\ \end{align}\]
(17.10)#\[\begin{align} \int_{\beta=0}^{\infty} p(\beta) \left[ \int_{\gamma=0}^{\infty} p(\mathcal{D} |\beta, \gamma ) p(\gamma) \; d \gamma \right] d \beta \\ \approx \sum_{\beta \in B} p(\beta) \Delta \beta \left[ \sum_{\gamma \in G} p(\mathcal{D} |\beta, \gamma ) p(\gamma) \Delta \gamma \; \right] \\ \end{align}\]

where \(B\) is some discrete set of points over the support of \(\beta\) and \(G\) is a discrete set of points over the support of \(\gamma\).

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats

# Simulate "true" data
beta_true = 0.4
gamma_true = 0.1
N = 1000
I0 = 10
R0 = 0
S0 = N - I0 - R0
T = 30

S = [S0]
I = [I0]
R = [R0]

for t in range(T):
    new_infected = beta_true * S[-1] * I[-1] / N
    new_recovered = gamma_true * I[-1]
    
    S.append(S[-1] - new_infected)
    I.append(I[-1] + new_infected - new_recovered)
    R.append(R[-1] + new_recovered)

sigma = 50
I_obs = np.array(I) + np.random.normal(0, sigma, size=(T+1,))

# Define grid
beta_grid = np.linspace(0.3, 0.5, 30)
gamma_grid = np.linspace(0.08, 0.12, 30)

posterior = np.zeros((len(beta_grid), len(gamma_grid)))

# Prior distributions
beta_prior  = scipy.stats.beta(2,5)
gamma_prior = scipy.stats.beta(2,8)

# Evaluate posterior
for i, beta in enumerate(beta_grid):
    for j, gamma in enumerate(gamma_grid):
        
        # simulate model
        S_pred = [S0]
        I_pred = [I0]
        R_pred = [R0]
        
        for t in range(T):
            new_infected = beta * S_pred[-1] * I_pred[-1] / N
            new_recovered = gamma * I_pred[-1]
            
            S_pred.append(S_pred[-1] - new_infected)
            I_pred.append(I_pred[-1] + new_infected - new_recovered)
            R_pred.append(R_pred[-1] + new_recovered)
        
        I_pred = np.array(I_pred)
        
        # likelihood
        log_likelihood = np.sum(scipy.stats.norm(I_pred, sigma).logpdf(I_obs))
        
        # prior
        log_prior_beta  = beta_prior.logpdf(beta)
        log_prior_gamma = gamma_prior.logpdf(gamma)
        
        log_prior = log_prior_beta + log_prior_gamma
        
        posterior[i,j] = np.exp(log_likelihood + log_prior)

# Normalize posterior
d_beta = beta_grid[1] - beta_grid[0]
d_gamma = gamma_grid[1] - gamma_grid[0]

posterior *= d_beta * d_gamma
posterior /= np.sum(posterior)

# Plot posterior
plt.figure(figsize=(8,6))
B, G = np.meshgrid(beta_grid, gamma_grid, indexing='ij')
plt.contourf(B, G, posterior, levels=20)
plt.xlabel(r'$\beta$')
plt.ylabel(r'$\gamma$')
plt.title('Grid Posterior for SIR Parameters (Informative Prior)')
plt.colorbar(label='Posterior Density')
plt.plot(beta_true, gamma_true, 'rx', markersize=10, label='True value')
plt.legend()
plt.show()
_images/1702e603f3f82f49b498e15031ce596c2ca39263903ad6c6bf3d7e843620e179.png