R/phase2.R

Defines functions twocon pickwin rp21 onearm binci

Documented in binci onearm pickwin rp21 twocon

#' Exact Binomial Confidence Limits
#'
#' Calculates exact confidence bounds on a single binomial probability
#'
#' @details
#' Calculates exact \code{1-(1-conf)/2} upper and lower confidence limits for a
#' binomial proportion.  The precision of the solution is the default in
#' \code{uniroot}.
#'
#' @param r number of successes
#' @param n total number of trials
#' @param conf confidence level
#'
#' @return
#' Returns a vector containing the two confidence limits. Returns 0 for
#' the lower limit if r=0, and returns 1 for the upper limit if r=n.
#'
#' @seealso
#' \code{\link{twocon}}
#'
#' @keywords htest
#'
#' @examples
#' binci(54, 88)
#'
#' @export binci

binci <- function(r, n, conf = 0.95) {
  if (r < 0 | r > n)
    stop('invalid value for r')
  if (conf <= 0 | conf >= 1)
    stop('must have 0 < conf <1')
  alpha <- (1 - conf) / 2
  ff <- function(p, r, n, alpha) 1 - pbinom(r - 1, n, p) - alpha
  pl <- if (r <= 0)
    0 else uniroot(ff, c(1e-8, 1 - 1e-8), r = r, n = n, alpha = alpha)$root
  ff2 <- function(p, r, n, alpha) pbinom(r, n, p) - alpha
  pu <- if (r >= n)
    1 else uniroot(ff2, c(1e-8, 1 - 1e-8), r = r, n = n, alpha = alpha)$root
  c(pl, pu)
}

#' One Sample Binomial Design
#'
#' Determines the critical value and power for an exact one sample binomial
#' test
#'
#' @details
#' Let \code{R} be the number of responses.  If \code{p0<pa}, determines the
#' smallest critical value \code{r} such that \code{P(R>=r|p0)<=alpha}, and
#' computes \code{P(R>=r|p)} for \code{p=p0,pa}.  If \code{p0>pa}, similar
#' calculations are done for rejecting in the opposite tail.
#'
#' @param n sample size
#' @param p0 The null response probability
#' @param pa The alternative response probability
#' @param alpha The one-sided type I error rate
#' @return A vector giving the critical value and the rejection probabilities
#' under the null and alternative.
#'
#' @seealso
#' \code{\link{bin1samp}}
#'
#' @keywords design
#'
#' @examples
#' onearm(30, 0.1, 0.3)
#'
#' @export onearm

onearm <- function(n, p0, pa, alpha = 0.1) {
  # single arm single stage evaluation
  u <- pbinom(0:n, n, p0) # P(<=)
  if (p0 > pa) {
    index <- max((1:(n + 1))[u <= alpha])
    c('rej if <=' = index - 1, size = u[index],
      power = pbinom(index - 1, n, pa))
  } else {
    u <- c(1, 1 - u[-n - 1]) # P(>=)
    index <- min((1:(n + 1))[u <= alpha])
    c('rej if >=' = index - 1, size = u[index],
      power = 1 - pbinom(index - 2, n, pa))
  }
}

#' Outcome Probabilities for Randomized Phase II Designs
#'
#' For a single stage randomized phase II study, computes the probability that
#' the difference in the number of responses is larger than a specified
#' critical value.
#'
#' @details
#' Computations assume two independent binomials R1 and R2, with R1 distributed
#' Binomal(n,p1) and R2 distributed Binomial(n,p2)
#'
#' @param n Planned number of subjects per arm
#' @param p1 Success probability for treatment 1
#' @param p2 Success probability for treatment 2
#' @param crit Maximum difference in number of responses that would be viewed
#' as an equivalent outcome
#'
#' @return
#' A vector giving P(R1>R2+crit), P(|R1-R2|<=crit) and P(R1<R2-crit).
#'
#' @seealso
#' \code{\link{pickwin}}
#'
#' @keywords design
#'
#' @examples
#' rp21(32, 0.2, 0.1)
#'
#' @export rp21

rp21 <- function(n, p1, p2, crit = 0) {
  # computes joint probs for two indep binom(n, p1), n(p2)
	probs <- outer(dbinom(0:n, n, p1), dbinom(0:n, n, p2))
	rw <- row(probs)
	cl <- col(probs)
	c('P(R1>R2+crit)' = sum(probs[rw > cl + crit]),
    'P(|R1-R2|<=crit)' = sum(probs[abs(rw - cl) <= crit]),
		'P(R1<R2-crit)' = sum(probs[rw < cl - crit]))
}

#' Two-Stage Randomized Phase II Designs
#'
#' Calculates operating characteristics of pick the winner rules for two stage
#' randomized phase II designs
#'
#' @details
#' Assumes that during the first stage of accrual \code{n1} patients are
#' randomized to each treatment (RX1 and RX2).  If more than \code{r1}
#' (\code{r3}) responses are seen on treatment RX1 (RX2), then an additional
#' \code{n2} patients will be accrued to treatment RX1 (RX2).  If more than
#' \code{r2} (\code{r4}) total responses are seen on RX1 (RX2), then RX1 (RX2)
#' will be declared active.
#'
#' Let X1 and X2 be the number of responses observed on treatments 1 and 2.
#' This function computes and prints P(X1<=r2)=P(RX1 declared inactive),
#' P(X2<=r4)=P(RX2 declared inactive), P(X2>r4 and X2>X1)=P(RX2 declared
#' superior), P(X1>r2 and X1>X2)=P(RX1 declared superior), and P(X1=X2 or
#' (X1<=r2 and X2<=r4))=P(neither declared superior).  Note that P(neither
#' declared superior) includes both the probability that both are declared
#' inactive and the probability that both are declared active and are equal.
#'
#' @param n1 first stage sample size (assumed to be the same for both
#' treatments)
#' @param n2 addition accrual during the second stage (assumed to be the same
#' for both treatments)
#' @param p1 True response probability on treatment 1
#' @param p2 True response probability on treatment 2
#' @param r1 The maximum number of responses to declare treatment 1 inactive in
#' the first stage
#' @param r2 The maximum number of total responses over both stages to declare
#' treatment 1 inactive
#' @param r3 The maximum number of responses to declare treatment 2 inactive in
#' the first stage
#' @param r4 The maximum number of total responses over both stages to declare
#' treatment 2 inactive
#'
#' @return
#' Returns a vector of length 9, whose components are (in order)
#' P(X1<=r1, X2>r4), P(r1<X1<=r2, X2>r4), P(X1>r2, X2>X1, X2>r4), P(X2<=r3,
#' X1>r2), P(r3<X2<=r4, X1>r2), P(X1>r2, X2>r4, X1>X2), P(X1<=r2, X2<=r4),
#' P(X1>r2, X2>r4, X1=X2), and the sum of the first 8 terms.
#'
#' @seealso
#' \code{\link{b2p}}
#'
#' @references
#' Simon R, Wittes RE and Ellenberg SS, 1985. Randomized phase II
#' clinical trials. \emph{Cancer Treat Rep} \strong{69} (12):1375--81.
#'
#' @keywords design
#'
#' @examples
#' pickwin(14, 18, 0.1, 0.2, 0, 3)
#'
#' @export pickwin

pickwin <- function(n1, n2, p1, p2, r1, r2, r3 = r1, r4 = r2) {
  # prob calculations for 2-stage pick the winner design
  # n1=# entered at first stage, n2=additional # entered at second stage
  # p1,p2 response probabilities on treatments 1 and 2
  # r1=max number responses stage 1 trt 1 and still stop
  # r2=max total number responses on trt 1 to be inactive
  # r3,r4 = corresponding values of r1,r2 for trt 2
  # prob( both are active and get the same # responses) included in p(neither
  #    better)
  if (n1 < 1 | n2 < 0 | r1 < 0 | r3 < 0 | r2 < 0 | r4 < 0 | p1 <= 0 | p2 <= 0 |
      r1 > n1 | r3 > n1 | r2 > n2 + n1 | r4 > n2 + n1 | p1 >= 1 | p2 >=1)
    stop('invalid arguments')
  x1 <- 0:n1
  x2 <- 0:n2
  w1 <- dbinom(x1, n1, p1)
  w2 <- dbinom(x1, n1, p2)
  w3 <- dbinom(x2, n2, p1)
  w4 <- dbinom(x2, n2, p2)
  # b1 = marginal dist of # responses in group 1
  u1 <- c(outer(x1[-(1:(r1 + 1))], x2, '+'))
  u2 <- c(outer(w1[-(1:(r1 + 1))], w3))
  b1 <- c(w1[1:(r1 + 1)], tapply(u2, u1, sum))
  # b2 = marginal dist of # responses in group 2
  u1 <- c(outer(x1[-(1:(r3 + 1))], x2, '+'))
  u2 <- c(outer(w2[-(1:(r3 + 1))], w4))
  b2 <- c(w2[1:(r3 + 1)], tapply(u2, u1, sum))
  # print(c(sum(b1), sum(b2)))

  cat('RX1 is declared inactive if <=', format(r1), 'responses are observed',
      ' in\nthe first', format(n1), 'cases or <=', format(r2), 'responses are',
      'observed in the first', format(n1 + n2), 'cases\n')
  cat('P(RX1 declared inactive) =', format(signif(sum(b1[1:(r2 + 1)]), 3)), '\n\n')
  cat('RX2 is declared inactive if <=', format(r3), 'responses are observed',
      ' in\nthe first', format(n1), 'cases or <=', format(r4), 'responses are',
      'observed in the first', format(n1 + n2), 'cases\n')
  cat('P(RX2 declared inactive) =', format(signif(sum(b2[1:(r4 + 1)]), 3)), '\n\n')
  a1 <- sum(b1[1:(r1 + 1)]) * sum(b2[(r4 + 2):length(b2)])
  a2 <- if (r2 > r1)
    sum(b1[(r1 + 2):(r2 + 1)]) * sum(b2[(r4 + 2):length(b2)]) else 0
  a3 <- 0
  for (i in (r2 + 2):(length(b1) - 1))
    a3 <- a3 + b1[i] * sum(b2[(max(i + 1, r4 + 2)):length(b2)])
  cat('prob RX2 declared better:', format(signif(a1 + a2 + a3, 3)), '\n')
  a4 <- sum(b2[1:(r3 + 1)]) * sum(b1[(r2 + 2):length(b1)])
  a5 <- if (r4 > r3)
    sum(b2[(r3 + 2):(r4 + 1)]) * sum(b1[(r2 + 2):length(b1)]) else 0
  a6 <- 0
  for (i in (r4 + 2):(length(b2) - 1))
    a6 <- a6 + b2[i] * sum(b1[(max(i + 1, r2 + 2)):length(b1)])
  cat('prob RX1 declared better:', format(signif(a4 + a5 + a6, 3)), '\n')
  a7 <- sum(b1[1:(r2 + 1)]) * sum(b2[1:(r4 + 1)])
  i <- (max(r2 + 2, r4 + 2)):length(b1)
  a8 <- sum(b1[i] * b2[i])
  cat('prob neither declared better:', format(signif(a7 + a8, 3)), '\n')
  c(a1, a2, a3, a4, a5, a6, a7, a8, a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8)
}

#' Confidence Interval on the Response Rate from a Two Stage Study
#'
#' Computes a confidence interval and several estimators of the response rate
#' using data from a phase II study with two-stage sampling
#'
#' @details
#' First \code{n1} patients are entered on the study.  If more than \code{r1}
#' responses are observed, then an additional \code{n2} patients are entered.
#' This function assumes that if the observed number of response \code{r < r1},
#' then only \code{n1} patients were entered.
#'
#' The estimators computed are the MLE (the observed proportion of responses),
#' a bias corrected MLE, and an unbiased estimator, which is sometimes
#' incorrectly described as the UMVUE.
#'
#' The confidence interval is based on the exact sampling distribution.
#' However, there is not a universally accepted ordering on the sample space in
#' two-stage designs.  The parameter \code{dp} can be used to modify the
#' ordering by weighting points within the sample space differently.
#' \code{dp=0} will give the Atkinson and Brown procedure, and \code{dp=1} will
#' order outcomes base on the MLE.  The Atkinson and Brown procedure orders
#' outcomes based solely on the number of responses, regardless of the number
#' cases sampled.  The MLE ordering defines as more extreme those outcomes with
#' a more extreme value of the MLE (the proportion of responses).  Other powers
#' of \code{dp}, such as \code{dp=1/2}, could also be used.  Let \code{R} be
#' the number of responses and \code{N=n1} if \code{R<=r1} and \code{N=n1+n2}
#' if \code{R>r1}.  In general, the outcomes that are more extreme in the high
#' response direction are those with \code{R/(N^dp) >= r/(n^dp)}, where
#' \code{r} and \code{n} are the observed values of \code{R} and \code{N}, and
#' the outcomes that are more extreme in the low response direction are those
#' with \code{R/(N^dp) <= r/(n^dp)}.
#'
#' @param n1 Number of cases entered during the first stage
#' @param n2 Number of additional cases to be entered during the second stage
#' @param r1 max number of responses that can be observed in the first stage
#' without continuing
#' @param r total number responses observed
#' @param conf two-sided confidence level (proportion) for the confidence
#' interval
#' @param dp Affects the ordering of outcomes within the sample space (see
#' below)
#'
#' @return
#' A vector with the lower confidence limit, the upper confidence
#' limit, the bias corrected MLE, the MLE, and the unbiased estimator.
#'
#' @seealso
#' \code{\link{binci}}
#'
#' @references
#' Atkinson and Brown (1985), BIOMETRICS 741-744.
#'
#' @keywords htest
#'
#' @examples
#' twocon(14, 18, 3, 4, dp = 0)
#' twocon(14, 18, 3, 4, dp = 1)
#'
#' @export twocon

twocon <- function(n1, n2, r1, r, conf = 0.95, dp = 1) {
  # confidence interval for two-stage phase II
  # n1 = # entered at first stage, n2=additional # entered at second stage
  # r1 = max number responses stage 1 trt 1 and still stop
  # r = total number responses observed
  if (n1 < 1 | n2 < 1 | r1 < 0 | r1 > n1 | r < 0 |
      r > n2 + n1 | conf <= 0 | conf >= 1)
    stop('invalid arguments')
  alpha <- (1 - conf) / 2
  x1 <- 0:n1
  x2 <- 0:n2
  u1 <- c(outer(x1[-(1:(r1 + 1))], x2, '+'))
  dbin2 <- function(p1, x1, x2, u1, n1, n2, r1) {
    w1 <- dbinom(x1, n1, p1)
    w3 <- dbinom(x2, n2, p1)
    u2 <- c(outer(w1[-(1:(r1 + 1))], w3))
    # ith component is P(R=i-1)
    c(w1[1:(r1 + 1)], tapply(u2, u1, sum))
  }
  n <- n1 + n2
  mle <- if (r > r1) r/n else r / n1
  # bias corrected estimator
  mm <- c((0:r1) / n1, (r1 + 1):n / n)
  ff <- function(p, x1, x2, u1, n1, n2, r1, mm, dbin2, mle)
    sum(dbin2(p, x1, x2, u1, n1, n2, r1) * mm) - mle
  pm <- if (r <= 0)
    0 else if (r >= n)
      1 else uniroot(ff, c(1e-8, 1 - 1e-8), x1 = x1, x2 = x2, u1 = u1, n1 = n1,
                     n2 = n2, r1 = r1, mm = mm, dbin2 = dbin2, mle = mle)$root
  # unbiased estimator
  ube <- if (r1 >= r) {
    r/n1
  } else {
    aa <- dhyper((r1 + 1):r, n1, n2, r)
    sum(((r1 + 1):r) * aa) / (n1 * sum(aa))
  }
  mm <- if (r > r1)
    c((n / n1) ^ dp * (0:r1),( r1 + 1):n) else c(0:r1,(n1 / n) ^ dp * ((r1 + 1):n))
  s1 <- mm >= r # for P(R>=r)
  s2 <- mm <= r
  ff2 <- function(p, x1, x2, u1, n1, n2, r1, s, dbin2, alpha)
    sum(dbin2(p, x1, x2, u1, n1, n2, r1)[s]) - alpha
  pl <- if (r <= 0)
    0 else uniroot(ff2, c(1e-8, 1 - 1e-8), x1 = x1, x2 = x2, u1 = u1, n1 = n1,
                   n2 = n2, r1 = r1, s = s1, dbin2 = dbin2, alpha = alpha)$root
  pu <- if (r >= n)
    1 else uniroot(ff2, c(1e-8, 1 - 1e-8), x1 = x1, x2 = x2, u1 = u1, n1 = n1,
                   n2 = n2, r1 = r1, s = s2, dbin2 = dbin2, alpha = alpha)$root
  c(lower = pl, upper = pu, bcmle = pm, mle = mle, unbiased = ube)
}
raredd/desmon documentation built on May 7, 2024, 3:46 p.m.