12 Scenario XI: F-Distribution
12.1 Details
In this scenario, we compute the necessary sample size for a one-way ANOVA with \(k\) groups. The resulting test statistic is \(F\)-distributed with \(k-1\) and \(nk-k\) degrees of freedom, where \(n\) stands for the sample size per group.
12.2 Variant XI-1: ANOVA
12.2.1 Setup
Under the alternative, we assume a mean of \(0.0\) in the first group, \(0.4\) in the second group and \(0.2\) in the third group.
<- c(0, 0.4, 0.2)
means <- get_tau_ANOVA(means)
theta
<- ANOVA(3)
datadist <- PointMassPrior(0, 1)
H_0 <- PointMassPrior(theta, 1)
prior
<- 0.05
alpha <- 0.8
min_power
<- Power(datadist, H_0) <= alpha
toer_cnstr <- Power(datadist, prior) >= min_power pow_cnstr
12.2.2 Objective
We want to minimize the expected sample size under the alternative.
<- ExpectedSampleSize(datadist, prior) ess
12.2.3 Initial Design
The initial designs are chosen via the in-built function to create initial designs.
<- tibble(
tbl_designs type = c("one-stage", "group-sequential", "two-stage"),
initial = list(
get_initial_design(theta, alpha, 1 - min_power,
"one-stage", dist = datadist),
get_initial_design(theta, alpha, 1 - min_power,
"group-sequential", dist = datadist),
get_initial_design(theta, alpha, 1 - min_power,
"two-stage", dist = datadist) ))
12.2.4 Optimization
<- tbl_designs %>%
tbl_designs mutate(
optimal = purrr::map(initial, ~minimize(
ess,subject_to(
toer_cnstr,
pow_cnstr
),
initial_design = .,
opts = opts)) )
12.2.5 Test Cases
We first verify that in none of the three cases, the maximal number of iterations was exceeded.
%>%
tbl_designs transmute(
type, iterations = purrr::map_int(tbl_designs$optimal,
~.$nloptr_return$iterations) ) %>%
print(.); .} %>%
{::expect_true(all(.$iterations < opts$maxeval))} {testthat
## # A tibble: 3 × 2
## type iterations
## <chr> <int>
## 1 one-stage 22
## 2 group-sequential 1429
## 3 two-stage 1913
We then check via simulations of the test statistic, that the type I error and power constraints are fulfilled.
%>%
tbl_designs transmute(
type, toer = purrr::map(tbl_designs$optimal,
~sim_pr_reject(.[[1]], .0, datadist)$prob),
power = purrr::map(tbl_designs$optimal,
~sim_pr_reject(.[[1]], theta , datadist)$prob) ) %>%
unnest(., cols = c(toer, power)) %>%
print(.); .} %>% {
{::expect_true(all(.$toer <= alpha * (1 + tol)))
testthat::expect_true(all(.$power >= min_power * (1 - tol))) } testthat
## # A tibble: 3 × 3
## type toer power
## <chr> <dbl> <dbl>
## 1 one-stage 0.0503 0.799
## 2 group-sequential 0.0502 0.798
## 3 two-stage 0.0500 0.799
The sample size function \(n_2\) should be monotonously decreasing.
::expect_true(
testthatall(diff(
# get optimal two-stage design n2 pivots
%>% filter(type == "two-stage") %>%
tbl_designs "optimal"]][[1]]$design@n2_pivots}
{.[[< 0) ) )
Since the degrees of freedom of the three design classes are ordered as
‘two-stage’ > ‘group-sequential’ > ‘one-stage’,
the expected sample sizes (under the alternative) should be ordered
in reverse (‘two-stage’ smallest).
Additionally, expected sample sizes under both null and alternative
are computed both via evaluate()
and simulation-based.
<- ExpectedSampleSize(datadist, H_0)
ess0
%>%
tbl_designs mutate(
ess = map_dbl(optimal,
~evaluate(ess, .$design) ),
ess_sim = map_dbl(optimal,
~sim_n(.$design, theta, datadist)$n ),
ess0 = map_dbl(optimal,
~evaluate(ess0, .$design) ),
ess0_sim = map_dbl(optimal,
~sim_n(.$design, .0, datadist)$n ) ) %>%
print(.); .} %>% {
{# sim/evaluate same under alternative?
::expect_equal(.$ess, .$ess_sim,
testthattolerance = tol_n,
scale = 1)
# sim/evaluate same under null?
::expect_equal(.$ess0, .$ess0_sim,
testthattolerance = tol_n,
scale = 1)
# monotonicity with respect to degrees of freedom
::expect_true(all(diff(.$ess) < 0)) } testthat
## # A tibble: 3 × 7
## type initial optimal ess ess_sim ess0 ess0_sim
## <chr> <list> <list> <dbl> <dbl> <dbl> <dbl>
## 1 one-stage <OnStgDsg> <adptrOpR [3]> 121 121 121 121
## 2 group-sequential <GrpSqntD> <adptrOpR [3]> 111. 111. 103. 103.
## 3 two-stage <TwStgDsg> <adptrOpR [3]> 111. 111. 104. 105.
The expected sample size under the alternative of the optimized designs should be lower than the sample size of the initial designs.
::expect_lte(
testthatevaluate(ess,
%>%
tbl_designs pull(optimal) %>%
1]] %>%
.[[$design ),
.evaluate(ess,
%>%
tbl_designs pull(initial) %>%
1]] ) ) .[[