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.
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.
data.df <- read.csv(file.path(nm.path,"example2.csv"),skip=1) data.df %<>% dplyr::rename(EVID = E,MDV = M, DV = CONC)
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)")
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")
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)
This shows how to pick up runrecord information. When using PSN::runrecord be sure to set -max_lvl=0.
rr = read.runrec("AAruninfo.txt",nm.path) kable(process.runrec(rr,plain=T),row.names=F)
One compartment is clearly sufficient.
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.
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()
The covariate plots can also be made for etas, to detect bias.
cov$eta.dens() cov$eta.splom() cov$etaContVarPlot() cov$etaCatVarPlot()
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
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 )
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%.
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)
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)
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)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.