library(survival)
## Warning: package 'survival' was built under R version 4.2.3
library(stats)
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.2.3
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
set.seed(12345)
simu <- function(alpha, beta, rate1, rate2, t1, real_rate2, rec, CL, CU, num_simulations){
z_alpha <- qnorm(1 - alpha/2)
z_beta <- qnorm(1 - beta)
# Rate is the probability to develop disease event in 76 weeks (for example)
rate <- (rate1+rate2)/2
diff <- rate1-rate2
# Calculate total Z-score required
z_total <- z_alpha + z_beta
# Calculate required sample size
n <- ceiling((z_total^2 * (rate * (1 - rate) * 2)) / diff^2)*2
n1 <- n/2
n2 <- n/2
# Actual event rate for group 1 is fixed
real_rate1 <- rate1
final_results <- data.frame()
scen_results <- data.frame()
count_simu <- 0
for (i in 1:num_simulations) {
# Calculate hazard rate from event rate
hr1 <- -log(1-real_rate1) / 76
hr2 <- -log(1-real_rate2) / 76
# Generate survival times
event_time1 <- rexp(n1, rate = hr1)
event_time2 <- rexp(n2, rate = hr2)
event_time <- c(event_time1, event_time2)
group1 <- rep(1, n1)
group2 <- rep(2, n2)
group <- c(group1, group2)
subj <-1:n
# Follow-up time is 76 weeks
follow_up <- 76
# Assume recruitment time is rec rate of total follow up time (final time)
rec_length <- follow_up*rec
# Assume uniform distribution for recruitment
rec_time <- runif(n, 0, rec_length)
# Study time for each subject at event occurrence is recruitment time plus event time
study_time <- rec_time + event_time
# Final time for each subject (if no event happened) is recruitment time plus follow-up time
final_time <- rec_time + follow_up
# Time to interim analysis (n*t1 subjects reach 76 weeks or have events)
sorted_interim <- sort(final_time)
interim_time <- sorted_interim[n*t1]
all_data <- data.frame(study_time = study_time, event_time = event_time, rec_time = rec_time, group = group, interim_time = interim_time, final_time = final_time, subj=subj)
surv_data <- all_data %>% filter(final_time <= interim_time)
# Compare with interim time for event indicator: 1 = event, 0 = censored
surv_data$cens <- ifelse(surv_data$study_time <= surv_data$interim_time, 1, 0)
n_int <- nrow(surv_data)
p <- sum(surv_data$cens)/n_int
# Calculate event rate in each treatment at interim, with control group fixed
if (p==1 | p==0 | p*2<=real_rate1 | p*2-real_rate1>=1) {
next
}
else{
p1 <- real_rate1
p2 <- p * 2 - p1
delta <- p1 - p2
# Calculate Z score
#SE <- sqrt(p * (1 - p) * (1/(n_int/2) + 1/(n_int/2)))
#Z_t <-(p1-p2)/SE
#alpha_D <- 0.05
#Z_alpha_D <- qnorm(1 -alpha_D/2)
# Calculate B-value
#B_t <- Z_t * sqrt(t1)
# Estimate drift parameter
#delta_hat_t <- B_t / t1
# Calculate conditional power
#Z_CP_t <- (delta_hat_t - Z_alpha_D) / sqrt(1 - t1)
#cp <- pnorm(Z_CP_t)
# Calculate conditional power
se <- sqrt(p * (1 - p) * (1 / n1 + 1 / n2))
# Calculate the Z-score for the observed difference
z_observed <- delta / se
# Calculate the power
cp <- pnorm(z_observed - z_alpha) + pnorm(-z_observed - z_alpha)
# Decision rules
if (is.na(cp)) {next}
else {
if (cp > CL & cp < CU) {
cat="Promising"
# Calculate the required sample size
n_star <- ceiling((z_total^2 * (p * (1 - p) * 2)) / (abs(delta))^2)*2
# Apply max N
n_new <- ifelse(n_star<=2*n, n_star, 2*n)
# add n
n_add <- ceiling((n_new-n)/2)*2
add_event_time1 <- rexp(n_add/2, rate = - log(1-p1) / 76)
add_event_time2 <- rexp(n_add/2, rate = - log(1-p2) / 76)
add_event_time <- c(add_event_time1, add_event_time2)
add_group1 <- rep(1, n_add/2)
add_group2 <- rep(2, n_add/2)
add_group <- c(add_group1, add_group2)
add_rec_length <- rec_length*n_add/n
add_rec_time <- runif(n_add, 0, add_rec_length) + interim_time
add_study_time <- add_rec_time + add_event_time
add_final_time <- add_rec_time + follow_up
add_subj <- (n+1):n_new
add_data <- data.frame(study_time = add_study_time, event_time = add_event_time, rec_time = add_rec_time, group = add_group, interim_time=interim_time, final_time=add_final_time, subj=add_subj)
comb_data <- rbind(all_data, add_data)
final_data <- comb_data %>% subset(select=c(study_time, event_time, rec_time, group, interim_time, final_time, subj))
# event time compare with final time to get indicator: 1 = event, 0 = censored
final_data$cens <- ifelse(final_data$study_time <= final_data$final_time, 1, 0)
}
else {
n_new=n
final_data <- all_data %>% subset(select=c(study_time, event_time, rec_time, group, interim_time, final_time, subj))
# event time compare with final time: 1 = event, 0 = censored
final_data$cens <- ifelse(final_data$study_time <= final_data$final_time, 1, 0)
if (cp <= CL) {cat="Unfavorable"}
else if (cp >= CU) {cat="Favorable"}
}
count_simu <- count_simu + 1
# final and interim analysis results
final_table <- table(final_data$group, final_data$cens)
count_group1 <- final_table["1", "1"]
count_group2 <- final_table["2", "1"]
final_p1 <- count_group1/(n_new/2)
final_p2 <- count_group2/(n_new/2)
final_p <- (count_group1 + count_group2) / n_new
# Standard error
SE_final <- sqrt(final_p * (1 - final_p) * (1/(n_new/2) + 1/(n_new/2)))
# Z statistic
z_final <- (final_p1 - final_p2) / SE_final
# P-value
p_value <- 2 * (1 - pnorm(abs(z_final)))
hypo <- ifelse(p_value < alpha, 1, 0)
final_results <- rbind(final_results, data.frame(p = p, p1 = p1, p2 = p2, cp = cp, cat = cat, n_new = n_new, p_value = p_value, hypo = hypo, count_simu = count_simu, n_int = nrow(surv_data)))
}
}
}
# interim analysis results printouts
est_n <- mean(final_results$n_new)
cp_mean <- mean(final_results$cp)
# Calculate the frequency and proportion of each category
cat_count <- table(final_results$cat)
prop_cat <- prop.table(cat_count)
# Print out some results
cat("New Sample Size / Original Sample Size:", est_n, "/", n, "(", est_n/n, ")", "\n")
cat("Mean Conditional Power:", cp_mean, "\n")
print(prop_cat)
# final analysis results printouts
sig <- sum(final_results$hypo)/max(final_results$count_simu)
nosig <- 1 - sig
cat("Probability of claim success:", sig, "\n")
cat("Proportion of not claim success:", nosig, "\n")
}
### under alternative hypothesis and type II error
simu(alpha=0.05, beta=0.2, rate1=0.7, rate2=0.3, t1=0.5, real_rate2=0.2, rec=1, CL=0.2, CU=0.8, num_simulations=100)
## New Sample Size / Original Sample Size: 65.5102 / 50 ( 1.310204 )
## Mean Conditional Power: 0.6834166
##
## Favorable Promising Unfavorable
## 0.5102041 0.3877551 0.1020408
## Probability of claim success: 0.9591837
## Proportion of not claim success: 0.04081633
### when real rate is same as assumed rate
simu(alpha=0.05, beta=0.2, rate1=0.7, rate2=0.3, t1=0.5, real_rate2=0.3, rec=1, CL=0.2, CU=0.8, num_simulations=100)
## New Sample Size / Original Sample Size: 67.3 / 50 ( 1.346 )
## Mean Conditional Power: 0.5015433
##
## Favorable Promising Unfavorable
## 0.24 0.46 0.30
## Probability of claim success: 0.87
## Proportion of not claim success: 0.13
### under null hypothesis and type I error
simu(alpha=0.05, beta=0.2, rate1=0.7, rate2=0.3, t1=0.5, real_rate2=0.7, rec=1, CL=0.2, CU=0.8, num_simulations=100)
## New Sample Size / Original Sample Size: 63.37931 / 50 ( 1.267586 )
## Mean Conditional Power: 0.3061703
##
## Promising Unfavorable
## 0.4367816 0.5632184
## Probability of claim success: 0.1494253
## Proportion of not claim success: 0.8505747