diff --git a/DESCRIPTION b/DESCRIPTION index 04e53671..19db13ea 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -5,7 +5,9 @@ Version: 0.11.0.9000 Authors@R: c( person("Bill", "Denney", email="wdenney@humanpredictions.com", role=c("aut", "cre"), comment=c(ORCID="0000-0002-5759-428X")), person("Clare", "Buckeridge", email="clare.buckeridge@pfizer.com", role="aut"), - person("Sridhar", "Duvvuri", role="ctb")) + person("Sridhar", "Duvvuri", role="ctb"), + person("Gerardo Jose", "Rodriguez", , "gerardo.jrac@gmail.com", role = "aut", comment = c(ORCID = "0000-0003-1413-0060")) + ) Imports: checkmate, dplyr (>= 0.5.0), diff --git a/NAMESPACE b/NAMESPACE index 16f86161..1e07f305 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -90,8 +90,10 @@ export(PKNCA.choose.option) export(PKNCA.options) export(PKNCA.options.describe) export(PKNCA.set.summary) +export(PKNCA_impute_method_start_c1) export(PKNCA_impute_method_start_cmin) export(PKNCA_impute_method_start_conc0) +export(PKNCA_impute_method_start_logslope) export(PKNCA_impute_method_start_predose) export(PKNCAconc) export(PKNCAdata) diff --git a/NEWS.md b/NEWS.md index b4234324..e0c583d4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -18,6 +18,8 @@ the dosing including dose amount and route. * `PKNCAconc()` and `PKNCAdose()` can now accept unit specifications as either column names or units to use (#336). +* New default PKNCA impute start methods for C1 and IV bolus logslope to add for + intervals without a start concentration * PKNCA options can now use `tmax` as a reference for BLQ handling by using new names in the `conc.blq` argument (`before.tmax`,`after.tmax`) diff --git a/R/impute.R b/R/impute.R index b691e81f..5e668be0 100644 --- a/R/impute.R +++ b/R/impute.R @@ -120,6 +120,53 @@ PKNCA_impute_method_start_predose <- function(conc, time, start, end, conc.group ret } +#' @describeIn PKNCA_impute_method Imputes based on a logarithmic slope on the +#' first points at time zero concentration (usually in IV bolus at dose time). +#' If this imputation is used for NCA calculations, back-extrapolation percent +#' will not be calculated or will be calculated as zero. +#' @export +PKNCA_impute_method_start_logslope <- function(conc, time, start, end, ..., options = list()) { # nolint + + ret <- data.frame(conc = conc, time = time) + mask_start <- time %in% start + if (!any(mask_start)) { + all_concs <- conc[time >= start & time <= end] + all_times <- time[time >= start & time <= end] + if (!all(is.na(all_concs))) { + c0 <- pk.calc.c0.method.logslope(conc = all_concs, + time = all_times, + time.dose = start) + if (!is.na(c0)) { + ret <- rbind(ret, data.frame(time = start, conc = c0)) + ret <- ret[order(ret$time), ] + } + } + } + ret +} + +#' @describeIn PKNCA_impute_method Shift the following concentration to a start +#' to become the time zero concentration (rarely used; non-monodecay IV bolus). +#' If this imputation is used for NCA calculations, back-extrapolation percent +#' will not be calculated or will be calculated as zero. +#' @return A data frame with imputed start concentration. +#' @export +PKNCA_impute_method_start_c1 <- function(conc, time, start, end, ..., options = list()) { # nolint + ret <- data.frame(conc = conc, time = time) + mask_start <- time %in% start + if (!any(mask_start)) { + assert_conc_time(conc, time) + all_concs <- conc[time >= start & time <= end] + all_times <- time[time >= start & time <= end] + c1 <- pk.calc.c0.method.c1(conc = all_concs, + time = all_times, + time.dose = start) + ret <- rbind(ret, data.frame(time = start, conc = c1)) + ret <- ret[order(ret$time), ] + } + ret +} + #' Separate out a vector of PKNCA imputation methods into a list of functions #' #' An error will be raised if the functions are not found. diff --git a/man/PKNCA_impute_method.Rd b/man/PKNCA_impute_method.Rd index 794b0672..a4cbe07f 100644 --- a/man/PKNCA_impute_method.Rd +++ b/man/PKNCA_impute_method.Rd @@ -5,6 +5,8 @@ \alias{PKNCA_impute_method_start_conc0} \alias{PKNCA_impute_method_start_cmin} \alias{PKNCA_impute_method_start_predose} +\alias{PKNCA_impute_method_start_logslope} +\alias{PKNCA_impute_method_start_c1} \title{Methods for imputation of data with PKNCA} \usage{ PKNCA_impute_method_start_conc0(conc, time, start = 0, ..., options = list()) @@ -22,6 +24,17 @@ PKNCA_impute_method_start_predose( max_shift = NA_real_, options = list() ) + +PKNCA_impute_method_start_logslope( + conc, + time, + start, + end, + ..., + options = list() +) + +PKNCA_impute_method_start_c1(conc, time, start, end, ..., options = list()) } \arguments{ \item{conc}{Measured concentrations} @@ -49,6 +62,8 @@ from start to \code{max(time)})} \value{ A data.frame with one column named conc with imputed concentrations and one column named time with the times. + +A data frame with imputed start concentration. } \description{ Methods for imputation of data with PKNCA @@ -65,4 +80,10 @@ the interval at the start time (usually used with multiple-dose data) \item \code{PKNCA_impute_method_start_predose()}: Shift a predose concentration to become the time zero concentration (only if a time zero concentration does not exist) +\item \code{PKNCA_impute_method_start_logslope()}: Imputes based on a logarithmic slope on the +first points a time zero concentration (usually in IV bolus at dose time) + +\item \code{PKNCA_impute_method_start_c1()}: Shift the following concentration to a start +to become the time zero concentration (rarely used; non-monodecay IV bolus) + }} diff --git a/tests/testthat/test-impute.R b/tests/testthat/test-impute.R index c71cf869..5866ec2e 100644 --- a/tests/testthat/test-impute.R +++ b/tests/testthat/test-impute.R @@ -92,6 +92,90 @@ test_that("PKNCA_impute_method_start_cmin", { }) +test_that("PKNCA_impute_method_start_logslope", { + # No imputation when start is in the data + expect_equal( + PKNCA_impute_method_start_logslope(conc = 3:1, time = 0:2, start = 0, end = 2), + data.frame(conc = 3:1, time = 0:2) + ) + # Impute when start is not in the data + expect_equal( + PKNCA_impute_method_start_logslope(conc = 3:1, time = 1:3, start = 0, end = 3), + data.frame(conc = c(4.5, 3:1), time = 0:3), + ignore_attr = TRUE + ) + # Data outside the interval are ignored (before interval) + expect_equal( + PKNCA_impute_method_start_logslope(conc = c(0, 2:1), time = c(-1, 1:2), start = 0, end = 2), + data.frame(conc = c(0, 4, 2:1), time = c(-1, 0, 1:2)), + ignore_attr = TRUE + ) + # No modification if no C1 -> C2 decline in samples + expect_equal( + PKNCA_impute_method_start_logslope(conc = c(1, 1, 1), time = 1:3, start = 0, end = 3), + data.frame(conc = c(1, 1, 1), time = 1:3), + ignore_attr = TRUE + ) + # No modification if C1 = C2 in samples + expect_equal( + PKNCA_impute_method_start_logslope(conc = c(3, 3, 1), time = 1:3, start = 0, end = 3), + data.frame(conc = c(3, 3, 1), time = 1:3), + ignore_attr = TRUE + ) + # All concentrations are NA -> does not change + expect_equal( + PKNCA_impute_method_start_logslope(conc = c(NA, NA, NA), time = 1:3, start = 0, end = 3), + data.frame(conc = c(NA, NA, NA), time = 1:3) + ) + # All times are NA -> does not change + expect_equal( + PKNCA_impute_method_start_logslope(conc = 1:3, time = c(NA, NA, NA), start = 0, end = 3), + data.frame(conc = 1:3, time = c(NA, NA, NA)) + ) + # All concentrations are 0 -> does not change + expect_equal( + PKNCA_impute_method_start_logslope(conc = c(0, 0, 0), time = 1:3, start = 0, end = 3), + data.frame(conc = c(0, 0, 0), time = 1:3) + ) +}) + +test_that("PKNCA_impute_method_start_c1", { + # No imputation when start is in the data + expect_equal( + PKNCA_impute_method_start_c1(conc = 1:3, time = 0:2, start = 0, end = 2), + data.frame(conc = 1:3, time = 0:2) + ) + # Impute when start is not in the data + expect_equal( + PKNCA_impute_method_start_c1(conc = 1:3, time = 1:3, start = 0, end = 3), + data.frame(conc = c(1, 1:3), time = 0:3), + ignore_attr = TRUE + ) + # Data outside the interval are ignored (before interval) + expect_equal( + PKNCA_impute_method_start_c1(conc = 1:3, time = c(-1, 1:2), start = 0, end = 2), + data.frame(conc = c(1, 2, 2:3), time = c(-1, 0, 1:2)), + ignore_attr = TRUE + ) + # All concentrations are NA + expect_equal( + PKNCA_impute_method_start_c1(conc = c(NA, NA, NA), time = 1:3, start = 0, end = 3), + data.frame(conc = c(NA, NA, NA, NA), time = 0:3), + ignore_attr = TRUE + ) + # All times are NA + expect_error( + PKNCA_impute_method_start_c1(conc = 1:3, time = c(NA, NA, NA), start = 0, end = 3), + "Assertion on 'time' failed: Contains missing values" + ) + # All concentrations are 0 + expect_equal( + PKNCA_impute_method_start_c1(conc = c(0, 0, 0), time = 1:3, start = 0, end = 3), + data.frame(conc = c(0, 0, 0, 0), time = 0:3), + ignore_attr = TRUE + ) +}) + test_that("PKNCA_impute_fun_list", { expect_equal( PKNCA_impute_fun_list(NA_character_),