Today: Approximate Bayesian Computation
Reading:
Next two weeks:
Suppose we have data \(y_1,\ldots, y_n\) that we believe can be described by a probability model with parameters \(\theta\).
We also have a prior distribution on the parameters \(\theta\), describing our belief about the values of those parameters before seeing any of the data.
\[ \begin{align*} y_i \mid \theta &\sim P(y_i \mid \theta), \quad i = 1,\ldots, n\\ \theta & \sim \pi \end{align*} \]
For example:
This posterior distribution is the Bayesian analog of a confidence interval for a normal mean.
Finance:
Epidemiology
By applying Bayes’ rule, we can compute the posterior distribution of the parameters given the data: \[ \begin{align*} P(\theta \mid y_1,\ldots, y_n) &= \frac{P(y_1,\ldots, y_n \mid \theta)P(\theta)}{P(y_1,\ldots, y_n)} \end{align*} \]
Inputs:
Sampling: for \(i = 1,\ldots, N\):
Why does this work?
Bayesian analysis for a Gamma-Poisson model:
Model is: \[ \begin{align*} Y_i &\sim \text{Poisson}(\theta), \quad i = 1,\ldots, n \\ \theta &\sim \text{Gamma}(\alpha, \beta) \end{align*} \]
By Bayes rule, we can find in closed form that the posterior, \(P(\theta \mid Y_1, \ldots, Y_n)\) has a \(\text{Gamma}(\sum_{i=1}^n Y_i + \alpha, n + \beta)\) distribution.
Let’s pretend we can’t do that though, and try using the sampling method we described on the previous slide.
Set up the function:
## We call this "ebc" because it is exactly sampling from the
## posterior ("exact Bayesian computation"). ABC will be a small
## modification of this method.
generate_ebc_sample <- function(observed_data,
prior_distribution,
data_generating_function) {
while(TRUE) {
theta <- prior_distribution()
y <- data_generating_function(theta)
if(all(y == observed_data)) {
return(theta)
}
}
}
Sampling from:
What if you have more than one sample?
We still have
n_samples <- 4
data_generating_function <- function(theta) rpois(n = n_samples, lambda = theta)
observed_data <- rep(3, n_samples)
generate_ebc_sample(observed_data, prior_distribution, data_generating_function)
## [1] 2.662207
system.time(replicate(n = 1000, generate_ebc_sample(observed_data, prior_distribution, data_generating_function)))
## user system elapsed
## 5.544 0.011 5.556
(Try changing n_samples
to something bigger on your own
computer…)
Therefore:
Inputs:
Sampling: for \(i = 1,\ldots, N\):
This method generates approximate samples from the posterior distribution
Set up a function for the approximate version of ABC:
generate_abc_sample <- function(observed_data,
summary_statistic,
prior_distribution,
data_generating_function,
epsilon) {
while(TRUE) {
theta <- prior_distribution()
y <- data_generating_function(theta)
if(abs(summary_statistic(y) - summary_statistic(observed_data)) < epsilon) {
return(theta)
}
}
}
Let’s see what happens with the approximate version:
We still have
n_samples <- 10
prior_distribution <- function() rgamma(n = 1, shape = 1, rate = 1)
data_generating_function <- function(theta) rpois(n = n_samples, lambda = theta)
observed_data <- rep(3, n_samples)
summary_statistic <- mean
epsilon <- .1
generate_abc_sample(observed_data, summary_statistic, prior_distribution, data_generating_function, epsilon)
## [1] 2.226695
posterior_samples <- replicate(n = 1000,
generate_abc_sample(observed_data,
summary_statistic,
prior_distribution,
data_generating_function,
epsilon))
system.time(
replicate(n = 1000,
generate_abc_sample(observed_data,
summary_statistic,
prior_distribution,
data_generating_function,
epsilon))
)
## user system elapsed
## 0.931 0.002 0.933
Checking on the posterior means and variances:
Checking on the posterior distributions:
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.