Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 14 additions & 82 deletions R/gs_design_npe.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,82 +16,14 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

#' Group sequential design computation with non-constant effect and information
#'
#' Derives group sequential design size,
#' bounds and boundary crossing probabilities based on proportionate
#' information and effect size at analyses.
#' It allows a non-constant treatment effect over time,
#' but also can be applied for the usual homogeneous effect size designs.
#' It requires treatment effect and proportionate statistical information
#' at each analysis as well as a method of deriving bounds, such as spending.
#' The routine enables two things not available in the gsDesign package:
#' 1) non-constant effect, 2) more flexibility in boundary selection.
#' For many applications, the non-proportional-hazards design function
#' `gs_design_nph()` will be used; it calls this function.
#' Initial bound types supported are 1) spending bounds,
#' 2) fixed bounds, and 3) Haybittle-Peto-like bounds.
#' The requirement is to have a boundary update method that
#' can each bound without knowledge of future bounds.
#' As an example, bounds based on conditional power that
#' require knowledge of all future bounds are not supported by this routine;
#' a more limited conditional power method will be demonstrated.
#' Boundary family designs Wang-Tsiatis designs including
#' the original (non-spending-function-based) O'Brien-Fleming and Pocock designs
#' are not supported by [gs_power_npe()].
#'
#' @param theta Natural parameter for group sequential design
#' representing expected incremental drift at all analyses;
#' used for power calculation.
#' @param theta0 Natural parameter used for upper bound spending;
#' if `NULL`, this will be set to 0.
#' @param theta1 Natural parameter used for lower bound spending;
#' if `NULL`, this will be set to `theta`
#' which yields the usual beta-spending.
#' If set to 0, spending is 2-sided under null hypothesis.
#' @param info Proportionate statistical information at
#' all analyses for input `theta`.
#' @param info0 Proportionate statistical information
#' under null hypothesis, if different than alternative;
#' impacts null hypothesis bound calculation.
#' @param info1 Proportionate statistical information
#' under alternate hypothesis;
#' impacts null hypothesis bound calculation.
#' @param info_scale Information scale for calculation. Options are:
#' - `"h0_h1_info"` (default): variance under both null and alternative hypotheses is used.
#' - `"h0_info"`: variance under null hypothesis is used.
#' - `"h1_info"`: variance under alternative hypothesis is used.


#' @rdname gs_power_design_npe
#' @param alpha One-sided Type I error.
#' @param beta Type II error.
#' @param binding Indicator of whether futility bound is binding;
#' default of `FALSE` is recommended.
#' @param upper Function to compute upper bound.
#' @param lower Function to compare lower bound.
#' @param upar Parameters passed to the function provided in `upper`.
#' @param lpar Parameters passed to the function provided in `lower`.
#' @param test_upper Indicator of which analyses should include
#' an upper (efficacy) bound; single value of `TRUE` (default) indicates
#' all analyses; otherwise, a logical vector of the same length as `info`
#' should indicate which analyses will have an efficacy bound.
#' @param test_lower Indicator of which analyses should include an lower bound;
#' single value of `TRUE` (default) indicates all analyses;
#' single value `FALSE` indicates no lower bound; otherwise,
#' a logical vector of the same length as `info` should indicate which
#' analyses will have a lower bound.
#' @param r Integer value controlling grid for numerical integration
#' as in Jennison and Turnbull (2000); default is 18, range is 1 to 80.
#' Larger values provide larger number of grid points and greater accuracy.
#' Normally `r` will not be changed by the user.
#' @param tol Tolerance parameter for boundary convergence (on Z-scale).
#'
#' @return A tibble with columns analysis, bound, z, probability, theta, info, info0.
#'

#' @details
#' The inputs `info` and `info0` should be
#' vectors of the same length with increasing positive numbers.
#' The design returned will change these by some constant scale
#' factor to ensure the design has power `1 - beta`.
#' The bound specifications in `upper`, `lower`, `upar`, `lpar`
#' The bound specifications (`upper`, `lower`, `upar`, `lpar`) of \code{gs_design_npe()}
#' will be used to ensure Type I error and other boundary properties are as specified.
#'
#' @section Specification:
Expand Down Expand Up @@ -131,7 +63,7 @@
#' library(gsDesign)
#'
#' # Example 1 ----
#' # Single analysis
#' # gs_design_npe with single analysis
#' # Lachin book p 71 difference of proportions example
#' pc <- .28 # Control response rate
#' pe <- .40 # Experimental response rate
Expand All @@ -147,7 +79,7 @@
#'
#'
#' # Example 2 ----
#' # Fixed bound
#' # gs_design_npe with with fixed bound
#' x <- gs_design_npe(
#' alpha = 0.0125,
#' theta = c(.1, .2, .3),
Expand All @@ -163,15 +95,15 @@
#' # Same upper bound; this represents non-binding Type I error and will total 0.025
#' gs_power_npe(
#' theta = rep(0, 3),
#' info = (x %>% filter(bound == "upper"))$info,
#' info = (x |> dplyr::filter(bound == "upper"))$info,
#' upper = gs_b,
#' upar = (x %>% filter(bound == "upper"))$z,
#' upar = (x |> dplyr::filter(bound == "upper"))$z,
#' lower = gs_b,
#' lpar = rep(-Inf, 3)
#' )
#'
#' # Example 3 ----
#' # Spending bound examples
#' # gs_design_npe with spending bound
#' # Design with futility only at analysis 1; efficacy only at analyses 2, 3
#' # Spending bound for efficacy; fixed bound for futility
#' # NOTE: test_upper and test_lower DO NOT WORK with gs_b; must explicitly make bounds infinite
Expand Down Expand Up @@ -201,7 +133,7 @@
#' )
#'
#' # Example 4 ----
#' # Spending function bounds
#' # gs_design_npe with spending function bounds
#' # 2-sided asymmetric bounds
#' # Lower spending based on non-zero effect
#' gs_design_npe(
Expand All @@ -215,7 +147,7 @@
#' )
#'
#' # Example 5 ----
#' # Two-sided symmetric spend, O'Brien-Fleming spending
#' # gs_design_npe with two-sided symmetric spend, O'Brien-Fleming spending
#' # Typically, 2-sided bounds are binding
#' xx <- gs_design_npe(
#' theta = c(.1, .2, .3),
Expand All @@ -236,8 +168,8 @@
#' binding = TRUE,
#' upper = gs_b,
#' lower = gs_b,
#' upar = (xx %>% filter(bound == "upper"))$z,
#' lpar = -(xx %>% filter(bound == "upper"))$z
#' upar = (xx |> dplyr::filter(bound == "upper"))$z,
#' lpar = -(xx |> dplyr::filter(bound == "upper"))$z
#' )
gs_design_npe <- function(
theta = .1, theta0 = 0, theta1 = theta, # 3 theta
Expand Down
80 changes: 52 additions & 28 deletions R/gs_power_npe.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,26 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

#' Group sequential bound computation with non-constant effect
#' @title Group sequential design computation with non-constant effect and information.
#'
#' Derives group sequential bounds and boundary crossing probabilities for a design.
#' It allows a non-constant treatment effect over time,
#' @description The following 2 functions allows a non-constant treatment effect over time,
#' but also can be applied for the usual homogeneous effect size designs.
#' It requires treatment effect and statistical information at each analysis
#' They requires treatment effect and statistical information at each analysis
#' as well as a method of deriving bounds, such as spending.
#' The routine enables two things not available in the gsDesign package:
#' 1) non-constant effect, 2) more flexibility in boundary selection.
#' For many applications, the non-proportional-hazards design function
#' `gs_design_nph()` will be used; it calls this function.
#' Initial bound types supported are 1) spending bounds,
#' 2) fixed bounds, and 3) Haybittle-Peto-like bounds.
#' The requirement is to have a boundary update method that can
#' Initial bound types supported are 1) spending bounds, 2) fixed bounds, and 3) Haybittle-Peto-like bounds.
#' The above routine enables two things not available in the gsDesign package: 1)
#' non-constant effect, 2) more flexibility in boundary selection.
#'
#' \code{gs_power_npe()} derives group sequential bounds and boundary crossing probabilities
#' for a design, given treatment effect and information at each analysis, as well as the
#' method of deriving bounds, such as spending.
#'
#' \code{gs_design_npe()} derives group sequential design size,
#' bounds and boundary crossing probabilities based on proportionate
#' information and effect size at analyses, as well as the
#' method of deriving bounds, such as spending.
#'
#' The requirement is to have a boundary update method that can compute
#' each bound without knowledge of future bounds.
#' As an example, bounds based on conditional power that require
#' knowledge of all future bounds are not supported by this routine;
Expand All @@ -42,8 +48,11 @@
#' expected incremental drift at all analyses; used for power calculation.
#' @param theta0 Natural parameter for null hypothesis,
#' if needed for upper bound computation.
#' Default is 0.
#' @param theta1 Natural parameter for alternate hypothesis,
#' if needed for lower bound computation.
#' The default is the same as `theta`, which yields the usual beta-spending.
#' If set to 0, spending is 2-sided under the null hypothesis.
#' @param info Statistical information at all analyses for input `theta`.
#' @param info0 Statistical information under null hypothesis,
#' if different than `info`;
Expand Down Expand Up @@ -77,10 +86,20 @@
#' Normally, `r` will not be changed by the user.
#' @param tol Tolerance parameter for boundary convergence (on Z-scale).
#'
#' @return A tibble with columns as analysis index, bounds, z,
#' crossing probability, theta (standardized treatment effect),
#' theta1 (standardized treatment effect under alternative hypothesis),
#' information fraction, and statistical information.
#' @return A tibble with columns of
#' - `analysis`: analysis index.
#' - `bound`: either of value `"upper"` or `"lower"`, indicating the upper and lower bound.
#' - `z`: the Z-score bounds.
#' - `probability`: cumulative probability of crossing the bound at or before the analysis.
#' - `theta`: same as the input.
#' - `theta1`: same as the input.
#' - `info`: statistical information at each analysis.
#' + If it is returned by `gs_power_ahr`, the `info`, `info0`, `info1` is same as the input.
#' + If it is returned by `gs_power_ahr`, the `info`, `info0`, `info1` is change by some constant scale
#' factor to ensure the design has power `1 - beta`.
#' - `info0`: statistical information under the null at each analysis.
#' - `info1`: statistical information under the alternative at each analysis.
#' - `info_frac`: information fraction at each analysis, i.e., `info / max(info)`.
#'
#' @section Specification:
#' \if{latex}{
Expand Down Expand Up @@ -117,17 +136,18 @@
#' }
#' \if{html}{The contents of this section are shown in PDF user manual only.}
#'
#' @name gs_power_design_npe
#' @rdname gs_power_design_npe
#' @export
#'
#' @examples
#' library(gsDesign)
#' library(gsDesign2)
#' library(dplyr)
#'
#' # Default (single analysis; Type I error controlled)
#' gs_power_npe(theta = 0) %>% filter(bound == "upper")
#' # Example 6 ----
#' # Default of gs_power_npe (single analysis; Type I error controlled)
#' gs_power_npe(theta = 0) |> dplyr::filter(bound == "upper")
#'
#' # Fixed bound
#' # Example 7 ----
#' # gs_power_npe with fixed bound
#' gs_power_npe(
#' theta = c(.1, .2, .3),
#' info = (1:3) * 40,
Expand All @@ -143,10 +163,11 @@
#' info = (1:3) * 40,
#' upar = gsDesign::gsDesign(k = 3, sfu = gsDesign::sfLDOF)$upper$bound,
#' lpar = rep(-Inf, 3)
#' ) %>%
#' filter(bound == "upper")
#' ) |>
#' dplyr::filter(bound == "upper")
#'
#' # Fixed bound with futility only at analysis 1; efficacy only at analyses 2, 3
#' # Example 8 ----
#' # gs_power_npe with fixed bound testing futility only at analysis 1; efficacy only at analyses 2, 3
#' gs_power_npe(
#' theta = c(.1, .2, .3),
#' info = (1:3) * 40,
Expand All @@ -156,7 +177,8 @@
#' lpar = c(qnorm(.1), -Inf, -Inf)
#' )
#'
#' # Spending function bounds
#' # Example 8 ----
#' # gs_power_npe with spending function bounds
#' # Lower spending based on non-zero effect
#' gs_power_npe(
#' theta = c(.1, .2, .3),
Expand All @@ -177,7 +199,8 @@
#' lpar = list(sf = gsDesign::sfHSD, total_spend = 0.1, param = -1, timing = NULL)
#' )
#'
#' # Two-sided symmetric spend, O'Brien-Fleming spending
#' # Example 9 ----
#' # gs_power_npe with two-sided symmetric spend, O'Brien-Fleming spending
#' # Typically, 2-sided bounds are binding
#' x <- gs_power_npe(
#' theta = rep(0, 3),
Expand All @@ -195,10 +218,11 @@
#' theta = c(.1, .2, .3),
#' info = (1:3) * 40,
#' binding = TRUE,
#' upar = (x %>% filter(bound == "upper"))$z,
#' lpar = -(x %>% filter(bound == "upper"))$z
#' upar = (x |> dplyr::filter(bound == "upper"))$z,
#' lpar = -(x |> dplyr::filter(bound == "upper"))$z
#' )
#'
#' # Example 10 ----
#' # Different values of `r` and `tol` lead to different numerical accuracy
#' # Larger `r` and smaller `tol` give better accuracy, but leads to slow computation
#' n_analysis <- 5
Expand Down
Loading
Loading