library(mrgsolve)
options(mrgsolve.soloc="build")
<- mread_cache("pred1", modlib()) mod
1 Introduction
This post introduces a new formal code block for writing models where there are no compartments. The block is named after the analogous NONMEM block called $PRED
. This functionality has always been possible with mrgsolve, but only now is there a code block dedicated to these models. Also, a relaxed set of data set constraints have been put in place when these types of models are invoked.
2 Example model
As a most-basic model, we look at the pred1
model in modlib()
The model code is
$PROB
An example model expressed in closed form= -1, beta0 = 100, beta1 = 0.1
$PARAM B 2 0.3
$OMEGA
$PREDdouble beta0i = beta0 + ETA(1);
double beta1i = beta1*exp(ETA(2));
= beta0i + beta1i*B; capture Y
This is a random-intercept, random slope linear model. Like other models in mrgsolve, you can write parameters ($PARAM
), and random effects ($OMEGA
). But the model is actually written in $PRED
.
When mrgsolve finds $PRED
, it will generate an error if it also finds $MAIN
, $TABLE
, or $ODE
. However, the code that gets entered into $PRED
would function exactly as if you put it in $TABLE
.
In the example model, the response is a function of the parameter B
, so we’ll generate an input data set with some values of B
library(dplyr)
<- tibble(ID = 1, B = exp(rnorm(100, 0,2)))
data
head(data)
# A tibble: 6 × 2
ID B
<dbl> <dbl>
1 1 6.72
2 1 5.68
3 1 0.171
4 1 6.01
5 1 0.198
6 1 1.93
<- mrgsim_d(mod,data,carry.out="B")
out
plot(out, Y~B)
Like other models, we can simulate from a population
library(purrr)
set.seed(223)
<- map_df(1:30, function(i) tibble(ID = i, B = seq(0,30,1)))
df
head(df)
# A tibble: 6 × 2
ID B
<int> <dbl>
1 1 0
2 1 1
3 1 2
4 1 3
5 1 4
6 1 5
%>%
mod data_set(df) %>%
mrgsim(carry.out="B") %>%
plot(Y ~ B)
3 PK/PD Model
Here is an implementation of a PK/PD model using $PRED
In this model
- Calculate
CL
as a function ofWT
and a random effect - Derive
AUC
fromCL
andDOSE
- The response (
Y
) is a calculated fromAUC
and the Emax model parameters
<- '
code $PARAM TVCL = 1, WT = 70, AUC50 = 20, DOSE = 100, E0 = 35, EMAX = 2.4
$OMEGA 1
$SIGMA 100
$PRED
double CL = TVCL*pow(WT/70,0.75)*exp(ETA(1));
capture AUC = DOSE/CL;
capture Y = E0*(1+EMAX*AUC/(AUC50+AUC))+EPS(1);
'
<- mcode_cache("pkpd", code) mod
Building pkpd ... done.
To simulate, look at 50 subjects at each of 5 doses
<-
data expand.idata(DOSE = c(30,50,80,110,200),ID = 1:50) %>%
mutate(WT = exp(rnorm(n(),log(80),1)))
head(data)
ID DOSE WT
1 1 30 59.13254
2 2 50 317.32739
3 3 80 242.15746
4 4 110 170.78136
5 5 200 248.18054
6 6 30 51.22012
<- mrgsim_d(mod,data,carry.out="WT,DOSE") %>% as.data.frame
out
head(out)
ID time WT DOSE AUC Y
1 1 0 59.13254 30 231.90852 110.61330
2 2 0 317.32739 50 36.76051 85.27834
3 3 0 242.15746 80 36.54808 98.90407
4 4 0 170.78136 110 23.68354 80.29131
5 5 0 248.18054 200 331.10229 108.81926
6 6 0 51.22012 30 251.58373 116.09649
Plot the response (Y
) versus AUC
, colored by dose
library(ggplot2)
ggplot(out, aes(AUC,Y,col =factor(DOSE))) +
geom_point() +
scale_x_continuous(trans = "log", breaks = 10^seq(-4,4)) +
geom_smooth(aes(AUC,Y),se = FALSE,col="darkgrey") + theme_bw() +
scale_color_brewer(palette = "Set2", name = "") +
theme(legend.position = "top")
`geom_smooth()` using method = 'loess' and formula = 'y ~ x'