Metrum Research Group
- Packages and setup
- Reference
- Data
- PBPK model: pitavastatin / CsA DDI
- Objective function
- Data grooming
- Optimize
library(tidyverse)
library(PKPDmisc)
library(mrgsolve)
source("script/functions.R")
source("script/global.R")
set.seed(10101)
theme_set(theme_bw() + theme(legend.position = "top"))
scale_colour_discrete <- function(...) scale_color_brewer(palette="Set2")
Models are located here:
model_dir <- "model"
Quantitative Analyses of Hepatic OATP-Mediated Interactions Between Statins and Inhibitors Using PBPK Modeling With a Parameter Optimization Method
-
T Yoshikado, K Yoshida, N Kotani, T Nakada, R Asaumi, K Toshimoto, K Maeda, H Kusuhara and Y Sugiyama
-
CLINICAL PHARMACOLOGY & THERAPEUTICS | VOLUME 100 NUMBER 5 | NOVEMBER 2016
- Example taken from figure 4a from the publication
- Using this as example data to fit
data.file <- "data/fig4a.csv"
data <-
data.file %>%
read_csv() %>%
mutate(
profile = NULL,
type=ID,
typef=factor(ID, labels = c("Statin", "Statin+CsA")),
DV = ifelse(DV==-1, NA_real_, DV)
)
data
. # A tibble: 23 x 8
. ID time DV evid amt cmt type typef
. <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <fct>
. 1 2 0 NA 1 2000 2 2 Statin+CsA
. 2 2 1 NA 1 30 1 2 Statin+CsA
. 3 2 1.49 73.7 0 0 0 2 Statin+CsA
. 4 2 1.99 102. 0 0 0 2 Statin+CsA
. 5 2 2.49 59.9 0 0 0 2 Statin+CsA
. 6 2 3.00 37.6 0 0 0 2 Statin+CsA
. 7 2 3.97 15.7 0 0 0 2 Statin+CsA
. 8 2 5.01 9.24 0 0 0 2 Statin+CsA
. 9 2 6.99 3.54 0 0 0 2 Statin+CsA
. 10 2 9.01 2.22 0 0 0 2 Statin+CsA
. # … with 13 more rows
data %>% filter(evid==1)
. # A tibble: 3 x 8
. ID time DV evid amt cmt type typef
. <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <fct>
. 1 2 0 NA 1 2000 2 2 Statin+CsA
. 2 2 1 NA 1 30 1 2 Statin+CsA
. 3 1 1 NA 1 30 1 1 Statin
- The goal is to fit the pitavastatin data either alone or in combination with cyclosporin administered 1 hour before the pitavastatin
ggplot(data=data,aes(time,DV)) +
geom_point(aes(col = typef), size = 3) +
geom_line(col = "darkgrey", aes(group = typef)) +
scale_y_continuous(trans="log", limits=c(0.1,300), breaks=logbr())
- Check out the model / data with a quick simulation
mod <- mread_cache("yoshikado", model_dir)
Make some persistent updates to the model
- Simulate out to 14 hours
- Only interested in
CP
, the pitavastatin concentration
mod <- mod %>% update(end=14, delta=0.1) %>% Req(CP)
A practice simulation
dose <- filter(data, evid==1) %>% mutate(typef=NULL)
sims <-
mod %>%
mrgsim_d(dose, obsaug=TRUE) %>%
mutate(type = typef(ID))
ggplot(sims, aes(time,CP,col=type)) +
geom_line(lwd = 1) +
scale_x_continuous(breaks = seq(0,12,2)) +
scale_y_log10(name = "Pitavastatin concentration")
sims %>%
group_by(type) %>%
summarise(auc = auc_partial(time,CP)) %>%
mutate(fold_increase = auc /first(auc))
. # A tibble: 2 x 3
. type auc fold_increase
. <fct> <dbl> <dbl>
. 1 Pitavastatin alone 44.1 1
. 2 Pitavastatin + CsA 161. 3.65
- Least squares objective function
- Weighted by the observations
Arguments:
dv
the observed datapred
the predicted data
wss <- function(dv, pred, weight = 1/dv) {
sum(((dv-pred)*weight)^2,na.rm=TRUE)
}
- Let’s go through step by step what each line is doing for us
Arguments:
p
the parameters proposed by the optimizer.data
the simulation template (doses and observation records)yobs
a vector of observed data which matches observations in.data
pred
logical; ifTRUE
, just return predicted data
sim_ofv <- function(p, data, pred = FALSE) {
names(p) <- names(theta)
p <- lapply(p,exp)
mod <- param(mod, p)
out <- mrgsim_q(mod, data = data, output="df")
if(pred) return(out)
ofv <- wss(data[["DV"]], out[["CP"]])
return(ofv)
#return(-1*sum(dnorm(log(yobs),log(out$CP),.par$sigma,log=TRUE)))
}
What this function does:
- Take in arguments; focus is on a new set of parameters
p
proposed by the optimizer; other arguments are just fixed data that we need - Get the parameters out of log scale
- Also, put names on the list of parameters; this is crutial
- Update the model object with the new parameters
- (optionally simulate and return)
- Simulate from the data set, taking only observed values
- Calculate and return the objective function value
- Pick out the observations
- Drop the non-numeric columns
data <- dplyr::select(data, -typef)
First, set up the initial estimates
theta <- c(
fbCLintall = 1.2,
ikiu = 1.2,
fbile = 0.9,
ka = 0.1,
ktr = 0.1
) %>% log()
fit <- nloptr::newuoa(x0 = theta, fn = sim_ofv, data = data)
fit
. $par
. [1] -0.20421286 -4.51432097 -1.06749446 -0.01109318 -0.37133662
.
. $value
. [1] 0.6860763
.
. $iter
. [1] 351
.
. $convergence
. [1] 4
.
. $message
. [1] "NLOPT_XTOL_REACHED: Optimization stopped because xtol_rel or xtol_abs (above) was reached."
Recall that our (transformed) parameters are
fit$par
. [1] -0.20421286 -4.51432097 -1.06749446 -0.01109318 -0.37133662
We can generate a prediction that matches our data like this
sim_ofv(fit$par, data = dose, pred = TRUE) %>% filter(time >= 1) %>% head
. ID time CP
. 1 2 1.0 0.00000
. 2 2 1.0 0.00000
. 3 2 1.1 18.19345
. 4 2 1.2 28.55603
. 5 2 1.3 36.22961
. 6 2 1.4 42.13621
We can also get the predictions under the initial conditions by passing
in theta
rather than fit$par
In the next block, generate
- Predictions with the final estimates
- Predications with the initial estimates
- Observed data to overlay
df_pred <- sim_ofv(fit$par, dose, pred=TRUE) %>% mutate(type = typef(ID))
df_init <- sim_ofv(theta, dose, pred=TRUE) %>% mutate(type = typef(ID))
df_obs <- mutate(data, type=typef(ID))
ggplot(df_pred, aes(time,CP)) +
geom_line(lwd=1) +
geom_point(data = df_obs, aes(time,DV),col="firebrick",size=2) +
facet_wrap(~type) + scale_y_log10()
ggplot(data=df_pred) +
geom_line(data=df_init,aes(time,CP,lty="A"), col="black", lwd=0.7) +
geom_line(aes(time,CP,lty="B"),col="black",lwd=0.7) +
geom_point(data=df_obs,aes(time,DV,col=type),size=3) +
facet_wrap(~type) +
scale_y_continuous(trans="log",breaks=10^seq(-4,4),
limits=c(0.1,100),
"Pitavastatin concentration (ng/mL)") +
scale_x_continuous(name="Time (hours)", breaks=seq(0,14,2)) +
scale_linetype_manual(values= c(2,1), guide = FALSE,
labels=c("Initial estimates", "Final estimates"), name="") +
theme_bw() + theme(legend.position="top")
sim_ofv(fit$par,data=data)
. [1] 0.6860763
exp(fit$par)
. [1] 0.81528881 0.01095104 0.34386902 0.98896812 0.68981170