knitr::opts_chunk$set(echo = FALSE) requireNamespace("pmxTools") library(PKNCA) library(dplyr) library(ggplot2) library(tidyr) library(purrr) breaks_hours <- function(n=5, Q=c(1, 6, 4, 12, 2, 24, 168), ...) { n_default <- n Q_default <- Q function(x, n = n_default, Q=Q_default) { x <- x[is.finite(x)] if (length(x) == 0) { return(numeric()) } rng <- range(x) labeling::extended(rng[1], rng[2], m=n, Q=Q, ...) } } scale_x_hours <- function(..., breaks=breaks_hours()) { ggplot2::scale_x_continuous(..., breaks=breaks) }
Creation of these materials were partially supported by funding from the Metrum Research Group.
PKNCA is a tool for calculating noncompartmental analysis (NCA) results for pharmacokinetic (PK) data.
... but, you already knew that or you wouldn't be here.
PKNCA has several foci:
I hope that you have a whale of a good time during this training.
(Foreshadowing...)
"Tidy datasets... have a specific structure: each variable is a column, each observation is a row, and each type of observational unit is a table." - Hadley Wickham (https://doi.org/10.18637/jss.v059.i10)
CDISC has NCA tidied, and PKNCA follows that model:
PKNCAconc()
object)PKNCAdose()
object)pk.nca()
output)PKNCA requires at least the concentration, time, and what you want to calculate.
conc <- datasets::Theoph %>% filter(Subject %in% 1) ggplot(conc, aes(x=Time, y=conc)) + geom_line() + scale_x_hours()
Column names are provided by the input to PKNCAconc()
and PKNCAdose()
; they are not hard-coded.
Columns that can be used include:
PKNCAconc()
: concentration, time, groups; data exclusions; half-life inclusion and exclusionPKNCAdose()
: dose, time, groups; route, rate/duration of infusion; data exclusionsPKNCAdata()
: groups, start, end, and any NCA parameters to calculateIn the following slides, abbreviated data from an example study where two treatments ("A" and "B") are administered to two subjects (1 and 2).
/
, if /
is present)....|Treatment+Subject
), PKNCA automatically knows to keep Treatment and drop Subject for summaries (more on that later).conc_data <- withr::with_seed(5, { data.frame( Subject=rep(1:2, each=6), Treatment=rep(c("A", "B", "A", "B"), each=3), Time=rep(c(0, 2, 8), 4), Conc=rep(c(0, 2, 0.5), 4)*exp(rnorm(n=12, sd=0.05)) ) })
pander::pander(conc_data %>% filter(Subject == 1))
pander::pander(conc_data %>% filter(Subject == 2))
dose_data <- data.frame( Subject=rep(1:2, each=2), Treatment=c("A", "B", "A", "B"), Time=0, Dose=10 )
pander::pander(dose_data %>% filter(Subject == 1))
pander::pander(dose_data %>% filter(Subject == 2))
d_interval_1 <- data.frame( start=0, end=8, cmax=TRUE, tmax=TRUE, auclast=TRUE )
pander::pander(d_interval_1)
Groups are not required, if you want the same intervals calculated for each group.
library(dplyr) library(ggplot2) library(tidyr) library(purrr) library(PKNCA) # Concentration data setup d_conc <- datasets::Theoph %>% filter(Subject %in% 1) o_conc <- PKNCAconc(conc~Time, data=d_conc) # Setup intervals for calculation d_intervals <- data.frame(start=0, end=24, cmax=TRUE, tmax=TRUE, auclast=TRUE, aucint.inf.obs=TRUE) # Combine concentration and dose o_data <- PKNCAdata(o_conc, intervals=d_intervals) # Calculate the results (suppressMessages() hides a message that isn't needed now) o_result <- suppressMessages(pk.nca(o_data)) # summary(o_result)
PKNCAconc()
: define a concentration-time PKNCAconc
objectPKNCAdose()
: define a dose-time PKNCAdose
object (optional)PKNCAdata()
: combine PKNCAconc
, optionally PKNCAdose
, and optionally intervals
into a PKNCAdata
objectPKNCAconc
object must be given; the PKNCAdose
object is optional; interval definitions are usually given; calculation options may be givenpk.nca()
: calculate the NCA parameters from a data object into a PKNCAresult
objectWe will break this down in subsequent slides.
# Concentration data setup d_conc <- datasets::Theoph %>% filter(Subject %in% 1) o_conc <- PKNCAconc(conc~Time, data=d_conc) # Dose data setup d_dose <- datasets::Theoph %>% filter(Subject %in% 1) %>% filter(Time == 0) o_dose <- PKNCAdose(Dose~Time, data=d_dose) # Combine concentration and dose o_data <- PKNCAdata(o_conc, o_dose) # Calculate the results o_result <- pk.nca(o_data)
# Load your dataset as a data.frame d_conc <- datasets::Theoph %>% filter(Subject %in% 1) # Take a look at the data pander::pander(head(d_conc, 2)) # Define the PKNCAconc object indicating the concentration and time columns, the # dataset, and any other options. o_conc <- PKNCAconc(conc~Time, data=d_conc)
# Load your dataset as a data.frame d_dose <- datasets::Theoph %>% filter(Subject %in% 1) %>% filter(Time == 0) # Take a look at the data pander::pander(d_dose) # Define the PKNCAdose object indicating the dose amount and time columns, the # dataset, and any other options. o_dose <- PKNCAdose(Dose~Time, data=d_dose)
# Combine the PKNCAconc and PKNCAdose objects. You can add interval # specifications and calculation options here. o_data <- PKNCAdata(o_conc, o_dose) # Calculate the results o_result <- pk.nca(o_data)
To calculate summary statistics, use summary()
; to extract all individual-level results, use as.data.frame()
.
The "caption"
attribute of the summary describes how the summary statistics were calculated for each parameter. (Hint: pander::pander()
knows how to use that to put the caption on a table in a report.)
The individual results contain the columns for start time, end time, grouping variables (none in this example), parameter names, values, and if the value should be excluded.
# Look at summarized results pander::pander(summary(o_result))
Use as.data.frame()
to get the individual NCA parameter results.
# Look at individual results pander::pander(head( as.data.frame(o_result), n=3 ))
Three types of data are inputs for calculation in PKNCA:
PKNCAconc
),PKNCAdose
), andPKNCAconc
and PKNCAdose
objects can optionally have groups. The groups in a PKNCAdose
object must be the same or fewer than the groups in PKNCAconc
object (for example, all subjects in a treatment arm may receive the same dose).
last_dose_time <- 24 dose_interval <- 8 dose_times <- seq(0, last_dose_time-dose_interval, by=dose_interval) d_conc_superposition <- superposition( o_conc, dose.times=dose_times, tau=last_dose_time, check.blq=FALSE, n.tau=1 )
A group separates one full concentration-time profile for a subject that you may ever want to consider at the same time. Usually, it groups by study, treatment, analyte, and subject (other groups can be useful depending on the study design).
An interval selects a time range within a group.
One time can be in zero or more intervals, but only zero or one group. Intervals can be adjacent (0-12 and 12-24) or overlap (0-12 and 0-24). In other words, one sample may be used in more than one interval, but one sample will never be used in more than one group.
Legend: The group contains all points on the figure. Shaded regions indicate intervals. Arrows indicate points shared between intervals within the group.
d_intervals <- tibble( start=dose_times, end=dose_times + dose_interval ) %>% mutate( name=sprintf("Interval %g", row_number()), height=max(d_conc_superposition$conc)*1.03, width=dose_interval, x=(start+end)/2, y=height/2 ) d_interval_arrows <- d_conc_superposition %>% filter(time != 0 & time %in% dose_times) %>% mutate( name1=sprintf("Interval %g", row_number()), name2=sprintf("Interval %g", row_number() + 1), ) ggplot(d_conc_superposition, aes(x=time, y=conc)) + geom_tile( data=d_intervals, aes(x=x, y=y, width=width, height=height, colour=name, fill=name), alpha=0.2, inherit.aes=FALSE, show.legend=FALSE ) + geom_segment( data=d_interval_arrows, aes(x=time - 0.8, xend=time - 0.1, y=conc-2.1, yend=conc - 0.1, colour=name2), arrow=arrow(length=unit(0.1, "inches")), inherit.aes=FALSE, show.legend=FALSE ) + geom_segment( data=d_interval_arrows, aes(x=time + 0.8, xend=time + 0.1, y=conc-2.1, yend=conc - 0.1, colour=name1), arrow=arrow(length=unit(0.1, "inches")), inherit.aes=FALSE, show.legend=FALSE ) + geom_line() + geom_point() + scale_x_hours() + labs( title=sprintf("Dosing Q%gH", dose_interval) )
PKNCAconc
(if given to PKNCAdose
, it must not be missing).NA
).Columns must be created for:
Normal dosing data setup: PKNCAdose(dose~time|actarm+usubjid, data=d_dose)
PKNCAdose(~time|actarm+usubjid, data=d_dose)
PKNCAdose(dose~.|actarm+usubjid, data=d_dose)
PKNCAdose(dose~time|actarm, data=d_dose)
PKNCAdose(dose~.|actarm, data=d_dose)
PKNCAdose(~time|actarm, data=d_dose)
Intervals have columns for:
start
and end
times for the interval,TRUE
means to calculate it; FALSE
means don't). The full list of available parameters is in the selection of calculation intervals vignette.PKNCA.options("single.dose.aucs") %>% select(c(all_of(c("start", "end")), where(~is.logical(.x) && any(.x)))) %>% pander::pander()
d_conc <- datasets::Theoph %>% mutate( Treatment= case_when( Dose <= median(Dose)~"Low dose", TRUE~"High dose" ) ) # The study was single-dose d_dose <- d_conc %>% select(Treatment, Subject, Dose) %>% unique() %>% mutate(dose_time=0)
o_conc <- PKNCAconc(conc~Time|Treatment+Subject, data=d_conc) try({ o_data <- PKNCAdata(o_conc) summary(pk.nca(o_data)) })
Whoops! Without dosing, we need intervals.
o_conc <- PKNCAconc(conc~Time|Treatment+Subject, data=d_conc) d_intervals <- data.frame(start=0, end=Inf, cmax=TRUE, tmax=TRUE, half.life=TRUE, aucinf.obs=TRUE) o_data_manual_intervals <- PKNCAdata(o_conc, intervals=d_intervals) summary(pk.nca(o_data_manual_intervals))
o_conc <- PKNCAconc(conc~Time|Treatment+Subject, data=d_conc) o_dose <- PKNCAdose(Dose~dose_time|Treatment+Subject, data=d_dose) o_data_auto_intervals <- PKNCAdata(o_conc, o_dose) o_data_auto_intervals$intervals$aucint.inf.obs <- TRUE summary(pk.nca(o_data_auto_intervals))
d_conc <- datasets::Theoph %>% filter(Subject == 1) o_conc <- PKNCAconc(conc~Time, data=d_conc) d_interval_int <- data.frame(start=0, end=Inf, half.life=TRUE) o_data_int <- PKNCAdata(o_conc, intervals=d_interval_int) o_nca_int <- suppressMessages(pk.nca(o_data_int)) lambda_z_int <- o_nca_int %>% as.data.frame() %>% filter(PPTESTCD %in% "lambda.z") %>% "[["("PPORRES") d_interval_inf <- data.frame(start=0, end=24, half.life=TRUE) o_data_inf <- PKNCAdata(o_conc, intervals=d_interval_inf) o_nca_inf <- suppressMessages(pk.nca(o_data_inf)) lambda_z_inf <- o_nca_inf %>% as.data.frame() %>% filter(PPTESTCD %in% "lambda.z") %>% "[["("PPORRES") tlast <- o_nca_inf %>% as.data.frame() %>% filter(PPTESTCD %in% "tlast") %>% "[["("PPORRES") d_auc_calcs <- d_conc %>% bind_rows( tibble(Time=seq(12, 60)) ) %>% mutate( conc_all_int= interp.extrap.conc( conc=conc[!is.na(conc)], time=Time[!is.na(conc)], time.out=Time, lambda.z=lambda_z_int ), conc_all_inf= interp.extrap.conc( conc=conc[!is.na(conc) & Time <= 24], time=Time[!is.na(conc) & Time <= 24], time.out=Time, lambda.z=lambda_z_inf ), conc_last= case_when( Time <= 24~conc, TRUE~NA_real_ ), conc_int= case_when( Time <= 24 & Time >= tlast~conc_all_int, TRUE~NA_real_ ), conc_inf= case_when( Time >= tlast~conc_all_inf, TRUE~NA_real_ ) ) %>% arrange(Time) auc_figure_time_max <- 36 p_auc_calcs <- ggplot(d_auc_calcs, aes(x=Time, y=conc)) + # AUCinf (with a work-around for https://github.com/tidyverse/ggplot2/issues/4661) geom_area( data=d_auc_calcs %>% filter(Time <= auc_figure_time_max), aes(y=conc_inf, colour="AUCinf", fill="AUCinf"), alpha=0.2, na.rm=TRUE ) + geom_line( data=d_auc_calcs, aes(y=conc_inf, colour="AUCinf"), na.rm=TRUE ) + # AUCint geom_area( aes(y=conc_int, colour="AUCint", fill="AUCint"), alpha=0.2, na.rm=TRUE ) + # AUClast geom_area( aes(y=conc_last, colour="AUClast", fill="AUClast"), na.rm=TRUE ) + geom_point(show.legend=FALSE, na.rm=TRUE) + geom_line(show.legend=FALSE, na.rm=TRUE) + geom_vline(xintercept=24, linetype="63") + scale_x_continuous(breaks=seq(0, auc_figure_time_max, by=6)) + coord_cartesian(xlim=c(0, auc_figure_time_max)) + labs( colour="AUC type", fill="AUC type" )
p_auc_calcs
The considerations below mainly apply to actual-time data; nominal-time data usually have measurements at the start and end time for the interval.
With an interval start and end of 0 and 24 (and the last measurement time just after 24 hours):
p_auc_calcs
The considerations below mainly apply to actual-time data; nominal-time data usually have measurements at the start and end time for the interval.
With an interval start and end of 0 and 24 (and the last measurement time just after 24 hours):
p_auc_calcs
The considerations below mainly apply to actual-time data; nominal-time data usually have measurements at the start and end time for the interval.
With an interval start and end of 0 and 24 (and the last measurement time just after 24 hours):
end=Inf
).The data for the exercise are from a PK study of amikacin in a killer whale and a beluga whale. (DOI: 10.1638/03-078)
(Callback...)
library(PKNCA) d_conc <- read.csv("c:/tmp/whale_conc.csv") d_dose <- read.csv("c:/tmp/whale_dose.csv") head(d_conc) head(d_dose) o_conc <- PKNCAconc(concentration~time|Animal, data=d_conc) o_dose <- PKNCAdose(dose~time|Animal, data=d_dose) o_data <- PKNCAdata(o_conc, o_dose) o_data$intervals o_nca <- pk.nca(o_data) summary(o_nca) summary(o_nca, drop.group=c()) as.data.frame(o_nca)
Data may be included/excluded in two ways:
For both ways of including/excluding data, it is defined by a column in the input data. The column is either NA
or an empty string (""
) to indicate "no" or any other text to indicate "yes".
Use the exclude
argument for PKNCAconc()
or PKNCAdose()
.
When you use exclude
, this is how you give your data to PKNCA:
d_before_exclude <- data.frame( time=0:4, conc=c(0, 2, 1, 0.5, 0.25), not_this=c(NA, "Not this", rep(NA, 3)) ) o_conc <- PKNCAconc( data=d_before_exclude, conc~time, exclude="not_this" )
And, this is how PKNCA thinks about it:
pander::pander( d_before_exclude %>% filter(is.na(not_this)) )
o_conc <- PKNCAconc(data=d_before_exclude, conc~time, exclude="not_this")
allow.tmax.in.half.life=TRUE
) to t~last~ and excluding BLQ in the middle.min.hl.points
option) to t~last~.adj.r.squared.factor
).> 0
.Note: WinNonlin first requires λz> 0
then selects for adjusted r^2^. Therefore, WinNonlin will occasionally provide a half-life when PKNCA will not, but the fit line is not as good (as measured by r^2^). The selection of filtering order is an intentional feature with PKNCA, and it generally has minimal impact on summary statistics because the quality of the half-life fit is usually low in this scenario.
Use the exclude_half.life
or include_half.life
argument for PKNCAconc()
. The two arguments behave very differently in how points are selected for half-life.
exclude_half.life
uses the same automatic point selection method of curve stripping (described before), but it excludes individual points from that calculation.
include_half.life
uses no automatic point selection method, and only points specifically noted by the analyst are included.
d_urine <- data.frame( conc=c(1, 2, 3), urine_volume=c(200, 100, 300), time=c(1, 2, 3) ) o_conc <- PKNCAconc(data=d_urine, conc~time, volume="urine_volume") d_intervals <- data.frame(start=0, end=24, ae=TRUE) o_data <- PKNCAdata(o_conc, intervals=d_intervals) o_nca <- suppressMessages(pk.nca(o_data)) summary(o_nca)
Intervals for urine are treated the same as any other interval type. Specifically, PKNCA does not look outside the start and end of the interval.
If you don't need a parameter, PKNCA won't calculate it.
For example, if all you need is cmax
, all you'll get is cmax
.
o_conc <- PKNCAconc(data=data.frame(conc=2^-(1:4), time=0:3), conc~time) o_data <- PKNCAdata(o_conc, intervals=data.frame(start=0, end=Inf, cmax=TRUE)) o_nca <- suppressMessages(pk.nca(o_data)) as.data.frame(o_nca)
If you need AUC~0-\infty~, PKNCA will calculate other required parameters behind the scenes.
o_data <- PKNCAdata( o_conc, intervals= data.frame( start=0, end=Inf, aucinf.obs=TRUE ) ) o_nca <- suppressMessages(pk.nca(o_data))
as.data.frame(o_nca)
r sum(grepl(x=names(PKNCA.options("single.dose.aucs")), pattern="^auc"))
types of AUC in PKNCA?)CDISC has one set of names, but they are not precise (e.g. AUCINT doesn't tell the interpolation/extrapolation method).
PKNCA tries to be everything to everyone (in terms of parameters calculated), and it simultaneously tries to be precise. That yields many parameters.
See the Selection of Calculation Intervals vignette in the Parameters Available for Calculation in an Interval section for all available parameters.
Very few parameters reach outside of the start
and end
of an interval for additional information about what is being calculated. As of the writing of these training materials (PKNCA version 0.9.5), the only parameters that look outside are the aucint
class of parameters.
AUC~int~ may look after the end of the interval to calculate the concentration at end
.
Note: Watch out for a dose before the next concentration (e.g. a dose at 24 hours but the prior sample is around 12 and the next is around 25):
d_prep <- datasets::Theoph %>% filter(Subject == 1) %>% mutate( conc= case_when( Time == 0~0, TRUE~conc ) ) d_plot <- superposition( conc=d_prep$conc, time=d_prep$Time, tau=48, n.tau=1, dose.times=24*(0:1) ) %>% # Pretend that we missed the predose sample filter( !between(time, 23, 24.5) ) # Pretend that there was a dose at 24 ggplot(d_plot, aes(x=time, y=conc)) + geom_point() + geom_line() + geom_vline(xintercept=24) + scale_x_hours()
A simple way to exclude a value from results is to convert the results to a data.frame and then drop the rows you don't want:
o_conc <- PKNCAconc(data=data.frame(conc=2^-(1:4), time=0:3), conc~time) o_data <- PKNCAdata( o_conc, intervals= data.frame( start=0, end=Inf, aucinf.obs=TRUE ) ) o_nca <- suppressMessages(pk.nca(o_data))
as.data.frame(o_nca) %>% filter(PPTESTCD != "half.life")
But, parameters derived from half-life remain.
When you use the exclude()
function, parameters that are dependent on an excluded parameter will be excluded.
o_nca_excluded <- o_nca %>% exclude(FUN=exclude_nca_span.ratio(3)) as.data.frame(o_nca_excluded)
Now, everything dependent on the half-life is excluded in summaries.
summary(o_nca) summary(o_nca_excluded)
Superposition assumes linear kinetics and can convert a single-dose profile to multi-dose.
# Subject 2 is selected for a BLQ time=0 concentration d_prep <- datasets::Theoph %>% filter(Subject == 2) # Superposition to steady-state is the default d_ss <- superposition( conc=d_prep$conc, time=d_prep$Time, tau=24 ) # Going to steady-state is also an option # (n.tau=2 means the second dose) d_second_dose <- superposition( conc=d_prep$conc, time=d_prep$Time, tau=24, n.tau=2 )
# Want the profile for the first two doses # together? d_first_two <- superposition( conc=d_prep$conc, time=d_prep$Time, tau=48, # 48 hours n.tau=1, # One tau interval (0 to 48 hours) dose.times=c(0, 24) )
ggplot(d_ss, aes(x=time, y=conc)) + geom_point() + geom_line() + scale_y_continuous(limits=c(0, NA))
Time-to-steady-state (tss) can be useful as a method to confirm that a subject is at steady-state. PKNCA can calculate tss using trough concentrations either with a monoexponential increase toward steady-state (preferred) or a linear trend back from the final point.
dose_times <- seq(0, 96-1, by=6) d_multidose <- superposition( conc=d_prep$conc, time=d_prep$Time, tau=96, # 48 hours n.tau=1, # One tau interval (0 to 48 hours) dose.times=dose_times ) pk.tss.monoexponential( conc=d_multidose$conc, time=d_multidose$time, subject=rep(1, nrow(d_multidose)), time.dosing=dose_times, subject.dosing=rep(1, length(dose_times)), output="single" )
Generate all individual profiles using the groups that you defined:
o_conc <- PKNCAconc(conc~Time|Subject, data=datasets::Theoph) d_plot <- grouped_df(data=datasets::Theoph, vars=names(getGroups(o_conc))) %>% nest() %>% mutate( figure= lapply( pmap(.l=list(data=data), .f=ggplot,aes(x=Time, y=conc)), FUN="+", geom_line() ) ) # d_plot$figure
Make summary tables using the summary()
function on the NCA results, and use pander::pander()
to make a pretty table with captions.
pander::pander(summary(o_nca))
Make an NCA data listing using the as.data.frame()
function on the NCA results.
pander::pander(as.data.frame(o_nca))
PKNCA supports units with the pknca_units_table()
function. See the
Unit Assignment and Conversion with PKNCA
vignette for more information.
When units are not specified, The most common place where that becomes an issue is with clearance which ends up having unusual units like "mg/(hr*ng/mL)" (with units of mg for dosing, hr for time, and ng/mL for concentration).
Some data points are required for inputs such as:
Due to the need for back-extrapolation to C~0~, AUCs for IV bolus dosing need to
use different AUC parameters such as "aucivlast"
instead of "auclast"
.
Sparse NCA calculations are supported in PKNCA. See the Sparse NCA Calculations vignette for more information.
PKNCA does not (yet) have the ability to calculate secondary PK parameters that require looking at more than one group/interval at a time.
PKNCA has an extensive testing and validation suite built-in. To run the testing and validation suite of tests with a full report generated, see the PKNCA Validation vignette.
d_conc <- datasets::Theoph %>% rename(time=Time) %>% mutate( Subject=as.character(Subject) ) d_multidose <- PKNCAconc(conc~time|Subject, data=d_conc) %>% superposition(tau=24, check.blq=FALSE) d_singledose_single_analyte <- d_conc %>% mutate( Study_Part="Single" ) d_multidose_single_analyte <- d_conc %>% mutate(Day=1) %>% bind_rows( d_multidose %>% mutate(time=time + 120, Day=6) ) %>% mutate( Study_Part="Multiple" )
d_single_multi_conc <- bind_rows(d_singledose_single_analyte, d_multidose_single_analyte) d_single_multi_dose <- d_single_multi_conc %>% filter( (Study_Part %in% "Single" & time == 0) | (Study_Part %in% "Multiple" & (time %% 24) == 0) )
o_conc <- PKNCAconc(data=d_single_multi_conc, conc~time|Study_Part+Subject) o_dose <- PKNCAdose(data=d_single_multi_dose, Dose~time|Study_Part+Subject) o_data <- PKNCAdata(o_conc, o_dose) o_data$intervals %>% select(-Subject) %>% unique() %>% as.data.frame() o_nca <- pk.nca(o_data)
d_intervals <- data.frame( start=0, end=24, Subject=c("1", "2"), Study_Part="Single", aucinf.obs=TRUE ) o_data <- PKNCAdata(o_conc, o_dose, intervals=d_intervals) o_nca <- pk.nca(o_data) summary(o_nca)
# Find the time closest to 12 hours d_intervals_prep <- d_single_multi_conc %>% filter(Study_Part == "Single") %>% mutate( time_deviation=abs(time-12) ) %>% group_by(Subject, Study_Part) %>% filter(time %in% time[time_deviation == min(time_deviation)]) d_intervals <- d_intervals_prep %>% select(Study_Part, Subject, end=time) %>% mutate( start=0, aucinf.obs=TRUE ) o_data <- PKNCAdata(o_conc, o_dose, intervals=d_intervals) o_nca <- pk.nca(o_data) summary(o_nca, drop.group=c("Subject", "end"))
d_single_multi_conc_multi_analyte <- bind_rows( d_single_multi_conc %>% mutate(Analyte="Parent"), d_single_multi_conc %>% mutate( Analyte="Metabolite", conc=conc/2 ) ) o_conc <- PKNCAconc( data=d_single_multi_conc_multi_analyte, conc~time|Study_Part+Subject/Analyte ) o_dose <- PKNCAdose(data=d_single_multi_dose, Dose~time|Study_Part+Subject) o_data <- PKNCAdata(o_conc, o_dose) o_nca <- pk.nca(o_data) summary(o_nca)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.