Spaces:
Sleeping
Sleeping
File size: 6,638 Bytes
406ac25 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
from src.utility_functions import log_pi_lambda, log_pi_t
import numpy as np
def update_lambda(lam, t, s, i, P, sigma, alpha, beta, phi):
# This function updates the parameter vector lambda.
# INPUT:
# - lam: array of the values of lambda;
# - t: array of the breakpoints;
# - s: array of susceptible individuals during time;
# - i: array of infected individuals during time;
# - P: total number of individuals;
# - sigma: algorithm parameter for the proposal of a new candidate lambda;
# - alpha, beta: hyperparameters of the prior of lambda;
# - phi parameter phi of the model.
# OUTPUT:
# - lam: update array;
# - accept: number of acceted candidates.
# NOTES: The update is done component-wise in a sequential manner.
current = np.copy(lam) # Get the current state of the chain.
candidate = np.copy(current) # Initialize the new candidate.
# For every component of the parameter vector, we tweak such component
# according to the chosen proposal and then update the chain according
# to the computed acceptance rate.
accepted = 0 # Initialize the count of accepted candidates.
for j in range(current.shape[0]):
# Tweak the j-th component.
candidate[j] = candidate[j] + sigma * np.random.normal()
# Compute the acceptance rate.
log_alpha = (log_pi_lambda(candidate, t, s, i, P, alpha, beta, phi)
- log_pi_lambda(current, t, s, i, P, alpha, beta, phi))
# If the candidate is accepted, we move the chain (current = candidate)
# and increase the count of accepted candidates. Otherwise, we reject
# the candidate and the chain does not move from the current state
# (candidate = current).
if log_alpha > np.log(np.random.uniform()):
current = np.copy(candidate)
accepted = accepted + 1
else:
candidate = np.copy(current)
return current.reshape(-1, 1), accepted
def update_t(lam, t, s, i, P, M, phi):
# This function updates the parameter vector lambda.
# INPUT:
# - lam: array of the values of lambda;
# - t: array of the breakpoints;
# - s: array of susceptible individuals during time;
# - i: array of infected individuals during time;
# - P: total number of individuals;
# - M: algorithm parameter for the proposal of a new candidate t;
# - phi parameter phi of the model.
# OUTPUT:
# - lam: update array;
# - accept: number of acceted candidates.
# NOTES: The update is done component-wise in a sequential manner.
current = np.copy(t) # Get the current state of the chain.
candidate = np.copy(current) # Initialize the new candidate.
# For every component of the parameter vector, we tweak such component
# according to the chosen proposal and then update the chain according
# to the computed acceptance rate.
accepted = 0 # Initialize the count of accepted candidates.
for j in range(current.shape[0]):
# Tweak the j-th component.
candidate[j] = candidate[j] + np.random.choice(np.arange(-M, M + 1))
# Compute the acceptance rate.
log_alpha = (log_pi_t(lam, candidate, s, i, P, phi)
- log_pi_t(lam, current, s, i, P, phi))
# If the candidate is accepted, we move the chain (current = candidate)
# and increase the count of accepted candidates. Otherwise, we reject
# the candidate and the chain does not move from the current state
# (candidate = current).
if log_alpha > np.log(np.random.uniform()):
current = np.copy(candidate)
accepted = accepted + 1
else:
candidate = np.copy(current)
return current.reshape(-1, 1), accepted
def mcmc_sampler(s, i, d, P, n_iterations, burnin, M, sigma,
alpha, beta, a, b, phi):
# This function implement the hybrid MCMC sampler.
# INPUT:
# - s: array of susceptible individuals during time;
# - i: array of infected individuals during time;
# - d: number of breakpoints;
# - P: total number of individuals;
# - n_iterations: number of iterations for the algorithm;
# - burnin: number of burnin iterations to discard;
# - M: algorithm parameter for the proposal of a new candidate t;
# - sigma: algorithm parameter for the proposal of a new candidate lambda;
# - alpha, beta: hyperparameters of the prior of lambda;
# - a, b: hyperparameters of the prior of p;
# - phi: parameter phi of the model.
# OUTPUT:
# - p: simulated chain for the probability of removal from
# infected population;
# - lam: simulated chain for lambda;
# - t: simulated chain for the breakpoints.
T = s.shape[0] - 1 # Index of the final time instant.
# Initialize the parameters.
# The initial value of p is drawn from the prior distribution.
p = np.random.beta(a, b, size=(1, 1))
# Each of the d breakpoints (t_i) is drawn randomly (without replacement)
# between 1 and T-1. The obtained vector is then sorted to make sure
# that t_1 < t_2 < ... < t_d.
t = np.sort(np.random.choice(np.arange(1, T), size=d-1, replace=False))
t = t.reshape(-1, 1)
# Each of the lambda_i's is drawn independently from
# its prior distribution.
lam = np.random.gamma(alpha, beta)
lam = lam.reshape(-1, 1)
# Compute the hyperparameters of the posterior of p.
a_new = a + i[0] - i[-1] + s[0] - s[-1]
b_new = b + np.sum(i[1:]) + s[-1] - s[0]
# Initialize the count of accepted candidates for lambda and t.
a_lam = 0
a_t = 0
# Run the chain
for _ in range(n_iterations):
# Update p by sampling from its posterior.
p = np.hstack((p, np.random.beta(a_new, b_new, size=(1, 1))))
# Update lam via Metropolis-Hastings step.
new_lam, accepted_lam = update_lambda(lam[:, -1], t[:, -1], s, i, P,
sigma, alpha, beta, phi)
# Update t via Metropolis-Hastings step.
new_t, accepted_t = update_t(lam[:, -1], t[:, -1], s, i, P, M, phi)
lam = np.hstack((lam, new_lam))
t = np.hstack((t, new_t))
# Update the counts of accepted candidates for lambda and t.
a_lam = a_lam + accepted_lam
a_t = a_t + accepted_t
# Compute the acceptance rates for lambda and t.
lam_ar = a_lam / n_iterations / d
t_ar = a_t / n_iterations / (d-1)
# Discard burn-in iterations.
p = p[:, burnin:]
lam = lam[:, burnin:]
t = t[:, burnin:]
return p, lam, t, lam_ar, t_ar
|