library(plyr)
library(qpToolkit)
library(knitr)
library(ggplot2)
library(magrittr)
library(dplyr)
library(yamlet)
library(lattice)

# path to examples NONMEM folder
# nm.path = file.path(getOption("qpExampleDir"))
nm.path = system.file(package = 'qpToolkit', 'NONMEM')
#hide the code blocks in the output
opts_chunk$set(echo=F)

This is an analysis notebook template/example using RMarkdown. This analysis uses examples from the NONMEM examples folder in a couple model development steps. Example 1 is a base model, example2 is the known covariate model (i.e. it was apparently simulated). The base model is reconfigured and run through PSN::SCM and the final model is rerun as example 3. This analysis notebook template demonstrates a few key features of Rmarkdown and the qpToolkit functionality:

Note that a TOC with two levels is requested, so h2 and h3 headers (with two or three hashes) will be presented. One suggestions is to start each major analysis step with an h2 header, and place subsequent major sections in h3 headers.

A key feature of this template is the use of a subreport to show model results. Within a given project, it is assumed that one would like to review model results in a consistent manner (same plots, tables, etc.). The sub report eliminates repetitious coding of these features.

IMPORTANT NOTE: Be sure to place your copy of /utils and drive.r in the project folder. These are not included in order to save space.

Dataset

The dataset used in this study is the example1.csv from the NONMEM examples. The example2.csv dataset is the same but has the covariates added.

Exploratory Data Analysis

data.df <- read.csv(file.path(nm.path,"example2.csv"),skip=1)
data.df %<>% dplyr::rename(EVID = E,MDV = M, DV = CONC)

Spaghetti Plot

It make make sense to stratify the plots by dose, day, cycle, etc...

ggplot(subset(data.df,EVID==0), aes(x=TIME,y=DV,group=ID)) + geom_line() + 
  scale_y_log10() +
  theme_bw() + labs(x="Time (h)", y="Concentration (ng/ml)")
With smoother on mean
ggplot(subset(data.df,EVID==0), aes(x=TIME,y=DV,group=ID)) + geom_line(alpha=.2) + 
  theme_bw() + 
  labs(x="Time (h)", y="Concentration (ng/ml)") + scale_y_log10() + 
  stat_summary(aes(group=NULL),fun.data = "mean_cl_normal", colour = "red", geom="smooth")

Covariate Correlations

If you have the GGally package, enable the code in this section.

library(GGally)
library(Hmisc)
cov.names = Cs(Gender,Age)
covs.df = data.df[!duplicated(data.df$ID),cov.names]
covs.df$Gender = as.factor(c("M","F")[covs.df$Gender+1])
p.cov.corr.png = ggpairs(covs.df, diag=list(continuous="density", discrete="bar"), axisLabels="show")
print(p.cov.corr.png)

Structural models

This shows how to pick up runrecord information. When using PSN::runrecord be sure to set -max_lvl=0.

Run Directory Comparison

rr =  read.runrec("AAruninfo.txt",nm.path)
kable(process.runrec(rr,plain=T),row.names=F)

One compartment is clearly sufficient.

Example 1: Base Model

This starts a subreport on run: example 1

run="example1"
out = get.xpose.tables(run, path = nm.path)
trellis.strip.color()
xyplot(CWRES ~ value | variable
             , data = reshape2::melt(subset(out,EVID==0), measure.vars=Cs(PRED,TIME))
             , panel = panel.cwres
             , xlab = list('Time after Dose',cex=1.25),
             , ylab = list('Conditional weighted residuals', cex = 1.25),
             , aspect = 1,
             , as.table = T
   )

xyplot(Cbind(CONC,PRED,IPRED,EVID) ~ TIME | ID
       , groups = ID
       , data = subset(out, EVID!=1 & ID %in% unique(ID)[1:16])
       , scales = list(x = list(relation = 'free'),y = list(log=10))
       , panel = panel.modelfit
       , logY = T
       , yscale.components = yscale.components.log10
)

Write some notes about the GOF here. You can use the text in presentations or reports.

Covariate modeling

Covariate Signals

nm.covplot explores post-hoc fits vs covariates.

cov = nm.covplot("example2",path=nm.path,covlist=list(cat=c("GNDR"),con=c("AGE"))
                 ,parameters = Cs("CL","V1"), eta.skip=Cs(ETA3,ETA4))

cov$parContVarPlot()
cov$parCatVarPlot()

Eta covariate plots

The covariate plots can also be made for etas, to detect bias.

cov$eta.dens()
cov$eta.splom()
cov$etaContVarPlot()
cov$etaCatVarPlot()

SCM Model Building

Print the steps in the process. Here we grab the results and format them for markdown.

path <- file.path(nm.path, "scm_example2")

cat("\n#### Summary of Steps \n")
path %>%
  nm.process.scm %>%
  filter(chosen == 1) %>%
  select(step, model, direction, pvalue) %>%
  alias %>%
  resolve %>%
  kable

cat("\n#### Model Building Steps \n")
path %>%
  nm.process.scm %>%
  #filter(chosen == 1) %>%
  #select(step, model, direction, pvalue) %>%
  alias %>%
  resolve %>%
  kable

Final Model

run="example3"
out = get.xpose.tables(run, path = nm.path)
trellis.strip.color()
xyplot(CWRES ~ value | variable
             , data = reshape2::melt(subset(out,EVID==0), measure.vars=Cs(PRED,TIME))
             , panel = panel.cwres
             , xlab = list('Time after Dose',cex=1.25),
             , ylab = list('Conditional weighted residuals', cex = 1.25),
             , aspect = 1,
             , as.table = T
   )

xyplot(Cbind(CONC,PRED,IPRED,EVID) ~ TIME | ID
       , groups = ID
       , data = subset(out, EVID!=1 & ID %in% unique(ID)[1:16])
       , scales = list(x = list(relation = 'free'),y = list(log=10))
       , panel = panel.modelfit
       , logY = T
       , yscale.components = yscale.components.log10
)

Parameter estimates

These should come from parTab, converted to a list or even just the estimates transposed. ETAs need to be inserted as zeros. Need to add a utility function for this.

params.df = nm.params.table("example3",path=nm.path)
kable(params.df)

Good diagnostics. Parameter estimates are precise, with Theta CV% generally <15-20%.

How much structural model variance is explained?

xml.base=nm.extract.xml("example1",nm.path)
xml.final=nm.extract.xml("example3",nm.path)

w.base=c(diag(make.symmetric(xml.base$omega[[5]],triangle="lower")))
         #,diag(make.symmetric(xml.base$sigma[[5]] ,triangle="lower")))
w.final=c(diag(make.symmetric(xml.final$omega[[1]],triangle="lower")))
         #,diag(make.symmetric(xml)))
w.names = c(paste("ETA",1:(length(xml.base$etabar[[1]][[1]]))))
            #,paste("SIGMA",1:(length(xml.base$epsshrink[[1]]))))
var.df = data.frame(Parameter=w.names,Base=w.base,Final=w.final) 
var.df$Explained=1-var.df$Final/var.df$Base
kable(var.df)

Covariate Effect Plots

Create equations for V1 and CL. If you add a list called "label", the elements will be used on the y axes of plots.

eqs=make.eqs(CL=THETA1*(1 + (GNDR==0)*THETA7)*(AGE/33.72)^THETA6*exp(ETA1)
             ,V1=THETA2*(1 + (GNDR==0)*THETA9)*(AGE/33.72)^THETA8*exp(ETA2)
             )
eqs$label=list(CL="Clearance (L/h)", V1="Volume of Central Compartment (L)")

Now get the parameter values and pack into a list. Add the ETA elements (only need two).

params.l=as.list(setNames(params.df$Estimate,params.df$Parameter))
params.l$ETA1=0
params.l$ETA2=0

Create covariate object

xpose.df = get.xpose.tables("example3",nm.path)
xpose.df = xpose.df[!duplicated(xpose.df$ID),c("GNDR","AGE","CL","V1")]
covs.info = makeCovInfo(xpose.df[,c("GNDR","AGE")],cat.covs = "GNDR")
covs.info$GNDR$label = "Gender (0: female, 1: male)"
covs.info$AGE$label = "Age (Y)"
covs.info$AGE$breaks = c(1:5,(1:8)*10)
covs.info$AGE$center=33.72

Print the plots

tmp = nm.extract.xml("example3",nm.path)
coveffs.l = nm.process.coveffects(eqs = eqs
                                  , covs.info = covs.info
                                  , pars = data.frame(params.l)
                                  , xpose.df = xpose.df
                                  , omega = make.symmetric(
                                     unlist(tmp$omega),triangle = "upper")
)

# plot(coveffs.l)
eqs=make.eqs(
  CL=THETA1*(1 + (GNDR==0)*THETA7)*(AGE/33.72)^THETA6*exp(ETA1),
  V1=
    THETA2*
    (1 + (GNDR==0)*THETA9)*
    (1 + (SEX==0)*THETA10)*
    (1 + (MALE==0)*THETA11)*
    (AGE/33.72)^THETA8*
    exp(ETA2)
)
eqs$label=list(CL="Clearance (L/h)", V1="Volume of Central Compartment (L)")

xpose.df$SEX <- xpose.df$GNDR
xpose.df$MALE <- xpose.df$GNDR
params.l$THETA10 <- params.l$THETA9
params.l$THETA11 <- params.l$THETA9
covs.info$SEX <- covs.info$GNDR
covs.info$MALE <- covs.info$GNDR
covs.info$SEX$name <- 'SEX'
covs.info$MALE$name <- 'MALE'

coveffs.l = nm.process.coveffects(
  eqs = eqs,
  covs.info = covs.info,
  pars = data.frame(params.l),
  xpose.df = xpose.df,
  omega = make.symmetric(
    unlist(tmp$omega), 
    triangle = "upper")
)
plot(coveffs.l)
eqs=make.eqs(
  CL=THETA1*(1 + (GNDR==0)*THETA7)*(AGE/33.72)^THETA6*exp(ETA1),
  V1=
    THETA2*
    (1 + (GNDR==0)*THETA9)*
    (1 + (SEX==0)*THETA10)*
    (1 + (MALE==0)*THETA11)*
    (AGE/33.72)^THETA8*
    exp(ETA2)
)
eqs$label=list(CL="Clearance (L/h)", V1="Volume of Central Compartment (L)")

xpose.df$SEX <- xpose.df$GNDR
xpose.df$MALE <- xpose.df$GNDR
params.l$THETA10 <- params.l$THETA9
params.l$THETA11 <- params.l$THETA9
covs.info$SEX <- covs.info$GNDR
covs.info$MALE <- covs.info$GNDR
covs.info$SEX$name <- 'SEX'
covs.info$MALE$name <- 'MALE'

coveffs.l = nm.process.coveffects(
  eqs = eqs,
  covs.info = covs.info,
  pars = data.frame(params.l),
  xpose.df = xpose.df,
  omega = make.symmetric(
    unlist(tmp$omega), 
    triangle = "upper")
)
plot(coveffs.l)
eqs=make.eqs(
  CL=THETA1*(1 + (GNDR==0)*THETA7)*(AGE/33.72)^THETA6*exp(ETA1),
  V1=
    THETA2*
    (1 + (GNDR=='male')*THETA9)*
    (AGE/33.72)^THETA8*
    exp(ETA2)
)
eqs$label=list(CL="Clearance (L/h)", V1="Volume of Central Compartment (L)")
library(magrittr)

xpose.df %<>% mutate(GNDR = recode(GNDR, `0` = 'female',`1` = 'male'))
covs.info = makeCovInfo(xpose.df[,c("GNDR","AGE")],cat.covs = "GNDR")
covs.info$GNDR$label = "Gender (female, male)"
covs.info$AGE$label = "Age (Y)"
covs.info$AGE$breaks = c(1:5,(1:8)*10)
covs.info$AGE$center=33.72

coveffs.l = nm.process.coveffects(
  eqs = eqs,
  covs.info = covs.info,
  pars = data.frame(params.l),
  xpose.df = xpose.df,
  omega = make.symmetric(
    unlist(tmp$omega), 
    triangle = "upper")
)
plot(coveffs.l)

VPC Final Model

First plot is xpose (preferred) style, second is simplified style.

myVPC = nm.read.vpc(path = file.path(nm.path, "vpc_final_strt"), PI.ci.area.smooth = T)
ggvpc_xpose(myVPC, point.size = 2) + scale_y_log10() + facet_wrap(~strata)
ggvpc_standard(myVPC, point.size = 2) + scale_y_log10() + facet_wrap(~strata)


qPharmetra/qpToolkit documentation built on May 24, 2023, 8:52 a.m.