Skip to content

Commit 936ec20

Browse files
Merge pull request #579 from Merck/578-the-sample-size-from-pw_info-is-not-correct-when-control-median-change-but-hr-unchanged
Sample size from `pw_info` is not correct when control median change but HR remain unchanged
2 parents 3ffa6cc + 5342ebc commit 936ec20

File tree

4 files changed

+50
-35
lines changed

4 files changed

+50
-35
lines changed

R/pw_info.R

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,15 @@ pw_info <- function(
179179
event = sum(event),
180180
info0 = sum(info0),
181181
info = sum(info)
182-
), by = .(time, stratum, hr)]
182+
), by = .(time, stratum, t, hr)]
183183

184184
# -------------------------------------- #
185185
# output the results #
186186
# -------------------------------------- #
187-
ans <- merge(tbl_event, tbl_n, by = c("time", "t", "stratum"))
187+
# merge 2 tables tbl_n and tbl_event, where they share the same time, t, stratum
188+
ans <- tbl_event[tbl_n, on = c("time", "stratum", "t")]
189+
ans[, t.1 := NULL]
190+
188191
# filter out the rows with 0 events and unneeded columns
189192
ans <- ans[!almost_equal(event, 0L), .(time, stratum, t, hr, n, event, info, info0)]
190193

tests/testthat/test-developer-pw_info.R

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,17 @@ test_that("When there are many pieces of HRs", {
111111
fail_rate = fail_rate,
112112
ratio = 2)
113113
)
114-
})
114+
})
115+
116+
test_that("When control median changes but HR remain unchanged", {
117+
x <- pw_info(
118+
enroll_rate = define_enroll_rate(duration = 12, rate = 20),
119+
fail_rate = define_fail_rate(duration = c(9, Inf),
120+
fail_rate = log(2) / c(10, 20),
121+
hr = c(0.72, 0.72),
122+
dropout_rate = 0.001),
123+
total_duration = 50,
124+
ratio = 1)
125+
126+
expect_equal(sum(x$n), 20 * 12)
127+
})

tests/testthat/test-independent-ahr.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,16 @@ test_that("AHR results are consistent with simulation results for single stratum
7171
expect_true(all.equal(simulation_ahr3$AHR, actual$ahr, tolerance = 5e-3))
7272
expect_true(all.equal(simulation_ahr3$Events, actual$event, tolerance = 7e-3))
7373
})
74+
75+
test_that("The sample size returned from the ahr() function is correct", {
76+
x <- ahr(
77+
enroll_rate = define_enroll_rate(duration = 24, rate = 10),
78+
fail_rate = define_fail_rate(duration = c(4, 2, 38),
79+
fail_rate = rep(log(2)/14, 3),
80+
hr = c(0.7, 0.7, 0.7),
81+
dropout_rate = - log(1 - 0.15)/12),
82+
total_duration = c(seq(1, 48, 1)))
83+
84+
expect_equal(x |> dplyr::filter(time <= 24) |> dplyr::pull(n), 1:24*10)
85+
expect_equal(x |> dplyr::filter(time > 24) |> dplyr::pull(n) |> unique(), 24*10)
86+
})

tests/testthat/test-independent-gs_power_ahr.R

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,14 @@ x <- gsDesign::gsSurv(
1919
T = NULL,
2020
minfup = NULL,
2121
ratio = 1
22-
)
22+
) |> gsDesign::toInteger()
2323

24-
# Update x with gsDesign() to get integer event counts
25-
x <- gsDesign::gsDesign(
26-
k = x$k,
27-
test.type = 1,
28-
alpha = x$alpha,
29-
beta = x$beta,
30-
sfu = x$upper$sf,
31-
sfupar = x$upper$param,
32-
n.I = ceiling(x$n.I),
33-
maxn.IPlan = ceiling(x$n.I[x$k]),
34-
delta = x$delta,
35-
delta1 = x$delta1,
36-
delta0 = x$delta0
37-
)
3824
y <- gsDesign::gsBoundSummary(
3925
x,
4026
ratio = 1,
4127
digits = 4,
4228
ddigits = 2,
43-
tdigits = 1,
29+
tdigits = 4,
4430
timename = "Month",
4531
logdelta = TRUE
4632
)
@@ -54,16 +40,16 @@ test_that("under same number of events, compare the power", {
5440

5541
out <- gs_power_ahr(
5642
enroll_rate = define_enroll_rate(
57-
duration = c(2, 2, 2, 6),
58-
rate = c(6, 12, 18, 24)
43+
duration = x$R,
44+
rate = x$gamma |> as.vector()
5945
),
6046
fail_rate = define_fail_rate(
61-
duration = 1,
62-
fail_rate = log(2) / 9,
63-
hr = 0.65,
64-
dropout_rate = 0.001
47+
duration = Inf,
48+
fail_rate = x$lambdaC |> as.vector(),
49+
dropout_rate = x$etaE |> as.vector(),
50+
hr = x$hr
6551
),
66-
ratio = 1,
52+
ratio = x$ratio,
6753
# Set number of events the same as the design x above from gsDesign()
6854
event = x$n.I,
6955
analysis_time = NULL,
@@ -84,20 +70,20 @@ test_that("under same power setting, compare the number of events", {
8470

8571
out <- gs_power_ahr(
8672
enroll_rate = define_enroll_rate(
87-
duration = c(2, 2, 2, 6),
88-
rate = c(6, 12, 18, 24)
73+
duration = x$R,
74+
rate = x$gamma |> as.vector()
8975
),
9076
fail_rate = define_fail_rate(
91-
duration = 1,
92-
fail_rate = log(2) / 9,
93-
dropout_rate = 0.001,
94-
hr = 0.65
77+
duration = Inf,
78+
fail_rate = x$lambdaC |> as.vector(),
79+
dropout_rate = x$etaE |> as.vector(),
80+
hr = x$hr
9581
),
96-
ratio = 1,
82+
ratio = x$ratio,
9783
event = NULL,
9884
# Adjust the times s.t. power ~= 0.801 and information fraction ~= 0.7
9985
# (same as the design x above from gsDesign())
100-
analysis_time = c(21, 34.9),
86+
analysis_time = sub("^Month: ", "", y$Analysis[startsWith(y$Analysis, "Month: ")]) |> as.numeric(),
10187
binding = FALSE,
10288
upper = gs_spending_bound,
10389
upar = list(sf = gsDesign::sfLDOF, total_spend = 0.025, param = NULL, timing = NULL, theta = 0),
@@ -108,5 +94,5 @@ test_that("under same power setting, compare the number of events", {
10894
)
10995

11096
# In case test fails, check whether caused by small tolerance
111-
expect_equal(out$analysis$event[1:2], x$n.I, tolerance = 0.02)
97+
expect_equal(out$analysis$event[1:2], x$n.I, tolerance = 0.002)
11298
})

0 commit comments

Comments
 (0)