Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable passing named vector of col_decimals to summary.gs_design() #431

Merged
merged 5 commits into from
Jun 28, 2024
Merged
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
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: gsDesign2
Title: Group Sequential Design with Non-Constant Effect
Version: 1.1.2.13
Version: 1.1.2.14
Authors@R: c(
person("Keaven", "Anderson", email = "keaven_anderson@merck.com", role = c("aut")),
person("Yilong", "Zhang", email = "elong0527@gmail.com", role = c("aut")),
Expand Down
122 changes: 78 additions & 44 deletions R/summary.R
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ summary.fixed_design <- function(object, ...) {
#' variables you want to be displayed differently than the defaults.
#' @param col_vars The variables to be displayed.
#' @param col_decimals The decimals to be displayed for the displayed variables in `col_vars`.
#' If the vector is unnamed, it must match the length of `col_vars`. If the
#' vector is named, you only have to specify the number of digits for the
#' columns you want to be displayed differently than the defaults.
LittleBeannie marked this conversation as resolved.
Show resolved Hide resolved
#' @param bound_names Names for bounds; default is `c("Efficacy", "Futility")`.
#'
#' @importFrom dplyr all_of
Expand Down Expand Up @@ -240,6 +243,16 @@ summary.fixed_design <- function(object, ...) {
#'
#' # Customize the variables to be summarized for each analysis
#' x_ahr %>% summary(analysis_vars = c("n", "event"), analysis_decimals = c(1, 1))
#'
#' # Customize the digits for the columns
#' x_ahr %>% summary(col_decimals = c(z = 4))
#'
#' # Customize the columns to display
#' x_ahr %>% summary(col_vars = c("z", "~hr at bound", "nominal p"))
#'
#' # Customize columns and digits
#' x_ahr %>% summary(col_vars = c("z", "~hr at bound", "nominal p"),
#' col_decimals = c(4, 2, 2))
#' }
#'
#' # Example 2 ----
Expand Down Expand Up @@ -315,60 +328,81 @@ summary.gs_design <- function(object,

# Prepare the columns decimals ----
if (method == "ahr") {
if (is.null(col_vars) && is.null(col_decimals)) {
x_decimals <- tibble::tibble(
col_vars = c("analysis", "bound", "z", "~hr at bound", "nominal p", "Alternate hypothesis", "Null hypothesis"),
col_decimals = c(NA, NA, 2, 4, 4, 4, 4)
)
} else {
x_decimals <- tibble::tibble(col_vars = col_vars, col_decimals = col_decimals)
}
}

if (method == "wlr") {
if (is.null(col_vars) && is.null(col_decimals)) {
x_decimals <- tibble::tibble(
col_vars = c("analysis", "bound", "z", "~whr at bound", "nominal p", "Alternate hypothesis", "Null hypothesis"),
col_decimals = c(NA, NA, 2, 4, 4, 4, 4)
)
} else {
x_decimals <- tibble::tibble(col_vars = col_vars, col_decimals = col_decimals)
}
col_vars_default <- c(
"analysis", "bound", "z", "~hr at bound", "nominal p",
"Alternate hypothesis", "Null hypothesis"
)
col_decimals_default <- c(NA, NA, 2, 4, 4, 4, 4)
} else if (method == "wlr") {
col_vars_default <- c(
"analysis", "bound", "z", "~whr at bound", "nominal p",
"Alternate hypothesis", "Null hypothesis"
)
col_decimals_default <- c(NA, NA, 2, 4, 4, 4, 4)
} else if (method == "combo") {
col_vars_default <- c(
"analysis", "bound", "z", "nominal p",
"Alternate hypothesis", "Null hypothesis"
)
col_decimals_default <- c(NA, NA, 2, 4, 4, 4)
} else if (method == "rd") {
col_vars_default <- c(
"analysis", "bound", "z", "~risk difference at bound",
"nominal p", "Alternate hypothesis", "Null hypothesis"
)
col_decimals_default <- c(NA, NA, 2, 4, 4, 4, 4)
} else {
stop("Invalid method: ", method)
}

if (method == "combo") {
if (is.null(col_vars) && is.null(col_decimals)) {
x_decimals <- tibble::tibble(
col_vars = c("analysis", "bound", "z", "nominal p", "Alternate hypothesis", "Null hypothesis"),
col_decimals = c(NA, NA, 2, 4, 4, 4)
)
} else {
x_decimals <- tibble::tibble(col_vars = col_vars, col_decimals = col_decimals)
# Filter columns and update decimal places
names(col_decimals_default) <- col_vars_default
if (is.null(col_vars) && is.null(col_decimals)) {
# Use default values
col_vars <- col_vars_default
col_decimals <- col_decimals_default
} else if (!is.null(col_vars) && is.null(col_decimals)) {
# Only drop/rearrange variables
col_decimals <- col_decimals_default[
match(col_vars, names(col_decimals_default))
]
} else if (is.null(col_vars) && !is.null(col_decimals)) {
# Only update decimals - must be named vector
if (is.null(names(col_decimals))) {
stop("summary: col_decimals must be a named vector if col_vars is not provided")
}
}

if (method == "rd") {
if (is.null(col_vars) && is.null(col_decimals)) {
x_decimals <- tibble::tibble(
col_vars = c(
"analysis", "bound", "z", "~risk difference at bound",
"nominal p", "Alternate hypothesis", "Null hypothesis"
),
col_decimals = c(NA, NA, 2, 4, 4, 4, 4)
)
col_vars <- col_vars_default
col_decimals_tmp <- col_decimals_default
col_decimals_tmp[names(col_decimals)] <- col_decimals
col_decimals <- col_decimals_tmp
} else if (!is.null(col_vars) && !is.null(col_decimals)) {
# Update variables and decimals
if (is.null(names(col_decimals))) {
# vectors must be same length if col_decimals is unnamed
if (length(col_vars) != length(col_decimals)) {
stop("summary: please input col_vars and col_decimals in pairs!")
}
} else {
x_decimals <- tibble::tibble(col_vars = col_vars, col_decimals = col_decimals)
col_decimals_tmp <- col_decimals_default
col_decimals_tmp[names(col_decimals)] <- col_decimals
col_decimals <- col_decimals_tmp
col_decimals <- col_decimals[
match(col_vars, names(col_decimals))
]
}
}

# "bound" is a required column
if (!"bound" %in% x_decimals$col_vars) {
x_decimals <- rbind(
tibble::tibble(col_vars = "bound", col_decimals = NA),
x_decimals
)
if (!"bound" %in% col_vars) {
col_vars <- c("bound", col_vars)
col_decimals <- c(NA, col_decimals)
}

x_decimals <- tibble::tibble(
col_vars = col_vars,
col_decimals = col_decimals
)

# Prepare the analysis summary row ----
# get the
# (1) analysis variables to be displayed on the header
Expand Down
15 changes: 14 additions & 1 deletion man/summary.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

124 changes: 122 additions & 2 deletions tests/testthat/test-developer-summary.R
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ test_that("The column 'Bound' is always included in summary.gs_design() output",
expect_true("Bound" %in% colnames(observed))
})


test_that("The full alpha is correctly carried over", {
a_level <- 0.02
x <- gs_power_ahr(
Expand All @@ -166,4 +165,125 @@ test_that("The full alpha is correctly carried over", {
observed <- summary(x)

expect_equal(attributes(observed)$full_alpha, a_level)
})
})

# Maintain previous behavior
test_that("summary.gs_design() accepts same-length vectors for col_vars and col_decimals", {
x <- gs_design_ahr()

# default decimals
x_sum <- summary(x)
observed <- as.data.frame(x_sum)[, -1:-2]
expected <- data.frame(
Z = 1.96,
`~HR at bound` = 0.795,
`Nominal p` = 0.025,
`Alternate hypothesis` = 0.9,
`Null hypothesis` = 0.025,
check.names = FALSE
)
expect_equal(observed, expected)

# specify the decimals for each variable
x_sum <- summary(
x,
col_vars = c("z", "~hr at bound", "nominal p", "Alternate hypothesis", "Null hypothesis"),
col_decimals = c(0, 0, 0, 0, 0)
)
observed <- as.data.frame(x_sum)[, -1:-2]
expected <- data.frame(
Z = 2,
`~HR at bound` = 1,
`Nominal p` = 0,
`Alternate hypothesis` = 1,
`Null hypothesis` = 0,
check.names = FALSE
)
expect_equal(observed, expected)

# Drop variables and also specify the decimals
x_sum <- summary(
x,
col_vars = c("nominal p", "Null hypothesis"),
col_decimals = c(0, 0)
)
observed <- as.data.frame(x_sum)[, -1:-2]
expected <- data.frame(`Nominal p` = 0, `Null hypothesis` = 0, check.names = FALSE)
expect_equal(observed, expected)

# Rearrange variables
x_sum <- summary(
x,
col_vars = c("Null hypothesis", "Alternate hypothesis", "nominal p", "~hr at bound", "z"),
col_decimals = c(0, 0, 0, 0, 0)
)
observed <- as.data.frame(x_sum)[, -1:-2]
expected <- data.frame(
`Null hypothesis` = 0,
`Alternate hypothesis` = 1,
`Nominal p` = 0,
`~HR at bound` = 1,
Z = 2,
check.names = FALSE
)
expect_equal(observed, expected)

# Throw error if unnamed col_decimals does not match length of col_vars
expect_error(
summary(
x,
col_vars = c("Null hypothesis", "Alternate hypothesis", "nominal p"),
col_decimals = c(0, 0),
),
"summary: please input col_vars and col_decimals in pairs!"
)
})

test_that("summary.gs_design() accepts a named vector for col_decimals", {
x <- gs_design_ahr()

# Specify decimals
x_sum <- summary(x, col_decimals = c(z = 0, `nominal p` = 0))
observed <- as.data.frame(x_sum)[, -1:-2]
expected <- data.frame(
Z = 2,
`~HR at bound` = 0.795,
`Nominal p` = 0,
`Alternate hypothesis` = 0.9,
`Null hypothesis` = 0.025,
check.names = FALSE
)
expect_equal(observed, expected)

# Specify decimals and also drop some variables
x_sum <- summary(
x,
col_vars = c("z", "nominal p", "Null hypothesis"),
col_decimals = c(z = 0, `nominal p` = 0)
)
observed <- as.data.frame(x_sum)[, -1:-2]
expected <- data.frame(Z = 2, `Nominal p` = 0, `Null hypothesis` = 0.025, check.names = FALSE)
expect_equal(observed, expected)

# Specify decimals and rearrange some variables
x_sum <- summary(
x,
col_vars = c("Null hypothesis", "nominal p", "z"),
col_decimals = c(z = 0, `nominal p` = 0)
)
observed <- as.data.frame(x_sum)[, -1:-2]
expected <- data.frame(`Null hypothesis` = 0.025, `Nominal p` = 0, Z = 2, check.names = FALSE)
expect_equal(observed, expected)

# Only drop variables
x_sum <- summary(x, col_vars = c("z", "nominal p", "Null hypothesis"))
observed <- as.data.frame(x_sum)[, -1:-2]
expected <- data.frame(Z = 1.96, `Nominal p` = 0.025, `Null hypothesis` = 0.025, check.names = FALSE)
expect_equal(observed, expected)

# Throw error is col_decimals is unnamed
expect_error(
summary(x, col_decimals = c(4, 4)),
"summary: col_decimals must be a named vector if col_vars is not provided"
)
})
32 changes: 4 additions & 28 deletions vignettes/articles/story-update-boundary.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,7 @@ gs_update_ahr(
x = x,
alpha = 0.025
) |>
summary(
col_vars = c(
"analysis", "bound", "z", "~hr at bound",
"nominal p", "Alternate hypothesis", "Null hypothesis"
),
col_decimals = c(NA, NA, 4, 4, 4, 4, 4)
) |>
summary(col_decimals = c(z = 4)) |>
as_gt(title = "Updated design",
subtitle = "For alternate alpha = 0.025")
```
Expand Down Expand Up @@ -184,13 +178,7 @@ gs_update_ahr(
ustime = ustime,
observed_data = list(observed_data_ia, observed_data_fa)
) |>
summary(
col_vars = c(
"analysis", "bound", "z", "~hr at bound",
"nominal p", "Alternate hypothesis", "Null hypothesis"
),
col_decimals = c(NA, NA, 4, 4, 4, 4, 4)
) |>
summary(col_decimals = c(z = 4)) |>
as_gt(title = "Updated design",
subtitle = paste0("With observed ", sum(observed_data_ia$event),
" events at IA and ", sum(observed_data_fa$event),
Expand Down Expand Up @@ -267,13 +255,7 @@ gs_update_ahr(
x = x,
alpha = 0.025
) |>
summary(
col_vars = c(
"analysis", "bound", "z", "~hr at bound",
"nominal p", "Alternate hypothesis", "Null hypothesis"
),
col_decimals = c(NA, NA, 4, 4, 4, 4, 4)
) |>
summary(col_decimals = c(z = 4)) |>
as_gt(title = "Updated design",
subtitle = "For alpha = 0.025")
```
Expand All @@ -294,13 +276,7 @@ gs_update_ahr(
lstime = ustime,
observed_data = list(observed_data_ia, observed_data_fa)
) |>
summary(
col_vars = c(
"analysis", "bound", "z", "~hr at bound",
"nominal p", "Alternate hypothesis", "Null hypothesis"
),
col_decimals = c(NA, NA, 4, 4, 4, 4, 4)
) |>
summary(col_decimals = c(z = 4)) |>
as_gt(title = "Updated design",
subtitle = paste0("With observed ", sum(observed_data_ia$event),
" events at IA and ", sum(observed_data_fa$event),
Expand Down
Loading