| buildMCEM {nimble} | R Documentation | 
Builds an MCEM algorithm for a given NIMBLE model
Description
Takes a NIMBLE model (with some missing data, aka random effects or latent
state nodes) and builds a Monte Carlo Expectation Maximization (MCEM)
algorithm for maximum likelihood estimation. The user can specify which
latent nodes are to be integrated out in the E-Step, or default choices will
be made based on model structure. All other stochastic non-data nodes will be
maximized over. The E-step is done with a sample from a nimble MCMC
algorithm. The M-step is done by a call to optim.
Usage
buildMCEM(
  model,
  paramNodes,
  latentNodes,
  calcNodes,
  calcNodesOther,
  control = list(),
  ...
)
Arguments
| model | a NIMBLE model object, either compiled or uncompiled. | 
| paramNodes | a character vector of names of parameter nodes in the
model; defaults are provided by  | 
| latentNodes | a character vector of names of unobserved (latent) nodes
to marginalize (sum or integrate) over; defaults are provided by
 | 
| calcNodes | a character vector of names of nodes for calculating
components of the full-data likelihood that involve  | 
| calcNodesOther | a character vector of names of nodes for calculating
terms in the log-likelihood that do not depend on any  | 
| control | a named list for providing additional settings used in MCEM.
See  | 
| ... | provided only as a means of checking if a user is using the deprecated interface to 'buildMCEM' in nimble versions < 1.2.0. | 
Details
buildMCEM is a nimbleFunction that creates an MCEM algorithm
for a model and choices (perhaps default) of nodes in different roles in
the model. The MCEM can then be compiled for fast execution with a compiled model.
Note that buildMCEM was re-written for nimble version 1.2.0 and is not
backward-compatible with previous versions. The new version is considered to
be in beta testing.
Denote data by Y, latent states (or missing data) by X, and parameters by T. MCEM works by the following steps, starting from some T:
- Draw a sample of size M from P(X | Y, T) using MCMC. 
- Update T to be the maximizer of E[log P(X, Y | T)] where the expectation is approximated as a Monte Carlo average over the sample from step(1) 
- Repeat until converged. 
The default version of MCEM is the ascent-based MCEM of Caffo et al. (2015).
This attempts to update M when necessary to ensure that step 2 really moves
uphill given that it is maximizing a Monte Carlo approximation and could
accidently move downhill on the real surface of interest due to Monte Carlo
error. The main tuning parameters include alpha, beta, gamma,
Mfactor, C, and tol (tolerance).
If the model supports derivatives via nimble's automatic differentiation (AD)
(and buildDerivs=TRUE in nimbleModel), the maximization step
can use gradients from AD. You must manually set useDerivs=FALSE in
the control list if derivatives aren't supported or if you don't want to use
them.
In the ascent-based method, after maximization in step 2, the Monte Carlo
standard error of the uphill movement is estimated. If the standardized
uphill step is bigger than 0 with Type I error rate alpha, the
iteration is accepted and the algorithm continues. Otherwise, it is not
certain that step 2 really moved uphill due to Monte Carlo error, so the MCMC
sample size M is incremented by a fixed factor (e.g. 0.33 or 0.5, called
Mfactor in the control list), the additional samples are added by
continuing step 1, and step 2 is tried again. If the Monte Carlo noise still
overwhelms the magnitude of uphill movement, the sample size is increased
again, and so on. alpha should be between 0 and 0.5. A larger value
than usually used for inference is recommended so that there is an easy
threshold to determine uphill movement, which avoids increasing M
prematurely. M will never be increased above maxM.
Convergence is determined in a similar way. After a definite move uphill, we
determine if the uphill increment is less than tol, with Type I error
rate gamma. (But if M hits a maximum value, the convergence criterion
changes. See below.)
beta is used to help set M to a minimal level based on previous
iterations. This is a desired Type II error rate, assuming an uphill move
and standard error based on the previous iteration. Set adjustM=FALSE
in the control list if you don't want this behavior.
There are some additional controls on convergence for practical purposes. Set
C in the control list to be the number of times the convergence
criterion mut be satisfied in order to actually stop. E.g setting C=2
means there will always be a restart after the first convergence.
One problem that can occur with ascent-based MCEM is that the final iteration
can be very slow if M must become very large to satisfy the convergence
criterion. Indeed, if the algorithm starts near the MLE, this can occur. Set
maxM in the control list to set the MCMC sample size that should never
be exceeded.
If M==maxM, a softer convergence criterion is used. This second
convergence criterion is to stop if we can't be sure we moved uphill using
Type I error rate delta. This is a soft criterion because for small delta,
Type II errors will be common (e.g. if we really did move uphill but can't be
sure from the Monte Carlo sample), allowing the algorithm to terminate. One
can continue the algorithm from where it stopped, so it is helpful to not
have it get stuck when having a very hard time with the first (stricter)
convergence criterion.
All of alpha, beta, delta, and gamma are utilized
based on asymptotic arguments but in practice must be chosen heuristically.
In other words, their theoretical basis does not exactly yield practical
advice on good choices for efficiency and accuracy, so some trial and error
will be needed.
It can also be helpful to set a minimum and maximum of allowed iterations (of
steps 1 and 2 above). Setting minIter>1 in the control list can
sometimes help avoid a false convergence on the first iteration by forcing at
least one more iteration. Setting maxIter provides a failsafe on a
stuck run.
If you don't want the ascent-based method at all and simply want to run a set
of iterations, set ascent=FALSE in the control list. This will use the
second (softer) convergence criterion.
Parameters to be maximized will by default be handled in an unconstrained
parameter space, transformed if necessary by a
parameterTransform object. In that case, the default
optim method will be "BFGS" and can can be changed by setting
optimMehod in the control list. Set useTransform=FALSE in the
control list if you don't want the parameters transformed. In that case the
default optimMethod will be "L-BFGS-B" if there are any actual
constraints, and you can provide a list of boxConstraints in the
control list. (Constraints may be determined by priors written in the model
for parameters, even though their priors play no other role in MLE. E.g.
sigma ~ halfflat() indicates sigma > 0).
Most of the control list elements can be overridden when calling the
findMLE method. The findMLE argument continue=TRUE
results in attempting to continue the algorithm where the previous call
finished, including whatever settings were in use.
See setupMargNodes (which is called with the given arguments
for paramNodes, calcNodes, and calcNodesOther; and with
allowDiscreteLatent=TRUE, randomEffectsNodes=latentNodes, and
check=check) for more about how the different groups of nodes are
determined. In general, you can provide none, one, or more of the different
kinds of nodes and setupMargNodes will try to determine the others in
a sensible way. However, note that this cannot work for all ways of writing a
model. One key example is that if random (latent) nodes are written as
top-level nodes (e.g. following N(0,1)), they appear structurally to
be parameters and you must tell buildMCEM that they are
latentNodes. The various "Nodes" arguments will all be passed through
model$expandNodeNames, allowing for example simply "x" to be provided
when there are many nodes within "x".
Estimating the Monte Carlo standard error of the uphill step is not trivial
because the sample was obtained by MCMC and so likely is autocorrelated. This
is done by calling whatever function in R's global environment is called
"MCEM_mcse", which is required to take two arguments: samples (which
will be a vector of the differences in log(P(Y, X | T)) between the new and
old values of T, across the sample of X) and m, the sample size. It
must return an estimate of the standard error of the mean of the sample.
NIMBLE provides a default version (exported from the package namespace),
which calls mcmcse::mcse with method "obm". Simply provide a different
function with this name in your R session to override NIMBLE's default.
Control list details
The control list accepts the following named elements:
-  initMinitial MCMC sample size,M. Default=1000.
-  MfactorFactor by which to increase MCMC sample size when step 2 results in noise overwhelming the uphill movement. The newMwill be1+Mfactor)*M(rounded up).Mfactoris1/kof Caffo et al. (2015). Default=1/3.
-  maxMMaximum allowed value ofM(see above). Default=initM*20.
-  burninNumber of burn-in iterations for the MCMC in step 1. Note that the initial states of one MCMC will be the last states from the previous MCMC, so they will often be good initial values after multiple iterations. Default=500.
-  thinThinning interval for the MCMC in step 1. Default=1.
-  alphaType I error rate for determining when step 2 has moved uphill. See above. Default=0.25.
-  betaUsed for determining a minimal value of $M$ based on previous iteration, ifadjustMisTRUE.betais a desired Type II error rate for determining uphill moves. Default=0.25.
-  deltaType I error rate for the soft convergence approach (second approach above). Default=0.25.
-  gammaType I error rate for determining when step 2 has moved less thantoluphill, in which case ascent-based convergence is achieved (first approach above). Default=0.05.
-  bufferA small amount added to lower box constraints and substracted from upper box constraints for all parameters, relevant only ifuseTransform=FALSEand some parameters do haveboxConstraintsset or have bounds that can be determined from the model. Default=1e-6.
-  tolAscent-based convergence tolerance. Default=0.001.
-  ascentLogical to determine whether to use the ascent-based method of Caffo et al. Default=TRUE.
-  CNumber of convergences required to actually stop the algorithm. Default = 1.
-  maxIterMaximum number of MCEM iterations to run.
-  minIterMinimum number of MCEM iterations to run.
-  adjustMLogical indicating whether to see if M needs to be increased based on statistical power argument in each iteration (usingbeta). Default=TRUE.
-  verboseLogical indicating whether verbose output is desired. Default=TRUE.
-  MCMCprogressBarLogical indicating whether MCMC progress bars should be shown for every iteration of step 1. This argument is passed toconfigureMCMC, or toconfigif provided. Default=TRUE.
-  derivsDeltaIf AD derivatives are not used, then the methodvcovmust use finite difference derivatives to implement the method of Louis (1982). The finite differences will bedeltaordelta/2for various steps. This is the same for all dimensions. Default=0.0001.
-  mcmcControlThis is passed toconfigureMCMC, orconfigif provided, as thecontrolargument. i.e.control=mcmcControl.
-  boxContrainstList of box constraints for the nodes that will be maximized over, only relevant ifuseTransform=FALSEandforceNoConstraints=FALSE(and ignored otherwise). Each constraint is a list in which the first element is a character vector of node names to which the constraint applies and the second element is a vector giving the lower and upper limits. Limits of-InforInfare allowed. Any nodes that are not given constrains will have their constraints automatically determined by NIMBLE. See above. Default=list().
-  forceNoConstraintsLogical indicating whether to force ignoring constraints even if they might be necessary. Default=FALSE.
-  useTransformLogical indicating whether to use a parameter transformation (seeparameterTransform) to create an unbounded parameter space for the paramNodes. This allows unconstrained maximization algorithms to be used. Default=TRUE.
-  checkLogical passed as thecheckargument tosetupMargNodes. Default=TRUE.
-  useDerivsLogical indicating whether to use AD. If TRUE, the model must have been build with 'buildDerivs=TRUE'. It is not automatically determined from the model whether derivatives are supported. Default=TRUE.
-  configFunction to create the MCMC configuration used for step 1. The MCMC configuration is created by callingconfig(model, nodes = latentNodes, monitors = latentNodes, thin = thinDefault, control = mcmcControl, print = FALSE) The default for config(if it is missing) isconfigureMCMC, which is nimble's general default MCMC configuration function.
Methods in the returned algorithm
The object returned by buildMCEM is a nimbleFunction object with the following methods
-  findMLEis the main method of interest, launching the MCEM algorithm. It takes the following arguments:-  pStart. Vector of initial parameter values. If omitted, the values currently in the model object are used.
-  returnTrans. Logical indicating whether to return parameters in the transformed space, if a parameter transformation is in use. Default=FALSE.
-  continue. Logical indicating whether to continue the MCEM from where the last call stopped. In addition, if TRUE, any other control setting provided in the last call will be used again. If FALSE, all control settings are reset to the values provided whenbuildMCEMwas called. Any control settings provided in the same call ascontinue=TRUEwill over-ride these behaviors and be used in the continued run.
- All run-time control settings available in the - controllist for- buildMCEM(except for- buffer,- boxConstraints,- forceNoConstraints,- useTransform, and- useDerivs) are accepted as individual arguments to over-ride the values provided in the- controllist.
 findMLEreturns on object of classoptimResultNimbleListwith the results of the final optimization of step 2. Theparelement of this list is the vector of maximum likelihood (MLE) parameters.
-  
-  vcovcomputes the approximate variance-covariance matrix of the MLE using the method of Louis (1982). It takes the following arguments:-  params. Vector of parameters at which to compute the Hessian matrix used to obtain thevcovresult. Typically this will beMLE$par, ifMLEis the output offindMLE.
-  trans. Logical indicating whetherparamsis on the transformed prameter scale, if a parameter transformation is in use. Typically this should be the same as thereturnTransargument tofindMLE. Default=FALSE.
-  returnTrans. Logical indicting whether thevcovresult should be for the transformed parameter space. Default matchestrans.
-  M. Number of MCMC samples to obtain ifresetSamples=TRUE. Default is the final value ofMfrom the last call tofindMLE. It can be helpful to increaseMto obtain a more accuratevcovresult (i.e. with less Monte Carlo noise).
-  resetSamples. Logical indicating whether to generate a new MCMC sample from P(X | Y, T), where T isparams. If FALSE, the last sample fromfindMLEwill be used. If MLE convergence was reasonable, this sample can be used. However, if the last MCEM step made a big move in parameter space (e.g. if convergence was not achieved), the last MCMC sample may not be accurate for obtainingvcov. Default=FALSE.
-  atMLE. Logical indicating whether you believe theparamsrepresents the MLE. If TRUE, one part of the computation will be skipped because it is expected to be 0 at the MLE. If there are parts of the model that are not connected to the latent nodes, i.e. ofcalcNodesOtheris not empty, thenatMLEwill be ignored and set to FALSE. Default=FALSE. It is not really worth using TRUE unless you are confident and the time saving is meaningful, which is not very likely. In other words, this argument is provided for technical completeness.
 vcovreturns a matrix that is the inverse of the negative Hessian of the log likelihood surface, i.e. the usual asymptotic approximation of the parameter variance-covariance matrix.
-  
-  doMCMC. This method runs the MCMC to sample from P(X | Y, T). One does not need to call this, as it is called via the MCEM algorithm infindMLE. This method is provided for users who want to use the MCMC for latent states directly. Samples should be retrieved byas.matrix(MCEM$mvSamples), whereMCEMis the (compiled or uncompiled) MCEM algorithm object. This method takes the following arguments:-  M. MCMC sample size.
-  thin. MCMC thinning interval.
-  reset. Logical indicating whether to reset the MCMC (passed to the MCMCrunmethod asreset).
 
-  
-  transformandinverseTransform. Convert a parameter vector to an unconstrained parameter space and vice-versa, ifuseTransform=TRUEin the call tobuildDerivs.
-  resetControls. Reset all control arguments to the values provided in the call tobuildMCEM. The user does not normally need to call this.
Author(s)
Perry de Valpine, Clifford Anderson-Bergman and Nicholas Michaud
References
Caffo, Brian S., Wolfgang Jank, and Galin L. Jones (2005). Ascent-based Monte Carlo expectation-maximization. Journal of the Royal Statistical Society: Series B (Statistical Methodology), 67(2), 235-251.
Louis, Thomas A (1982). Finding the Observed Information Matrix When Using the EM Algorithm. Journal of the Royal Statistical Society. Series B (Statistical Methodology), 44(2), 226-233.
Examples
## Not run: 
pumpCode <- nimbleCode({
 for (i in 1:N){
     theta[i] ~ dgamma(alpha,beta);
     lambda[i] <- theta[i]*t[i];
     x[i] ~ dpois(lambda[i])
 }
 alpha ~ dexp(1.0);
 beta ~ dgamma(0.1,1.0);
})
pumpConsts <- list(N = 10,
              t = c(94.3, 15.7, 62.9, 126, 5.24,
                31.4, 1.05, 1.05, 2.1, 10.5))
pumpData <- list(x = c(5, 1, 5, 14, 3, 19, 1, 1, 4, 22))
pumpInits <- list(alpha = 1, beta = 1,
             theta = rep(0.1, pumpConsts$N))
pumpModel <- nimbleModel(code = pumpCode, name = 'pump', constants = pumpConsts,
                         data = pumpData, inits = pumpInits,
                         buildDerivs=TRUE)
pumpMCEM <- buildMCEM(model = pumpModel)
CpumpModel <- compileNimble(pumpModel)
CpumpMCEM <- compileNimble(pumpMCEM, project=pumpModel)
MLE <- CpumpMCEM$findMLE()
vcov <- CpumpMCEM$vcov(MLE$par)
## End(Not run)