Skip to content

Commit c59c39f

Browse files
committed
delete obs_data from gs_update_ahr
1 parent e00aeee commit c59c39f

File tree

2 files changed

+47
-273
lines changed

2 files changed

+47
-273
lines changed

R/gs_update_ahr.R

+47-210
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,18 @@
2525
#' with the spending time at each analysis.
2626
#' @param lstime Default is NULL in which case lower bound spending time is determined by timing.
2727
#' Otherwise, this should be a vector of length k (total number of analyses)
28-
#' with the spending time at each analysis
29-
#' @param observed_data a list of observed datasets by analyses.
30-
#' @param event_tbl A data frame with 2 columns: (1) analysis and (2) event (events observed at each analysis, per piecewise interval)
31-
#'
32-
#' @return A list with input parameters, enrollment rate, analysis, and bound.
28+
#' with the spending time at each analysis.
29+
#' @param event_tbl A data frame with two columns: (1) analysis and (2) event,
30+
#' which represents the events observed at each analysis per piecewise interval.
31+
#' This can be defined via the `pw_observed_event()` function or manually entered.
32+
#' For example, consider a scenario with two intervals in the piecewise model:
33+
#' the first interval lasts 6 months with a hazard ratio (HR) of 1,
34+
#' and the second interval follows with an HR of 0.6.
35+
#' The data frame `event_tbl = data.frame(analysis = c(1, 1, 2, 2), event = c(30, 100, 30, 200))`
36+
#' indicates that 30 events were observed during the delayed effect period,
37+
#' 130 events were observed at the IA, and 230 events were observed at the FA.
38+
#'
39+
#' @return A list with input parameters, enrollment rate, failure rate, analysis, and bound.
3340
#'
3441
#' @export
3542
#'
@@ -59,85 +66,7 @@
5966
#' ratio <- 1
6067
#'
6168
#' # ------------------------------------------------- #
62-
#' # Example A: one-sided design (efficacy only)
63-
#' # ------------------------------------------------- #
64-
#' # Original design
65-
#' upper <- gs_spending_bound
66-
#' upar <- list(sf = sfLDOF, total_spend = alpha)
67-
#' x <- gs_design_ahr(
68-
#' enroll_rate = enroll_rate, fail_rate = fail_rate,
69-
#' alpha = alpha, beta = beta, ratio = ratio,
70-
#' info_scale = "h0_info",
71-
#' info_frac = NULL,
72-
#' analysis_time = c(20, 36),
73-
#' upper = gs_spending_bound, upar = upar,
74-
#' lower = gs_b, lpar = rep(-Inf, 2),
75-
#' test_upper = TRUE, test_lower = FALSE) |> to_integer()
76-
#'
77-
#' # Observed dataset at IA and FA
78-
#' set.seed(123)
79-
#'
80-
#' observed_data <- simtrial::sim_pw_surv(
81-
#' n = x$analysis$n[x$analysis$analysis == 2],
82-
#' stratum = data.frame(stratum = "All", p = 1),
83-
#' block = c(rep("control", 2), rep("experimental", 2)),
84-
#' enroll_rate = x$enroll_rate,
85-
#' fail_rate = (fail_rate |> simtrial::to_sim_pw_surv())$fail_rate,
86-
#' dropout_rate = (fail_rate |> simtrial::to_sim_pw_surv())$dropout_rate)
87-
#'
88-
#' observed_data_ia <- observed_data |> simtrial::cut_data_by_date(x$analysis$time[1])
89-
#' observed_data_fa <- observed_data |> simtrial::cut_data_by_date(x$analysis$time[2])
90-
#'
91-
#' observed_event_ia <- sum(observed_data_ia$event)
92-
#' observed_event_fa <- sum(observed_data_fa$event)
93-
#'
94-
#' planned_event_ia <- x$analysis$event[1]
95-
#' planned_event_fa <- x$analysis$event[2]
96-
#'
97-
#' # Example A1 ----
98-
#' # IA spending = observed events / final planned events
99-
#' # the remaining alpha will be allocated to FA.
100-
#' ustime <- c(observed_event_ia / planned_event_fa, 1)
101-
#' gs_update_ahr(
102-
#' x = x,
103-
#' ustime = ustime,
104-
#' observed_data = list(observed_data_ia, observed_data_fa))
105-
#'
106-
#' # Example A2 ----
107-
#' # IA, FA spending = observed events / final planned events
108-
#' ustime <- c(observed_event_ia, observed_event_fa) / planned_event_fa
109-
#' gs_update_ahr(
110-
#' x = x,
111-
#' ustime = ustime,
112-
#' observed_data = list(observed_data_ia, observed_data_fa))
113-
#'
114-
#' # Example A3 ----
115-
#' # IA spending = min(observed events, planned events) / final planned events
116-
# # the remaining alpha will be allocated to FA.
117-
#' ustime <- c(min(observed_event_ia, planned_event_ia) / planned_event_fa, 1)
118-
#' gs_update_ahr(
119-
#' x = x,
120-
#' ustime = ustime,
121-
#' observed_data = list(observed_data_ia, observed_data_fa))
122-
#'
123-
#' # Example A4 ----
124-
#' # IA spending = min(observed events, planned events) / final planned events
125-
#' ustime <- c(min(observed_event_ia, planned_event_ia),
126-
#' min(observed_event_fa, planned_event_fa)) / planned_event_fa
127-
#' gs_update_ahr(
128-
#' x = x,
129-
#' ustime = ustime,
130-
#' observed_data = list(observed_data_ia, observed_data_fa))
131-
#'
132-
#' # alpha is upadted to 0.05
133-
#' gs_update_ahr(
134-
#' x = x,
135-
#' alpha = 0.05,
136-
#' ustime = ustime,
137-
#' observed_data = list(observed_data_ia, observed_data_fa))
138-
#'
139-
#' # ------------------------------------------------- #
140-
#' # Example B: Two-sided asymmetric design,
69+
#' # Two-sided asymmetric design,
14170
#' # beta-spending with non-binding lower bound
14271
#' # ------------------------------------------------- #
14372
#' # Original design
@@ -154,116 +83,47 @@
15483
#' test_lower = c(TRUE, FALSE),
15584
#' binding = FALSE) |> to_integer()
15685
#'
157-
#' # Example B1 ----
158-
#' # IA spending = observed events / final planned events
159-
#' # the remaining alpha will be allocated to FA.
160-
#' ustime <- c(observed_event_ia / planned_event_fa, 1)
161-
#' gs_update_ahr(
162-
#' x = x,
163-
#' ustime = ustime,
164-
#' lstime = ustime,
165-
#' observed_data = list(observed_data_ia, observed_data_fa))
86+
#' planned_event_ia <- x$analysis$event[1]
87+
#' planned_event_fa <- x$analysis$event[2]
16688
#'
167-
#' # Example B2 ----
168-
#' # IA, FA spending = observed events / final planned events
169-
#' ustime <- c(observed_event_ia, observed_event_fa) / planned_event_fa
170-
#' gs_update_ahr(
171-
#' x = x,
172-
#' ustime = ustime,
173-
#' lstime = ustime,
174-
#' observed_data = list(observed_data_ia, observed_data_fa))
17589
#'
176-
#' # Example B3 ----
177-
#' ustime <- c(min(observed_event_ia, planned_event_ia) / planned_event_fa, 1)
90+
#' # Updated design with 190 events observed at IA,
91+
#' # where 50 events observed during the delayed effect.
92+
#' # IA spending = observed events / final planned events, the remaining alpha will be allocated to FA.
17893
#' gs_update_ahr(
17994
#' x = x,
180-
#' ustime = ustime,
181-
#' lstime = ustime,
182-
#' observed_data = list(observed_data_ia, observed_data_fa))
95+
#' ustime = c(190 / planned_event_fa, 1),
96+
#' lstime = c(190 / planned_event_fa, 1),
97+
#' event_tbl = data.frame(analysis = c(1, 1),
98+
#' event = c(50, 140)))
18399
#'
184-
#' # Example B4 ----
185-
#' # IA spending = min(observed events, planned events) / final planned events
186-
#' ustime <- c(min(observed_event_ia, planned_event_ia),
187-
#' min(observed_event_fa, planned_event_fa)) / planned_event_fa
100+
#' # Updated design with 190 events observed at IA, and 300 events observed at FA,
101+
#' # where 50 events observed during the delayed effect.
102+
#' # IA spending = observed events / final planned events, the remaining alpha will be allocated to FA.
188103
#' gs_update_ahr(
189104
#' x = x,
190-
#' ustime = ustime,
191-
#' lstime = ustime,
192-
#' observed_data = list(observed_data_ia, observed_data_fa))
193-
#'
194-
#' # Example B5 ----
195-
#' # alpha is updated to 0.05 ----
196-
#' gs_update_ahr(x = x, alpha = 0.05)
105+
#' ustime = c(190 / planned_event_fa, 1),
106+
#' lstime = c(190 / planned_event_fa, 1),
107+
#' event_tbl = data.frame(analysis = c(1, 1, 2, 2),
108+
#' event = c(50, 140, 50, 250)))
197109
#'
198-
#' # Example B6 ----
199-
#' # updated boundaries only when IA data is observed
200-
#' ustime <- c(observed_event_ia / planned_event_fa, 1)
110+
#' # Updated design with 190 events observed at IA, and 300 events observed at FA,
111+
#' # where 50 events observed during the delayed effect.
112+
#' # IA spending = minimal of planned and actual information fraction spending
201113
#' gs_update_ahr(
202114
#' x = x,
203-
#' ustime = ustime,
204-
#' lstime = ustime,
205-
#' observed_data = list(observed_data_ia, NULL))
206-
#'
207-
#' # ------------------------------------------------- #
208-
#' # Example C: Two-sided asymmetric design,
209-
#' # with calendar spending for efficacy and futility bounds
210-
#' # beta-spending with non-binding lower bound
211-
#' # ------------------------------------------------- #
212-
#' # Original design
213-
#' x <- gs_design_ahr(
214-
#' enroll_rate = enroll_rate, fail_rate = fail_rate,
215-
#' alpha = alpha, beta = beta, ratio = ratio,
216-
#' info_scale = "h0_info",
217-
#' info_frac = NULL, analysis_time = c(20, 36),
218-
#' upper = gs_spending_bound,
219-
#' upar = list(sf = sfLDOF, total_spend = alpha, timing = c(20, 36) / 36),
220-
#' test_upper = TRUE,
221-
#' lower = gs_spending_bound,
222-
#' lpar = list(sf = sfLDOF, total_spend = beta, timing = c(20, 36) / 36),
223-
#' test_lower = c(TRUE, FALSE),
224-
#' binding = FALSE) |> to_integer()
115+
#' ustime = c(min(190, planned_event_ia) / planned_event_fa, 1),
116+
#' lstime = c(min(190, planned_event_ia) / planned_event_fa, 1),
117+
#' event_tbl = data.frame(analysis = c(1, 1, 2, 2),
118+
#' event = c(50, 140, 50, 250)))
225119
#'
226-
#' # Updated design due to potential change of multiplicity graph
120+
#' # Alpha is updated to 0.05 ----
227121
#' gs_update_ahr(x = x, alpha = 0.05)
228-
#'
229-
#' # ------------------------------------------------- #
230-
#' # Example D: one-sided design without TTE dataset as input
231-
#' # ------------------------------------------------- #
232-
#' # Original design
233-
#' upper <- gs_spending_bound
234-
#' upar <- list(sf = sfLDOF, total_spend = alpha)
235-
#' x <- gs_design_ahr(
236-
#' enroll_rate = enroll_rate, fail_rate = fail_rate,
237-
#' alpha = alpha, beta = beta, ratio = ratio,
238-
#' info_scale = "h0_info",
239-
#' info_frac = NULL,
240-
#' analysis_time = c(20, 36),
241-
#' upper = gs_spending_bound, upar = upar,
242-
#' lower = gs_b, lpar = rep(-Inf, 2),
243-
#' test_upper = TRUE, test_lower = FALSE) |> to_integer()
244-
#'
245-
#' # Updated design with 100 events observed at IA,
246-
#' # where 30 events observed during the delayed effect
247-
#' gs_update_ahr(
248-
#' x = x,
249-
#' ustime = c(100/x$analysis$event[2], 1),
250-
#' event_tbl = data.frame(analysis = c(1, 1),
251-
#' event_tbl = c(30, 70)))
252-
#'
253-
#' # Updated design with 100 events observed at IA, 170 events at FA
254-
#' # where 30 events observed during the delayed effect at IA,
255-
#' # and 40 events observed during the delayed effect at FA.
256-
#' gs_update_ahr(
257-
#' x = x,
258-
#' ustime = c(100/x$analysis$event[2], 1),
259-
#' event_tbl = data.frame(analysis = c(1, 1, 2, 2),
260-
#' event_tbl = c(30, 70, 40, 130)))
261122
gs_update_ahr <- function(
262123
x = NULL,
263124
alpha = NULL,
264125
ustime = NULL,
265126
lstime = NULL,
266-
observed_data = NULL,
267127
event_tbl = NULL) {
268128

269129
# ----------------------------------- #
@@ -314,7 +174,7 @@ gs_update_ahr <- function(
314174
# ----------------------------------- #
315175
# If users do not input observed data, nor event_tbl
316176
# which means they update design with a different value of alpha
317-
if (is.null(observed_data) && is.null(event_tbl)) {
177+
if (is.null(event_tbl)) {
318178

319179
# Check if ustime and lstime matches the spending time of the original design
320180
if (!is.null(ustime) && any(ustime != x$input$upar$timing)) {
@@ -375,7 +235,7 @@ gs_update_ahr <- function(
375235
blinded_est <- NULL
376236
observed_event <- NULL
377237
for (i in 1:n_analysis) {
378-
if (is.null(observed_data[[i]]) && !(i %in% event_tbl$analysis)) {
238+
if (!(i %in% event_tbl$analysis)) {
379239
# if there is no observed data at analysis i,
380240
# for example, we only observed IA data and FA data is unavailable yet
381241
blinded_est_new <- data.frame(event = x$analysis$event[i],
@@ -384,38 +244,15 @@ gs_update_ahr <- function(
384244
info0 = x$analysis$info0[i])
385245
event_new <- x$analysis$event[i]
386246
} else {
387-
# if both observed_data and event_tbl provided, check if the events matches
388-
if (!is.null(observed_data[[i]]) && i %in% event_tbl$analysis) {
389-
event_from_observed_data <- simtrial::fit_pwexp(srv = survival::Surv(time = observed_data[[i]]$tte,
390-
event = observed_data[[i]]$event),
391-
intervals = cumsum(x$fail_rate$duration))[, 3]
392-
event_from_event_tbl <- event_tbl$event[event_tbl$analysis == i, ]
393-
if (event_from_observed_data != event_from_event_tbl) {
394-
stop("The events from event_tbl mismatches observed_data.")
395-
}
396-
}
397-
398-
# if there is observed data at analysis i,
399-
# we calculate the blinded estimation based on the observed_data
400-
if (!is.null(observed_data[[i]])) {
401-
blinded_est_new <- ahr_blinded(surv = survival::Surv(time = observed_data[[i]]$tte,
402-
event = observed_data[[i]]$event),
403-
intervals = cumsum(x$fail_rate$duration),
404-
hr = x$input$fail_rate$hr,
405-
ratio = x$input$ratio)
406-
event_new <- sum(observed_data[[i]]$event)
407-
# we calculate the blinded estimation based on the event_tbl
408-
} else if (i %in% event_tbl$analysis) {
409-
q_e <- x$input$ratio / (1 + x$input$ratio)
410-
event_i <- event_tbl$event[event_tbl$analysis == i]
411-
hr_i <- x$fail_rate$hr
412-
event_new <- sum(event_i)
247+
q_e <- x$input$ratio / (1 + x$input$ratio)
248+
event_i <- event_tbl$event[event_tbl$analysis == i]
249+
hr_i <- x$fail_rate$hr
250+
event_new <- sum(event_i)
413251

414-
blinded_est_new <- data.frame(event = sum(event_i),
415-
theta = -sum(log(hr_i) * event_i) / sum(event_i),
416-
info0 = sum(event_i) * (1 - q_e) * q_e)
417-
blinded_est_new$ahr <- exp(-blinded_est_new$theta)
418-
}
252+
blinded_est_new <- data.frame(event = sum(event_i),
253+
theta = -sum(log(hr_i) * event_i) / sum(event_i),
254+
info0 = sum(event_i) * (1 - q_e) * q_e)
255+
blinded_est_new$ahr <- exp(-blinded_est_new$theta)
419256
}
420257

421258
blinded_est <- rbind(blinded_est, blinded_est_new)

tests/testthat/test-developer-gs_update_ahr.R

-63
This file was deleted.

0 commit comments

Comments
 (0)