Title: | Approximate Bayesian Inference via Sparse Grid Quadrature Evaluation (BISQuE) for Hierarchical Models |
---|---|
Description: | Implementation of the 'bisque' strategy for approximate Bayesian posterior inference. See Hewitt and Hoeting (2019) <arXiv:1904.07270> for complete details. 'bisque' combines conditioning with sparse grid quadrature rules to approximate marginal posterior quantities of hierarchical Bayesian models. The resulting approximations are computationally efficient for many hierarchical Bayesian models. The 'bisque' package allows approximate posterior inference for custom models; users only need to specify the conditional densities required for the approximation. |
Authors: | Joshua Hewitt |
Maintainer: | Joshua Hewitt <[email protected]> |
License: | GPL-3 |
Version: | 1.0.2 |
Built: | 2024-11-10 04:29:35 UTC |
Source: | https://github.com/jmhewitt/bisque |
Enhances mvQuad::createNIGrid by shifting and scaling a sparse integration grid, and evaluating the weight function at each of the grid nodes.
createLocScaleGrid( mu = 0, prec = 1, level = 2, quadError = FALSE, prec.chol = chol(prec) )
createLocScaleGrid( mu = 0, prec = 1, level = 2, quadError = FALSE, prec.chol = chol(prec) )
mu |
location at which grid should be centered |
prec |
"precision matrix" associated with the integration grid. When
building a sparse integration grid for a density, |
level |
accuracy level. This is typically number of grid points for the underlying 1D quadrature rule. [description from mvQuad::createNIGrid] |
quadError |
provide additional information about the grid points and
integration weights for the quadrature rule with |
prec.chol |
Upper-triangular Cholesky decomposition of precision matrix. |
mvQuad::createNIGrid
g = createLocScaleGrid(mu = c(1,0), prec = diag(c(1,.5)), level = 2 )
g = createLocScaleGrid(mu = c(1,0), prec = diag(c(1,.5)), level = 2 )
Evaluates mixture densities of the form
where the are (possibly negative) weights that sum to 1 and
are densities that are specified via parameters
, which are passed in the function argument
params
.
A unique feature of this function is that it is able to evaluate mixture
densities in which some of the mixture weights are negative.
dmix(x, f, params, wts, log = FALSE, errorNodesWts = NULL, ...)
dmix(x, f, params, wts, log = FALSE, errorNodesWts = NULL, ...)
x |
Points at which the mixture should be evaluated. If the density
is multivariate, then each row of |
f |
Density used in the mixture. The function should be defined so it
is can be called via |
params |
Matrix in which each row contains parameters that define
|
wts |
vector of weights for each mixture component |
log |
TRUE to return the log of the mixture density |
errorNodesWts |
list with elements |
... |
additional arguments to be passed to |
# evaluate mixture density at these locations x = seq(0, 1, length.out = 100) # density will be a mixture of beta distributions f = function(x, theta, log = FALSE) { dbeta(x, shape1 = theta[1], shape2 = theta[2], log = log) } # beta parameters are randomly assigned params = matrix(exp(2*runif(10)), ncol=2) # mixture components are equally weighted wts = rep(1/nrow(params), nrow(params)) # evaluate mixture density fmix = dmix(x = x, f = f, params = params, wts = wts) # plot mixture density plot(x, fmix, type='l', ylab = expression(f(x)), ylim = c(0, 4)) # plot component densities for(i in 1:length(wts)){ curve(f(x, params[i,]), col = 2, add = TRUE) }
# evaluate mixture density at these locations x = seq(0, 1, length.out = 100) # density will be a mixture of beta distributions f = function(x, theta, log = FALSE) { dbeta(x, shape1 = theta[1], shape2 = theta[2], log = log) } # beta parameters are randomly assigned params = matrix(exp(2*runif(10)), ncol=2) # mixture components are equally weighted wts = rep(1/nrow(params), nrow(params)) # evaluate mixture density fmix = dmix(x = x, f = f, params = params, wts = wts) # plot mixture density plot(x, fmix, type='l', ylab = expression(f(x)), ylim = c(0, 4)) # plot component densities for(i in 1:length(wts)){ curve(f(x, params[i,]), col = 2, add = TRUE) }
Approximates expectations of the form
using a weighted mixture
emix(h, params, wts, ncores = 1, errorNodesWts = NULL, ...)
emix(h, params, wts, ncores = 1, errorNodesWts = NULL, ...)
h |
Function for which the expectation should be taken. The function
should be defined so it is can be called via |
params |
Matrix in which each row contains parameters at which
|
wts |
vector of weights for each mixture component |
ncores |
number of cores over which to evaluate mixture. this function assumes a parallel backend is already registered. |
errorNodesWts |
list with elements |
... |
additional arguments to be passed to |
# density will be a mixture of betas params = matrix(exp(2*runif(10)), ncol=2) # mixture components are equally weighted wts = rep(1/nrow(params), nrow(params)) # compute mean of distribution by cycling over each mixture component h = function(p) { p[1] / sum(p) } # compute mixture mean mean.mix = emix(h, params, wts) # (comparison) Monte Carlo estimate of mixture mean nsamples = 1e4 component = sample(x = 1:length(wts), size = nsamples, prob = wts, replace = TRUE) x = sapply(component, function(cmp) { rbeta(n = 1, shape1 = params[cmp, 1], shape2 = params[cmp, 2]) }) mean.mix.mc = mean(x) # compare estimates c(emix = mean.mix, MC = mean.mix.mc)
# density will be a mixture of betas params = matrix(exp(2*runif(10)), ncol=2) # mixture components are equally weighted wts = rep(1/nrow(params), nrow(params)) # compute mean of distribution by cycling over each mixture component h = function(p) { p[1] / sum(p) } # compute mixture mean mean.mix = emix(h, params, wts) # (comparison) Monte Carlo estimate of mixture mean nsamples = 1e4 component = sample(x = 1:length(wts), size = nsamples, prob = wts, replace = TRUE) x = sapply(component, function(cmp) { rbeta(n = 1, shape1 = params[cmp, 1], shape2 = params[cmp, 2]) }) mean.mix.mc = mean(x) # compare estimates c(emix = mean.mix, MC = mean.mix.mc)
These data are used in the book "Computational Statistics" by G.H. Givens and J.A. Hoeting (2013). They are discussed in Chapter 7, Examples 7.2,7.3,7.8, and Exercise 7.2.
data(furseals)
data(furseals)
A data.frame with variables:
The census attempt
Number of pups captured in census attempt
Number of newly captured pups
As described by the authors:
Source: Richard Barker, University of Otago, New Zealand
Description: Data from a capture-recapture study conducted on the Otago Penninsula, South Island, New Zealand. Fur seal pups were marked and released during 7 census attempts in one season. The population is assumed closed. For each census attempt, the number of pups captured and the number of these captures corresponding to pups never previously caught are recorded.
https://www.stat.colostate.edu/computationalstatistics/
https://www.stat.colostate.edu/computationalstatistics/datasets.zip
data("furseals") str(furseals)
data("furseals") str(furseals)
Evaluates the inverse of the named link function at the locations
x
.
itx(x, link, linkparams)
itx(x, link, linkparams)
x |
Values at which to evaluate the inverse link function |
link |
Character vector specifying link function for which the
inverse link function should be evaluated. Supports |
linkparams |
Optional list of additional parameters for link functions. For example, the logit function can be extended to allow mappings to any closed interval. There should be one list entry for each link function. Specify NA if defaults should be used. |
bisque:::itx(0, 'logit', list(NA))
bisque:::itx(0, 'logit', list(NA))
Let be a transformation of a random variable
.
This function computes the jacobian
when using the density of
to evaluate the density of
via
where
jac.exp(x, log = TRUE)
jac.exp(x, log = TRUE)
x |
value at which to evaluate |
log |
TRUE to return |
jac.exp(1)
jac.exp(1)
Let be a transformation of a random variable
.
This function computes the jacobian
when using the density of
to evaluate the density of
via
where
jac.invlogit(x, log = TRUE)
jac.invlogit(x, log = TRUE)
x |
value at which to evaluate |
log |
TRUE to return |
jac.invlogit(1)
jac.invlogit(1)
Let be a transformation of a random variable
.
This function computes the jacobian
when using the density of
to evaluate the density of
via
where
jac.log(x, log = TRUE)
jac.log(x, log = TRUE)
x |
value at which to evaluate |
log |
TRUE to return |
jac.log(1)
jac.log(1)
Let be a transformation of a random variable
that
lies in the closed interval (L,U).
This function computes the jacobian
when using the density of
to evaluate the density of
via
where
jac.logit(x, log = TRUE, range = c(0, 1))
jac.logit(x, log = TRUE, range = c(0, 1))
x |
value at which to evaluate |
log |
TRUE to return |
range |
vector specifying min and max range of the closed interval for the logit. While the logit is defined for real numbers in the unit interval, we extend it to real numbers in arbitrary closed intervals (L,U). |
jac.logit(1)
jac.logit(1)
This function integrates (unnormalized) densities and may be used to compute integration constants for unnormalized densities, or to marginalize a joint density, for example.
kCompute( f, init, method = "BFGS", maxit = 10000, level = 2, log = FALSE, link = NULL, linkparams = NULL, quadError = FALSE, ... )
kCompute( f, init, method = "BFGS", maxit = 10000, level = 2, log = FALSE, link = NULL, linkparams = NULL, quadError = FALSE, ... )
f |
(Unnormalized) density to integrate.
the function |
init |
Initial guess for the density's mode |
method |
method to be used to search for the density's mode |
maxit |
maximum number of iterations |
level |
accuracy level (typically number of grid points for the underlying 1D quadrature rule) [description from mvQuad::createNIGrid] |
log |
TRUE to return log of integration constant |
link |
character vector that specifies transformations used during
optimization and integration of f(theta2 | X). while theta2 may be
defined on arbitrary support, |
linkparams |
Optional list of additional parameters for link functions. For example, the logit function can be extended to allow mappings to any closed interval. There should be one list entry for each link function. Specify NA if no additional arguments are passed. |
quadError |
TRUE if integration nodes and weight should be computed for
the |
... |
additional arguments to pass to |
kCompute(dgamma, init = 1, shape=2, link='log', level = 5)
kCompute(dgamma, init = 1, shape=2, link='log', level = 5)
Wrapper to abstractly evaluate log-Jacobian functions for transforms
logjac(x, link, linkparams)
logjac(x, link, linkparams)
x |
values at which to evaluate |
link |
Character vector specifying link function for which the
inverse link function should be evaluated. Supports |
linkparams |
Optional list of additional parameters for link functions. For example, the logit function can be extended to allow mappings to any closed interval. There should be one list entry for each link function. Specify NA if defaults should be used. |
bisque:::logjac(1, 'logit', list(NA))
bisque:::logjac(1, 'logit', list(NA))
For use in the parallel call in wtdMix()
mergePars(x, y)
mergePars(x, y)
x |
Output from one of the parallel calls in wtdMix() |
y |
Another output from one of the parallel calls in wtdMix() |
Uses a Gibbs sampler to estimate the parameters of a Matern covariance function used to model observations from a Gaussian process with mean 0.
sFit( x, coords, nSamples, thin = 1, rw.initsd = 0.1, inits = list(), C = 1, alpha = 0.44, priors = list(sigmasq = list(a = 2, b = 1), rho = list(L = 0, U = 1), nu = list(L = 0, U = 1)) )
sFit( x, coords, nSamples, thin = 1, rw.initsd = 0.1, inits = list(), C = 1, alpha = 0.44, priors = list(sigmasq = list(a = 2, b = 1), rho = list(L = 0, U = 1), nu = list(L = 0, U = 1)) )
x |
Observation of a spatial Gaussian random field, passed as a vector |
coords |
Spatial coordinates of the observation |
nSamples |
(thinned) number of MCMC samples to generate |
thin |
thinning to be used within the returned MCMC samples |
rw.initsd |
initial standard devaition for random walk proposals. this parameter will be adaptively tuned during sampling |
inits |
list of initial parameters for the MCMC chain |
C |
scale factor used during tuning of the random walk proposal s.d. |
alpha |
target acceptance rate for which the random walk proposals should optimize |
priors |
parameters to specify the prior distributions for the model |
library(fields) simulate.field = function(n = 100, range = .3, smoothness = .5, phi = 1){ # Simulates a mean-zero spatial field on the unit square # # Parameters: # n - number of spatial locations # range, smoothness, phi - parameters for Matern covariance function coords = matrix(runif(2*n), ncol=2) Sigma = Matern(d = as.matrix(dist(coords)), range = range, smoothness = smoothness, phi = phi) list(coords = coords, params = list(n=n, range=range, smoothness=smoothness, phi=phi), x = t(chol(Sigma)) %*% rnorm(n)) } # simulate data x = simulate.field() # configure gibbs sampler it = 100 # run sampler using default posteriors post.samples = sFit(x = x$x, coords = x$coords, nSamples = it) # build kriging grid cseq = seq(0, 1, length.out = 10) coords.krig = expand.grid(x = cseq, y = cseq) # sample from posterior predictive distribution burn = 75 samples.krig = sKrig(x$x, post.samples, coords.krig = coords.krig, burn = burn)
library(fields) simulate.field = function(n = 100, range = .3, smoothness = .5, phi = 1){ # Simulates a mean-zero spatial field on the unit square # # Parameters: # n - number of spatial locations # range, smoothness, phi - parameters for Matern covariance function coords = matrix(runif(2*n), ncol=2) Sigma = Matern(d = as.matrix(dist(coords)), range = range, smoothness = smoothness, phi = phi) list(coords = coords, params = list(n=n, range=range, smoothness=smoothness, phi=phi), x = t(chol(Sigma)) %*% rnorm(n)) } # simulate data x = simulate.field() # configure gibbs sampler it = 100 # run sampler using default posteriors post.samples = sFit(x = x$x, coords = x$coords, nSamples = it) # build kriging grid cseq = seq(0, 1, length.out = 10) coords.krig = expand.grid(x = cseq, y = cseq) # sample from posterior predictive distribution burn = 75 samples.krig = sKrig(x$x, post.samples, coords.krig = coords.krig, burn = burn)
Draw posterior predictive samples from a spatial Gaussian process model
sKrig(x, sFit, coords.krig, coords = sFit$coords, burn = 0, ncores = 1)
sKrig(x, sFit, coords.krig, coords = sFit$coords, burn = 0, ncores = 1)
x |
Observation of a spatial Gaussian random field, passed as a vector |
sFit |
posterior samples of model parameters; output from bisque::sFit |
coords.krig |
Spatial coordinates at which the field should be interpolated |
coords |
Spatial coordinates at which observations are available |
burn |
number of posterior samples to discard from sFit before sampling |
ncores |
Kriging is done via composition sampling, which may be done in
parallel. |
library(fields) simulate.field = function(n = 100, range = .3, smoothness = .5, phi = 1){ # Simulates a mean-zero spatial field on the unit square # # Parameters: # n - number of spatial locations # range, smoothness, phi - parameters for Matern covariance function coords = matrix(runif(2*n), ncol=2) Sigma = Matern(d = as.matrix(dist(coords)), range = range, smoothness = smoothness, phi = phi) list(coords = coords, params = list(n=n, range=range, smoothness=smoothness, phi=phi), x = t(chol(Sigma)) %*% rnorm(n)) } # simulate data x = simulate.field() # configure gibbs sampler it = 100 # run sampler using default posteriors post.samples = sFit(x = x$x, coords = x$coords, nSamples = it) # build kriging grid cseq = seq(0, 1, length.out = 10) coords.krig = expand.grid(x = cseq, y = cseq) # sample from posterior predictive distribution burn = 75 samples.krig = sKrig(x$x, post.samples, coords.krig = coords.krig, burn = burn)
library(fields) simulate.field = function(n = 100, range = .3, smoothness = .5, phi = 1){ # Simulates a mean-zero spatial field on the unit square # # Parameters: # n - number of spatial locations # range, smoothness, phi - parameters for Matern covariance function coords = matrix(runif(2*n), ncol=2) Sigma = Matern(d = as.matrix(dist(coords)), range = range, smoothness = smoothness, phi = phi) list(coords = coords, params = list(n=n, range=range, smoothness=smoothness, phi=phi), x = t(chol(Sigma)) %*% rnorm(n)) } # simulate data x = simulate.field() # configure gibbs sampler it = 100 # run sampler using default posteriors post.samples = sFit(x = x$x, coords = x$coords, nSamples = it) # build kriging grid cseq = seq(0, 1, length.out = 10) coords.krig = expand.grid(x = cseq, y = cseq) # sample from posterior predictive distribution burn = 75 samples.krig = sKrig(x$x, post.samples, coords.krig = coords.krig, burn = burn)
Evaluates the named link function at the locations x
.
tx(x, link, linkparams)
tx(x, link, linkparams)
x |
Values at which to evaluate the link function |
link |
Character vector specifying link function to evaluate. Supports
|
linkparams |
Optional list of additional parameters for link functions. For example, the logit function can be extended to allow mappings to any closed interval. There should be one list entry for each link function. Specify NA if defaults should be used. |
bisque:::tx(0.5, 'logit', list(NA))
bisque:::tx(0.5, 'logit', list(NA))
Note: is defined on the transformed scale, but for convenience
f
is defined on the original scale.
wBuild( f, init, dim.theta2 = length(init), approx = "gaussian", link = rep("identity", length(init)), link.params = rep(list(NA), length(init)), optim.control = list(maxit = 5000, method = "BFGS"), ... )
wBuild( f, init, dim.theta2 = length(init), approx = "gaussian", link = rep("identity", length(init)), link.params = rep(list(NA), length(init)), optim.control = list(maxit = 5000, method = "BFGS"), ... )
f |
function used to derive the weight function |
init |
initial guess for mode of |
dim.theta2 |
|
approx |
Style of approximation (i.e.,
|
link |
character vector that specifies transformations used during
optimization and integration of |
link.params |
Optional list of additional parameters for link functions. For example, the logit function can be extended to allow mappings to any closed interval. There should be one list entry for each link function. Specify NA if no additional arguments are passed. |
optim.control |
List of arguments to pass to
|
... |
additional arguments needed for function evaluation. |
# Use BISQuE to approximate the marginal posterior distribution for unknown # population f(N|c, r) for the fur seals capture-recapture data example in # Givens and Hoeting (2013), example 7.10. data('furseals') # define theta transformation and jacobian tx.theta = function(theta) { c(log(theta[1]/theta[2]), log(sum(theta[1:2]))) } itx.theta = function(u) { c(exp(sum(u[1:2])), exp(u[2])) / (1 + exp(u[1])) } lJ.tx.theta = function(u) { log(exp(u[1] + 2*u[2]) + exp(2*sum(u[1:2]))) - 3 * log(1 + exp(u[1])) } # compute constants r = sum(furseals$m) nC = nrow(furseals) # set basic initialization for parameters init = list(U = c(-.7, 5.5)) init = c(init, list( alpha = rep(.5, nC), theta = itx.theta(init$U), N = r + 1 )) post.alpha_theta = function(theta2, log = TRUE, ...) { # Function proportional to f(alpha, U1, U2 | c, r) alpha = theta2[1:nC] u = theta2[-(1:nC)] theta = itx.theta(u) p = 1 - prod(1-alpha) res = - sum(theta)/1e3 - r * log(p) + lJ.tx.theta(u) - nC * lbeta(theta[1], theta[2]) for(i in 1:nC) { res = res + (theta[1] + furseals$c[i] - 1)*log(alpha[i]) + (theta[2] + r - furseals$c[i] - 1)*log(1-alpha[i]) } if(log) { res } else { exp(res) } } post.N.mixtures = function(N, params, log = TRUE, ...) { # The mixture component of the weighted mixtures for f(N | c, r) dnbinom(x = N-r, size = r, prob = params, log = log) } mixparams.N = function(theta2, ...) { # compute parameters for post.N.mixtures 1 - prod(1 - theta2[1:nC]) } w.N = wBuild(f = post.alpha_theta, init = c(init$alpha, init$U), approx = 'gauss', link = c(rep('logit', nC), rep('identity', 2))) m.N = wMix(f1 = post.N.mixtures, f1.precompute = mixparams.N, f2 = post.alpha_theta, w = w.N) # compute posterior mean m.N$expectation$Eh.precompute(h = function(p) ((1-p)*r/p + r), quadError = TRUE) # compute posterior density post.N.dens = data.frame(N = r:105) post.N.dens$d = m.N$f(post.N.dens$N) # plot posterior density plot(d~N, post.N.dens, ylab = expression(f(N~'|'~bold(c),r)))
# Use BISQuE to approximate the marginal posterior distribution for unknown # population f(N|c, r) for the fur seals capture-recapture data example in # Givens and Hoeting (2013), example 7.10. data('furseals') # define theta transformation and jacobian tx.theta = function(theta) { c(log(theta[1]/theta[2]), log(sum(theta[1:2]))) } itx.theta = function(u) { c(exp(sum(u[1:2])), exp(u[2])) / (1 + exp(u[1])) } lJ.tx.theta = function(u) { log(exp(u[1] + 2*u[2]) + exp(2*sum(u[1:2]))) - 3 * log(1 + exp(u[1])) } # compute constants r = sum(furseals$m) nC = nrow(furseals) # set basic initialization for parameters init = list(U = c(-.7, 5.5)) init = c(init, list( alpha = rep(.5, nC), theta = itx.theta(init$U), N = r + 1 )) post.alpha_theta = function(theta2, log = TRUE, ...) { # Function proportional to f(alpha, U1, U2 | c, r) alpha = theta2[1:nC] u = theta2[-(1:nC)] theta = itx.theta(u) p = 1 - prod(1-alpha) res = - sum(theta)/1e3 - r * log(p) + lJ.tx.theta(u) - nC * lbeta(theta[1], theta[2]) for(i in 1:nC) { res = res + (theta[1] + furseals$c[i] - 1)*log(alpha[i]) + (theta[2] + r - furseals$c[i] - 1)*log(1-alpha[i]) } if(log) { res } else { exp(res) } } post.N.mixtures = function(N, params, log = TRUE, ...) { # The mixture component of the weighted mixtures for f(N | c, r) dnbinom(x = N-r, size = r, prob = params, log = log) } mixparams.N = function(theta2, ...) { # compute parameters for post.N.mixtures 1 - prod(1 - theta2[1:nC]) } w.N = wBuild(f = post.alpha_theta, init = c(init$alpha, init$U), approx = 'gauss', link = c(rep('logit', nC), rep('identity', 2))) m.N = wMix(f1 = post.N.mixtures, f1.precompute = mixparams.N, f2 = post.alpha_theta, w = w.N) # compute posterior mean m.N$expectation$Eh.precompute(h = function(p) ((1-p)*r/p + r), quadError = TRUE) # compute posterior density post.N.dens = data.frame(N = r:105) post.N.dens$d = m.N$f(post.N.dens$N) # plot posterior density plot(d~N, post.N.dens, ylab = expression(f(N~'|'~bold(c),r)))
For a Bayesian model
the marginal posterior distribution can be
approximated via weighted mixtures via
where is based on
and weights
, where
and
are
nodes and weights for a sparse-grid quadrature integration scheme.
The quadrature rule is developed by finding the posterior mode of
, after transforming
to an unconstrained
support. For best results,
should be a continuous random
variable, or be able to be approximated by one.
wMix( f1, f2, w, f1.precompute = function(x, ...) { x }, spec = "ff", level = 2, c.int = NULL, c.level = 2, c.init = NULL, c.link = rep("identity", length(c.init)), c.link.params = rep(list(NA), length(c.init)), c.optim.control = list(maxit = 5000, method = "BFGS"), ncores = 1, quadError = TRUE, ... )
wMix( f1, f2, w, f1.precompute = function(x, ...) { x }, spec = "ff", level = 2, c.int = NULL, c.level = 2, c.init = NULL, c.link = rep("identity", length(c.init)), c.link.params = rep(list(NA), length(c.init)), c.optim.control = list(maxit = 5000, method = "BFGS"), ncores = 1, quadError = TRUE, ... )
f1 |
evaluates
|
f2 |
evaluates |
w |
|
f1.precompute |
function that pre-computes parameters for evaluating
|
spec |
Specification of whether |
level |
accuracy level of the numerical approximation (typically number of grid points for the underlying 1D quadrature rule) [description from mvQuad::createNIGrid] |
c.int |
If |
c.level |
accuracy level of the numerical approximation for |
c.init |
initial guess for mode of |
c.link |
character vector that specifies transformations used during
optimization and integration of |
c.link.params |
Optional list of additional parameters for link
functions used with |
c.optim.control |
Arguments used to find mode of |
ncores |
number of cores used to parallelize computation of parameters
for |
quadError |
TRUE if integration nodes and weight should be computed for
the |
... |
Additional arguments to pass to |
A list with class wMix
, which contains the following items.
f
Function for evaluating the posterior density
.
f
is callable via
f(theta1, log, ...)
.
mix
A matrix containing the pre-computed parameters for
evaluating the mixture components .
Each row of the matrix contains parameters for one of the
mixture components.
wts
Integration weights for each of the mixture components. Some of the weights may be negative.
expectation
List containing additional tools for computing
posterior expectations of . However, posterior
expectations of
can also be computed when
expectations of
are known. The elements
of
expectation
are
Eh
Function to compute .
Eh
is callable via Eh(h, ...)
, where h
is a
function callable via h(theta2, ...)
and ...
are
additional arguments to the function. The function h
is
evaluated at the quadrature nodes .
Eh.precompute
Exactly the same idea as Eh
, but
the function h
is evalauted at the quadrature nodes after
being passed through the function f1.precompute
.
grid
The sparse-quadrature integration grid used.
Helpful for seeing the quadrature nodes .
wts
The integration weights for approximating the
expectation . Note that these integration weights may
differ from the main integration weights for evaluating the
posterior density
.
# Use BISQuE to approximate the marginal posterior distribution for unknown # population f(N|c, r) for the fur seals capture-recapture data example in # Givens and Hoeting (2013), example 7.10. data('furseals') # define theta transformation and jacobian tx.theta = function(theta) { c(log(theta[1]/theta[2]), log(sum(theta[1:2]))) } itx.theta = function(u) { c(exp(sum(u[1:2])), exp(u[2])) / (1 + exp(u[1])) } lJ.tx.theta = function(u) { log(exp(u[1] + 2*u[2]) + exp(2*sum(u[1:2]))) - 3 * log(1 + exp(u[1])) } # compute constants r = sum(furseals$m) nC = nrow(furseals) # set basic initialization for parameters init = list(U = c(-.7, 5.5)) init = c(init, list( alpha = rep(.5, nC), theta = itx.theta(init$U), N = r + 1 )) post.alpha_theta = function(theta2, log = TRUE, ...) { # Function proportional to f(alpha, U1, U2 | c, r) alpha = theta2[1:nC] u = theta2[-(1:nC)] theta = itx.theta(u) p = 1 - prod(1-alpha) res = - sum(theta)/1e3 - r * log(p) + lJ.tx.theta(u) - nC * lbeta(theta[1], theta[2]) for(i in 1:nC) { res = res + (theta[1] + furseals$c[i] - 1)*log(alpha[i]) + (theta[2] + r - furseals$c[i] - 1)*log(1-alpha[i]) } if(log) { res } else { exp(res) } } post.N.mixtures = function(N, params, log = TRUE, ...) { # The mixture component of the weighted mixtures for f(N | c, r) dnbinom(x = N-r, size = r, prob = params, log = log) } mixparams.N = function(theta2, ...) { # compute parameters for post.N.mixtures 1 - prod(1 - theta2[1:nC]) } w.N = wBuild(f = post.alpha_theta, init = c(init$alpha, init$U), approx = 'gauss', link = c(rep('logit', nC), rep('identity', 2))) m.N = wMix(f1 = post.N.mixtures, f1.precompute = mixparams.N, f2 = post.alpha_theta, w = w.N) # compute posterior mean m.N$expectation$Eh.precompute(h = function(p) ((1-p)*r/p + r), quadError = TRUE) # compute posterior density post.N.dens = data.frame(N = r:105) post.N.dens$d = m.N$f(post.N.dens$N) # plot posterior density plot(d~N, post.N.dens, ylab = expression(f(N~'|'~bold(c),r)))
# Use BISQuE to approximate the marginal posterior distribution for unknown # population f(N|c, r) for the fur seals capture-recapture data example in # Givens and Hoeting (2013), example 7.10. data('furseals') # define theta transformation and jacobian tx.theta = function(theta) { c(log(theta[1]/theta[2]), log(sum(theta[1:2]))) } itx.theta = function(u) { c(exp(sum(u[1:2])), exp(u[2])) / (1 + exp(u[1])) } lJ.tx.theta = function(u) { log(exp(u[1] + 2*u[2]) + exp(2*sum(u[1:2]))) - 3 * log(1 + exp(u[1])) } # compute constants r = sum(furseals$m) nC = nrow(furseals) # set basic initialization for parameters init = list(U = c(-.7, 5.5)) init = c(init, list( alpha = rep(.5, nC), theta = itx.theta(init$U), N = r + 1 )) post.alpha_theta = function(theta2, log = TRUE, ...) { # Function proportional to f(alpha, U1, U2 | c, r) alpha = theta2[1:nC] u = theta2[-(1:nC)] theta = itx.theta(u) p = 1 - prod(1-alpha) res = - sum(theta)/1e3 - r * log(p) + lJ.tx.theta(u) - nC * lbeta(theta[1], theta[2]) for(i in 1:nC) { res = res + (theta[1] + furseals$c[i] - 1)*log(alpha[i]) + (theta[2] + r - furseals$c[i] - 1)*log(1-alpha[i]) } if(log) { res } else { exp(res) } } post.N.mixtures = function(N, params, log = TRUE, ...) { # The mixture component of the weighted mixtures for f(N | c, r) dnbinom(x = N-r, size = r, prob = params, log = log) } mixparams.N = function(theta2, ...) { # compute parameters for post.N.mixtures 1 - prod(1 - theta2[1:nC]) } w.N = wBuild(f = post.alpha_theta, init = c(init$alpha, init$U), approx = 'gauss', link = c(rep('logit', nC), rep('identity', 2))) m.N = wMix(f1 = post.N.mixtures, f1.precompute = mixparams.N, f2 = post.alpha_theta, w = w.N) # compute posterior mean m.N$expectation$Eh.precompute(h = function(p) ((1-p)*r/p + r), quadError = TRUE) # compute posterior density post.N.dens = data.frame(N = r:105) post.N.dens$d = m.N$f(post.N.dens$N) # plot posterior density plot(d~N, post.N.dens, ylab = expression(f(N~'|'~bold(c),r)))