---
title: "Generate MAP Bayes Parameter Estimates"
date:  2017-02-23T10:13:36
tags: "estimation"
---

```{r,echo=FALSE}
library(knitr)
knitr::opts_chunk$set(comment='.',fig.align="center",message=FALSE,cache=FALSE, autodep=TRUE)
```

```{r,message=FALSE}
library(ggplot2)
library(mrgsolve)
library(minqa)
library(dplyr)
library(magrittr)
```




# About

This tutorial illustrates how to do MAP Bayes estimation with `mrgsolve`.  
The setup was adapted from an existing project, where only a single
individual was considered.  With some additional `R` coding, it could be expanded 
to consider multiple individuals in a single run.



# One compartment model, keep it simple for now

* The model specification code below is for a one-compartment model,
where `mrgsolve` will calculate the amount in `CENT` from closed-form
equations

* For now, `$OMEGA` and `$SIGMA` are filled with zeros; we'll 
update it later

* The control stream is set up so that we can either simulate
the etas or pass them in.  `ETA(1)` and `ETA(2)` are the etas
that `mrgsolve` will draw from `$OMEGA`.  `ETA1` and `ETA2` 
are fixed and known at the time of time of the simulation.  The 
optimizer will search for values of `ETA1` and `ETA2` that 
optimize the objective function.  Note that `ETA1` and `ETA2` must
be in the parameter list for this to work

* We do a trick where `CL=TVCL*exp(ETA1+ETA(1));`  The assumption
is that either `ETA1` (simulating) is zero or `ETA(1)` is zero (estimating)

* We table out `ETA(1)` and `ETA(2)` so we can know the true
(simulated) values (but not both zero and not both non-zero)

* `DV` is output as a function of `EPS(1)`; this will be zero until
we add in values for `$SIGMA`.  But when we're estimating,
we need to make sure that `EPS(1)` is zero; the prediction 
shouldn't have any randomness in it (just the individual prediction based
on known etas)

```{r,message=FALSE}
code <- '
$SET request=""

$PARAM TVCL=1.5, TVVC=23.4, ETA1=0, ETA2=0

$CMT CENT

$PKMODEL ncmt=1

$OMEGA 0 0
$SIGMA 0

$MAIN
double CL = TVCL*exp(ETA1 + ETA(1));
double V =  TVVC*exp(ETA2 + ETA(2));

$TABLE 
double DV = (CENT/V)*(1+EPS(1));
double ET1 = ETA(1);
double ET2 = ETA(2);

$CAPTURE DV ET1 ET2
'

mod <- mcode("map", code)
```


# First, simulate some data

`$OMEGA` and `$SIGMA`; 

* The result may look better or worse depending 
on what we choose here
* These will be used to both simulate and fit the data
* The `cmat` call makes a `2x2` matrix where the off-diagonal
is a correlation (`?cmat`).
 
```{r}
omega <- cmat(0.23,-0.78, 0.62)
omega.inv <- solve(omega)
sigma <- matrix(0.0032)
```


Just a single dose to `CENT` with an events object
```{r}
dose <- ev(amt=750,cmt=1)
```

Take these times for concentration observations
```{r}
sampl <- c(0.5,12,24)
```



Simulate 

* Here, we're populating `$OMEGA` and `$SIGMA` so that the
simulated data will be random
* It is important to `carry.out` all of the items that we will need
in the estimation data set (doses, evid, etc)
* Using `end=-1` with `add=sampl` makes sure that we only 
get observation records at the times listed in `sampl`


```{r}
set.seed(1012) 
sim <- 
  mod %>%
  ev(dose) %>%
  omat(omega) %>%
  smat(sigma) %>%
  carry.out(amt,evid,cmt) %>%
  mrgsim(end=-1, add=sampl)

sim
```


# Create input for optimization

* Using the simulated data as the starting point here

```{r}
sim %<>% as.data.frame
```

Observed data (`y`)

* Just select `DV` from observation records
```{r}
y <- sim %>% filter(evid==0) %>% select(DV) %>% unlist %>% unname

y
```

Create a data set to use in the optimization

* We need to drop `ET1` and `ET2` since they are in the
parameter list

```{r}
data <- sim %>% select(-ET1, -ET2)
data
```



# Optimize

This function takes in a set of proposed $\eta$s along with 
the observed data vector, the data set and a model object and returns
the value of the EBE objective function

* When we do the estimation, the fixed effects and random effect
variances are fixed.  

* The estimates are the $\eta$ for clearance and volume

Arguments: 

* `eta` the current values from the optimizer
* `y` the observed data
* `d` the data set that generated `y`
* `m` the model object
* `pred` if `TRUE`, just return predicted values


## What is this function doing?

1. get the matrix for residual error
1. Make sure `eta` is a list
1. Make sure `eta` is properly named (i.e. `ETA1` and `ETA2`)
1. Copy `eta` into a matrix that is one row
1. Update the model object (`m`) with the current values of `ETA1` and `ETA2`
1. If we are estimating (`!pred`), request only observations in the output (`obsonly`)
1. Simulate from data set `d` and save output to `out` object
1. If we are just requesting predictions (`if(pred)`) return the simulated data
1. The final lines calculate the EBE objective function; see [this paper](http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3339294/) for reference
1. Notice that the function returns a single value (a number); the optimizer
will minimize this value

```{r}
mapbayes <- function(eta,y,d,m,pred=FALSE) {
    
  sig2 <- as.numeric(sigma)
  eta %<>% as.list
  names(eta) <- names(init)
  eta_m <- eta %>% unlist %>% matrix(nrow=1)
  m %<>% param(eta)
  if(!pred) m %<>% obsonly
  out <- m %>% drop.re() %>% data_set(d) %>% mrgsim
  if(pred) return(out %>% as.tbl)
  # http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3339294/
  sig2j <- out$DV^2*sig2
  sqwres <- log(sig2j) + (1/sig2j)*(y-out$DV)^2
  nOn <- diag(eta_m %*% omega.inv %*% t(eta_m))
  return(sum(sqwres) + nOn)

}
```


## Initial estimate

* Note again that we are optimizing the etas here

```{r}
init <- c(ETA1=-0.3, ETA2=0.2)
```

Fit the data

* `newuoa` is from the `minqa` package
* Other optimizers (via `optim`) could probably also be used

Arguments to `newuoa`

* First: the initial estimates
* Second: the function to optimize
* The other argument are passed to `mapbayes`

```{r}
fit <- newuoa(init,mapbayes,y=y,m=mod,d=data)
```


Here are the final estimates
```{r}
fit$par
```

Here are the simulated values
```{r}
slice(sim,1) %>% select(ET1, ET2)
```


# Look at the result

A data set and model to get predictions; this will 
give us a smooth prediction line

```{r}
pdata <- data %>% filter(evid==1)
pmod <- mod %>% update(end=24, delta=0.1) 
```

Predicted line based on final estimates
```{r}
pred <- mapbayes(fit$par,y,pdata,pmod,pred=TRUE) %>% filter(time > 0)
head(pred)
```

Predicted line based on initial estimates
```{r}
initial <- mapbayes(init,y,pdata,pmod,pred=TRUE) %>% filter(time > 0)
head(initial)

```


Plot
```{r}
ggplot() + 
  geom_line(data=pred, aes(time,DV),col="firebrick", lwd=1) + 
  geom_line(data=initial,aes(time,DV), lty=2, col="darkgreen", lwd=1) + 
  geom_point(data=data %>% filter(evid==0), aes(time,DV), col="darkslateblue",size=3)
```
