From 6dd1b824efbe1d80f1e0d89a421de078259d5216 Mon Sep 17 00:00:00 2001 From: Audrey Yeo Date: Tue, 30 Jul 2024 18:20:38 +0200 Subject: [PATCH] 115 make website live (#116) Co-authored-by: 27856297+dependabot-preview[bot]@users.noreply.github.com <27856297+dependabot-preview[bot]@users.noreply.github.com> --- DESCRIPTION | 2 +- NAMESPACE | 1 + R/boundsPostprob.R | 75 ++++++++++++++-------------- examples/boundsPostprob.R | 14 +++--- man/boundsPostprob.Rd | 59 +++++++++++----------- tests/testthat/test-boundsPostProb.R | 33 ++++++++++++ 6 files changed, 107 insertions(+), 77 deletions(-) create mode 100644 tests/testthat/test-boundsPostProb.R diff --git a/DESCRIPTION b/DESCRIPTION index b568d599..d7f95063 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -44,7 +44,7 @@ Language: en-US LazyData: true Roxygen: list(markdown = TRUE, packages = "roxytypes") -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 Config/Needs/documentation: roxytypes Remotes: diff --git a/NAMESPACE b/NAMESPACE index c499d7fe..c908b935 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -6,6 +6,7 @@ export(dbetaMix) export(dbetabinom) export(dbetabinomMix) export(dbetadiff) +export(myPlot) export(myPlotDiff) export(oc2) export(oc3) diff --git a/R/boundsPostprob.R b/R/boundsPostprob.R index 09822eda..b50fee96 100644 --- a/R/boundsPostprob.R +++ b/R/boundsPostprob.R @@ -1,33 +1,29 @@ #' Decision cutpoints for boundary (based on posterior probability) #' #' This function is used to identify the efficacy and futility -#' boundaries based on posterior probabilities, i.e.: -#' Efficacy boundary: find minimum x (xU) where Pr(P>p0|x,n,a,b) >= tU and -#' Futility boundary: find maximum x (xL) where Pr(P>p1|x,n,a,b) <= tL +#' boundaries based on the following rules: +#' Efficacy boundary: find minimum x (xU) where Pr(P > p1 |x, n, a, b) >= tU and +#' Futility boundary: find maximum x (xL) where Pr(P < p0 | x, n, a, b) >= tL #' -#' @param nvec a vector of number of patients -#' @param p0 the efficacy threshold parameter in the postprob function -#' @param p1 the futility threshold parameter in the postprob function -#' (default = p0) -#' @param tL futility boundary probability threshold -#' @param tU efficacy boundary probability threshold -#' @param a the alpha parameter of the beta prior of treatment group -#' @param b the beta parameter of the beta prior of treatment group -#' @return A matrix where for each sample size in \code{nvec}, this function -#' returns the maximum number of responses that meet the futility -#' threshold (xL), its corresponding response rate (pL), posterior probability -#' (postL), upper bound of one sided 95% CI for the response rate based on an -#' exact binomial test (UciL), and the same boundary parameters for efficacy: -#' the minimal number of responses that meet the efficacy threshold (xU), -#' the corresponding response rate (pU), posterior probability (postU) and -#' the lower bound of one sided 95% CI for the response rate based on exact -#' binomial test (LciU). -#' -#' @importFrom stats binom.test +#' @inheritParams postprob +#' @inheritParams ocPostprob +#' @typed nvec : numeric +#' A vector of number of patients in each look. +#' @return A matrix for each same size in `nvec`. For each sample size, the following is returned: +#' - `xL` : the maximum number of responses that meet the futility. +#' threshold +#' - `pL` : response rate corresponding to `xL`. +#' - `postL`: posterior probability corresponding to `xL`. +#' - `pL_upper_ci` : upper bound of one sided 95% CI for the response rate `pL` based on an +#' exact binomial test. +#' - `xU` : the minimal number of responses that meet the efficacy threshold. +#' - `pU` : response rate corresponding to `xU`. +#' - `postU` : posterior probability corresponding to `xU`. +#' - `pU_lower_ci` : lower bound of one sided 95% CI for the response rate `pU` based on exact +#' binomial test. #' #' @example examples/boundsPostprob.R #' @export -#' @keywords graphics boundsPostprob <- function(nvec, p0, p1 = p0, tL, tU, a, b) { z <- matrix(NA, length(nvec), 6) dimnames(z) <- list(nvec, c( @@ -35,8 +31,8 @@ boundsPostprob <- function(nvec, p0, p1 = p0, tL, tU, a, b) { "xU", "pU", "postU" )) znames <- c( - "xL", "pL", "postL", "UciL", - "xU", "pU", "postU", "LciU" + "xL", "pL", "postL", "pL_upper_ci", + "xU", "pU", "postU", "pU_lower_ci" ) z <- matrix(NA, length(nvec), length(znames)) dimnames(z) <- list(nvec, znames) @@ -47,26 +43,31 @@ boundsPostprob <- function(nvec, p0, p1 = p0, tL, tU, a, b) { xL <- NA xU <- NA for (x in 0:n) { - postp <- postprob(x, n, p1, parE = c(a, b)) - if (postp <= tL) { + postp <- 1 - postprob(x, n, p0, parE = c(a, b)) # futility look + if (postp >= tL) { + postL <- postp xL <- x } - if (p0 != p1) { - postp <- postprob(x, n, p0, parE = c(a, b)) - } + postp <- postprob(x, n, p0, parE = c(a, b)) # efficacy look if (postp >= tU) { + postU <- postp xU <- x - # done: leave innermost for loop break } } - # calculate posterior probabilities at boundaries - postL <- postprob(xL, n, p1, parE = c(a, b)) - postU <- postprob(xU, n, p0, parE = c(a, b)) # calculate lower CI at boundaries - UciL <- ifelse(!is.na(xL), stats::binom.test(xL, n, alt = "less")$conf.int[2], NA) - LciU <- ifelse(!is.na(xU), stats::binom.test(xU, n, alt = "greater")$conf.int[1], NA) - z[k, ] <- c(xL, xL / n, postL, UciL, xU, xU / n, postU, LciU) + pL_upper_ci <- ifelse(!is.na(xL), stats::binom.test(xL, n, alt = "less")$conf.int[2], NA) + pU_lower_ci <- ifelse(!is.na(xU), stats::binom.test(xU, n, alt = "greater")$conf.int[1], NA) + z[k, ] <- c( + xL, + xL / n, + postL, + pL_upper_ci, + xU, + xU / n, + postU, + pU_lower_ci + ) } return(round(data.frame(nvec, z), 4)) } diff --git a/examples/boundsPostprob.R b/examples/boundsPostprob.R index 97491a9f..f4377968 100644 --- a/examples/boundsPostprob.R +++ b/examples/boundsPostprob.R @@ -1,10 +1,8 @@ -## 40 pts trial with interim looks after each 10 pts., -## efficacy decision if more than 90% probability to be above 20% ORR, -## futility decision if less than 10% probability to be above 20% ORR, -## with uniform prior (i.e. beta(1, 1)) on the ORR: +# 40 pts trial with interim looks after each 10 pts., +# Efficacy decision if more than 60% probability to be above 20% ORR, +# Futility decision if less than 60% probability to be below 20% ORR, +# with uniform prior (i.e. beta(1, 1)) on the ORR: boundsPostprob( - nvec = c(10, 20, 30, 40), p0 = 0.20, - tL = 0.10, tU = 0.90, a = 1, b = 1 + nvec = c(10, 20, 30, 40), p0 = 0.20, p1 = 0.2, + tL = 0.60, tU = 0.60, a = 1, b = 1 ) -## From this we see e.g. that at the third IA at 30 pts, we would stop for futility -## if 5 or less patients responded, and for efficacy if 9 or more pts responded. diff --git a/man/boundsPostprob.Rd b/man/boundsPostprob.Rd index 1cb2ae60..4394ef94 100644 --- a/man/boundsPostprob.Rd +++ b/man/boundsPostprob.Rd @@ -7,48 +7,45 @@ boundsPostprob(nvec, p0, p1 = p0, tL, tU, a, b) } \arguments{ -\item{nvec}{a vector of number of patients} +\item{nvec}{(\code{numeric}):\cr A vector of number of patients in each look.} -\item{p0}{the efficacy threshold parameter in the postprob function} +\item{p0}{(\code{number}):\cr lower Futility threshold of response rate.} -\item{p1}{the futility threshold parameter in the postprob function -(default = p0)} +\item{p1}{(\code{number}):\cr upper Efficacy threshold of response rate.} -\item{tL}{futility boundary probability threshold} +\item{tL}{(\code{number}):\cr posterior probability threshold for being below \code{p0}.} -\item{tU}{efficacy boundary probability threshold} - -\item{a}{the alpha parameter of the beta prior of treatment group} - -\item{b}{the beta parameter of the beta prior of treatment group} +\item{tU}{(\code{number}):\cr posterior probability threshold for being above \code{p1}.} } \value{ -A matrix where for each sample size in \code{nvec}, this function -returns the maximum number of responses that meet the futility -threshold (xL), its corresponding response rate (pL), posterior probability -(postL), upper bound of one sided 95\% CI for the response rate based on an -exact binomial test (UciL), and the same boundary parameters for efficacy: -the minimal number of responses that meet the efficacy threshold (xU), -the corresponding response rate (pU), posterior probability (postU) and -the lower bound of one sided 95\% CI for the response rate based on exact -binomial test (LciU). +A matrix for each same size in \code{nvec}. For each sample size, the following is returned: +\itemize{ +\item \code{xL} : the maximum number of responses that meet the futility. +threshold +\item \code{pL} : response rate corresponding to \code{xL}. +\item \code{postL}: posterior probability corresponding to \code{xL}. +\item \code{pL_upper_ci} : upper bound of one sided 95\% CI for the response rate \code{pL} based on an +exact binomial test. +\item \code{xU} : the minimal number of responses that meet the efficacy threshold. +\item \code{pU} : response rate corresponding to \code{xU}. +\item \code{postU} : posterior probability corresponding to \code{xU}. +\item \code{pU_lower_ci} : lower bound of one sided 95\% CI for the response rate \code{pU} based on exact +binomial test. +} } \description{ This function is used to identify the efficacy and futility -boundaries based on posterior probabilities, i.e.: -Efficacy boundary: find minimum x (xU) where Pr(P>p0|x,n,a,b) >= tU and -Futility boundary: find maximum x (xL) where Pr(P>p1|x,n,a,b) <= tL +boundaries based on the following rules: +Efficacy boundary: find minimum x (xU) where Pr(P > p1 |x, n, a, b) >= tU and +Futility boundary: find maximum x (xL) where Pr(P < p0 | x, n, a, b) >= tL } \examples{ -## 40 pts trial with interim looks after each 10 pts., -## efficacy decision if more than 90\% probability to be above 20\% ORR, -## futility decision if less than 10\% probability to be above 20\% ORR, -## with uniform prior (i.e. beta(1, 1)) on the ORR: +# 40 pts trial with interim looks after each 10 pts., +# Efficacy decision if more than 60\% probability to be above 20\% ORR, +# Futility decision if less than 60\% probability to be below 20\% ORR, +# with uniform prior (i.e. beta(1, 1)) on the ORR: boundsPostprob( - nvec = c(10, 20, 30, 40), p0 = 0.20, - tL = 0.10, tU = 0.90, a = 1, b = 1 + nvec = c(10, 20, 30, 40), p0 = 0.20, p1 = 0.2, + tL = 0.60, tU = 0.60, a = 1, b = 1 ) -## From this we see e.g. that at the third IA at 30 pts, we would stop for futility -## if 5 or less patients responded, and for efficacy if 9 or more pts responded. } -\keyword{graphics} diff --git a/tests/testthat/test-boundsPostProb.R b/tests/testthat/test-boundsPostProb.R new file mode 100644 index 00000000..3d74d3bc --- /dev/null +++ b/tests/testthat/test-boundsPostProb.R @@ -0,0 +1,33 @@ +# boundsPostProb ---- +test_that("boundsPostProb gives correct result and list", { + result <- boundsPostprob( + nvec = c(10, 20, 30, 40), + p0 = 0.2, + p1 = 0.2, + tL = 0.60, + tU = 0.60, + a = 1, + b = 1 + ) + expected <- data.frame( + list( + nvec = c(10, 20, 30, 40), + xL = c(1, 3, 5, 6), + pL = c(0.1, 0.15, 0.1667, 0.15), + postL = c(0.6779, 0.6296, 0.6069, 0.739), + pL_upper_ci = c(0.3942, 0.3437, 0.319, 0.2747), + xU = c(2, 5, 7, 9), + pU = c(0.2, 0.25, 0.2333, 0.225), + postU = c(0.6174, 0.7693, 0.73, 0.704), + pU_lower_ci = c(0.0368, 0.1041, 0.115, 0.1227) + ) + ) + expect_equal(result$xL, c(1, 3, 5, 6)) + expect_equal(result$pL, c(0.1, 0.15, 0.1667, 0.15)) + expect_equal(result$postL, c(0.6779, 0.6296, 0.6069, 0.739)) + expect_equal(result$pL_upper_ci, c(0.3942, 0.3437, 0.319, 0.2747)) + expect_equal(result$xU, c(2, 5, 7, 9)) + expect_equal(result$pU, c(0.2, 0.25, 0.2333, 0.225)) + expect_equal(result$postU, c(0.6174, 0.7693, 0.73, 0.704)) + expect_equal(result$pU_lower_ci, c(0.0368, 0.1041, 0.115, 0.1227)) +})