The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
The bbssr
package provides comprehensive tools for
implementing blinded sample size re-estimation (BSSR)
in two-arm clinical trials with binary endpoints. This vignette
introduces the key concepts and demonstrates how to use the main
functions in the package.
Traditional clinical trials use fixed sample sizes determined during the planning phase. However, these calculations often rely on assumptions about treatment effects and response rates that may prove incorrect. BSSR addresses this limitation by allowing adaptive sample size adjustments during the trial while maintaining:
Let’s start with a basic power calculation for a traditional fixed-sample design:
# Calculate power for a traditional design
power_result <- BinaryPower(
p1 = 0.5, # Response rate in treatment group
p2 = 0.2, # Response rate in control group
N1 = 40, # Sample size in treatment group
N2 = 40, # Sample size in control group
alpha = 0.025, # One-sided significance level
Test = 'Fisher' # Fisher exact test
)
print(paste("Power:", round(power_result, 3)))
#> [1] "Power: 0.749"
Now let’s calculate the required sample size for a desired power:
# Calculate required sample size
sample_size_result <- BinarySampleSize(
p1 = 0.5, # Expected response rate in treatment group
p2 = 0.2, # Expected response rate in control group
r = 1, # Allocation ratio (1:1)
alpha = 0.025, # One-sided significance level
tar.power = 0.8, # Target power
Test = 'Boschloo' # Boschloo exact test (most powerful)
)
print(sample_size_result)
#> p1 p2 r alpha tar.power Test Power N1 N2 N
#> 1 0.5 0.2 1 0.025 0.8 Boschloo 0.8096508 40 40 80
Here’s how to perform BSSR analysis:
# Basic BSSR calculation
bssr_result <- BinaryPowerBSSR(
asmd.p1 = 0.45, # Assumed response rate in treatment group
asmd.p2 = 0.09, # Assumed response rate in control group
p = seq(0.1, 0.9, by = 0.1), # Range of pooled response rates
Delta.A = 0.36, # Assumed treatment effect (risk difference)
Delta.T = 0.36, # True treatment effect
N1 = 24, # Initial sample size in treatment group
N2 = 24, # Initial sample size in control group
omega = 0.5, # Fraction of data for interim analysis
r = 1, # Allocation ratio
alpha = 0.025, # Significance level
tar.power = 0.8, # Target power
Test = 'Z-pool', # Statistical test
restricted = FALSE, # Unrestricted design
weighted = FALSE # Non-weighted approach
)
# Display first few rows
head(bssr_result)
#> p1 p2 p power.BSSR power.TRAD
#> 1 0.38 0.02 0.2 0.8728849 0.9310364
#> 2 0.48 0.12 0.3 0.7714587 0.7880436
#> 3 0.58 0.22 0.4 0.7816618 0.7168506
#> 4 0.68 0.32 0.5 0.7851850 0.6677197
#> 5 0.78 0.42 0.6 0.7816618 0.7168506
#> 6 0.88 0.52 0.7 0.7714587 0.7880436
One of the key features of bbssr
is the ability to
compare different BSSR design rules. Here’s the comprehensive comparison
as requested:
# Calculate power of the BSSR with binary endpoint
power.BSSR <- tibble(
Rule = factor(
c('Restricted', 'Unrestricted', 'Weighted'),
levels = c('Restricted', 'Unrestricted', 'Weighted')
),
restricted = c(TRUE, FALSE, FALSE),
weighted = c(FALSE, FALSE, TRUE)
) %>%
group_by_all() %>%
reframe(r = c(1, 2), N1 = c(24, 36), N2 = c(24, 18)) %>%
group_by_all() %>%
reframe(
BinaryPowerBSSR(
asmd.p1 = 0.45, asmd.p2 = 0.09, p = seq(0, 1, by = 0.01),
Delta.A = 0.36, Delta.T = 0.36, N1, N2, omega = 0.5, r,
alpha = 0.025, tar.power = 0.8, Test = 'Z-pool',
restricted, weighted
)
) %>%
mutate(
Rule = factor(Rule, levels = c('Restricted', 'Unrestricted', 'Weighted')),
r_label = paste0('Allocation ratio = ', r, ':1')
) %>%
rename(Theta = p, Power = power.BSSR)
# Create the improved figure
power.BSSR %>%
ggplot(aes(x = Theta, y = Power)) +
geom_line(aes(color = Rule), linewidth = 1.0) +
theme_bw() +
facet_grid(. ~ r_label) +
geom_hline(yintercept = 0.8, color = 'gray', linetype = 'longdash', linewidth = 1.0) +
scale_x_continuous(
limits = c(0.1, 0.9),
breaks = seq(0.2, 0.8, by = 0.2), # Fewer x-axis breaks
labels = c("0.2", "0.4", "0.6", "0.8")
) +
scale_y_continuous(
limits = c(0.7, 1.0),
breaks = seq(0.7, 1.0, by = 0.1),
labels = c("0.7", "0.8", "0.9", "1.0")
) +
scale_color_manual(
values = c("Restricted" = "#E31A1C", "Unrestricted" = "#1F78B4", "Weighted" = "#33A02C")
) +
labs(
x = expression(theta),
y = "Power",
title = "Power Comparison: BSSR Design Rules",
subtitle = "Dashed line indicates target power = 0.8"
) +
theme(
text = element_text(size = 11),
plot.title = element_text(size = 13, hjust = 0.5, margin = margin(b = 5)),
plot.subtitle = element_text(size = 10, hjust = 0.5, margin = margin(b = 10)),
panel.spacing = unit(0.8, 'lines'),
legend.position = 'bottom',
legend.key.width = unit(1.2, 'cm'),
legend.text = element_text(size = 10),
legend.title = element_blank(),
legend.margin = margin(t = 8, r = 0, b = 0, l = 0),
axis.title.x = element_text(size = 11, margin = margin(t = 8)),
axis.title.y = element_text(size = 11, margin = margin(r = 8)),
axis.text = element_text(size = 9),
strip.text = element_text(size = 10),
plot.margin = margin(t = 10, r = 10, b = 5, l = 5)
)
The plot above shows three different BSSR approaches:
The package supports five different exact statistical tests:
Test | Code | Description | Characteristics |
---|---|---|---|
Pearson chi-squared | 'Chisq' |
One-sided exact test | Good for large samples |
Fisher exact | 'Fisher' |
Classical conditional test | Conservative, widely accepted |
Fisher mid-p | 'Fisher-midP' |
Less conservative Fisher | Better power than Fisher exact |
Z-pooled | 'Z-pool' |
Unconditional exact test | Good compromise |
Boschloo | 'Boschloo' |
Most powerful unconditional | Highest power, computationally intensive |
# Compare different statistical tests
tests <- c('Chisq', 'Fisher', 'Fisher-midP', 'Z-pool', 'Boschloo')
test_results <- sapply(tests, function(test) {
BinaryPower(p1 = 0.5, p2 = 0.2, N1 = 30, N2 = 30, alpha = 0.025, Test = test)
})
test_comparison_df <- data.frame(
Test = tests,
Power = round(test_results, 3)
)
print(test_comparison_df)
#> Test Power
#> Chisq Chisq 0.692
#> Fisher Fisher 0.596
#> Fisher-midP Fisher-midP 0.679
#> Z-pool Z-pool 0.678
#> Boschloo Boschloo 0.671
BSSR is particularly valuable when: - Initial assumptions about response rates are uncertain - Regulatory efficiency is important - Maintaining study blinding is critical - Exact statistical control is required
This vignette provided a basic introduction to bbssr
.
For more advanced topics, see:
vignette("bbssr-statistical-methods")
- Detailed
statistical methodologyhelp(package = "bbssr")
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.