The Monte Carlo expectation maximization (MCEM) algorithm is a method for finding maximum likelihoods in models with latent or missing information. MCEM uses Monte Carlo integration methods to simplify and evaluate potentially high-dimensional integrals.

Here we use the pump model example from BUGS to illustrate how to implement the MCEM algorithm to find maximum likelihood estimates of parameters for statistical models with latent states.

library(nimble, warn.conflicts = FALSE)
## nimble version 1.3.0 is loaded.
## For more information on NIMBLE and a User Manual,
## please visit https://R-nimble.org.
## 
## Note for advanced users who have written their own MCMC samplers:
##   As of version 0.13.0, NIMBLE's protocol for handling posterior
##   predictive nodes has changed in a way that could affect user-defined
##   samplers in some situations. Please see Section 15.5.1 of the User Manual.

NIMBLE code for the pump example

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)
})

Set up the model

Assign values to the constants in the model, provide data, initialize the random variables, and then create the model.

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 = 0.1, beta = 0.1,
                  theta = rep(0.1, pumpConsts$N))

## Create the model
pump <- nimbleModel(code = pumpCode, name = "pump", constants = pumpConsts,
                    data = pumpData, inits = pumpInits, buildDerivs = TRUE)
## Defining model
## Building model
## Setting data and initial values
## Running calculate on model
##   [Note] Any error reports that follow may simply reflect missing values in model variables.
## Checking model sizes and dimensions

Compile the model

Cpump <- compileNimble(pump)
## Compiling
##   [Note] This may take a minute.
##   [Note] Use 'showCompilerOutput = TRUE' to see C++ compilation details.

Run the MCEM algorithm provided by NIMBLE

pumpMCEM <- buildMCEM(model = pump, latentNodes = "theta[1:10]")
##   [Note] You may need to rebuild and recompile a model for each call to buildMCEM.
CpumpMCEM <- compileNimble(pumpMCEM, project = pump)
## Compiling
##   [Note] This may take a minute.
##   [Note] Use 'showCompilerOutput = TRUE' to see C++ compilation details.
pumpMLE <- CpumpMCEM$findMLE()
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
## Loading required namespace: mcmcse
##   [Note] Iteration Number: 1.
##   [Note] Current number of MCMC iterations: 1000.
##   [Note] Parameter Estimates: 
## 0.679112
## 0.927349
##   [Note] Convergence Criterion: 8.4924.
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
##   [Note] Iteration Number: 2.
##   [Note] Current number of MCMC iterations: 1000.
##   [Note] Parameter Estimates: 
## 0.784673
##  1.14538
##   [Note] Convergence Criterion: 0.0970515.
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
##   [Note] Iteration Number: 3.
##   [Note] Current number of MCMC iterations: 1000.
##   [Note] Parameter Estimates: 
## 0.807621
##  1.22919
##   [Note] Convergence Criterion: 0.0152672.
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
## Monte Carlo error too big: increasing MCMC sample size.
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
##   [Note] Iteration Number: 4.
##   [Note] Current number of MCMC iterations: 1167.
##   [Note] Parameter Estimates: 
## 0.819977
##  1.25236
##   [Note] Convergence Criterion: 0.00207652.
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
##   [Note] Iteration Number: 5.
##   [Note] Current number of MCMC iterations: 1167.
##   [Note] Parameter Estimates: 
## 0.821779
##  1.27048
##   [Note] Convergence Criterion: 0.00182642.
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
## Monte Carlo error too big: increasing MCMC sample size.
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
## Monte Carlo error too big: increasing MCMC sample size.
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
##   [Note] Iteration Number: 6.
##   [Note] Current number of MCMC iterations: 1687.
##   [Note] Parameter Estimates: 
## 0.817154
##  1.25532
##   [Note] Convergence Criterion: 0.000927936.
pumpMLE
## nimbleList object of type OptimResultNimbleList
## Field "par":
## [1] 0.8171536 1.2553249
## Field "value":
## [1] -26.87812
## Field "counts":
## [1] 17  4
## Field "convergence":
## [1] 0
## Field "message":
## [1] ""
## Field "hessian":
## <0 x 0 matrix>