## Description

The One Arm Expected Events calculator computes an estimate of the expected events for a planned one-arm study. The program assumes uniform accrual and exponential survival. It allows the user to specify a follow-up period after the close of study accrual. The program default presents a table of expected event totals at timepoints spanning the duration of the study. Alternatively, user can calculate the expected proportion of events at a given time, or the time at which a given proportion of events have occurred. The program will allow the user to specify a percentage of patients that have no risk (‘Percent cured’).

## Input Items

The user is prompted for values to the following items. For items that have initial default values set, the values are given in parentheses.

• Type of calculation- table of event information, expected events at a given analysis time, or analysis time for a given proportion of expected events
• Survival probability at time t, or hazard rate
• Accrual time
• Follow-up time
• Sample size
• Percent cured (0%)
• Analysis time (if computing expected events at a given analysis time)
• Percent of events at analysis time (if computing analysis time for a given proportion of events)

## Output Items

For calculations of expected events at given analysis time(s):

• Expected events at analysis time(s) specified
• Percentage of total expected events at analysis time(s) specified
• Total expected events on study
• For default table output, accrual and percent of total accrual at each timepoint

For calculations of analysis time for a given number of expected events:

• Analysis time for a given number of expected events
• Percentage of total expected events at analysis time(s) specified
• Total expected events on study

## Calculations

Hazard rate: The hazard rate $$\lambda$$ for a survival probability S(t) at time t is computed as follows:

$\lambda = \frac{-ln(S(t))}{t}$

Total probability of event: The probability $$P_{tot}$$ of an event for a study with hazard rate $$\lambda$$, accrual time $$t_{acc}$$, and follow-up time $$t_{fu}$$, is as follows:

$P_{tot} = 1 - \frac{e^{-\lambda t_{fu}}(1-e^{-\lambda t_{acc}})}{\lambda t_{acc}}$

Fraction of the total events at time t: At times before the completion of accrual, the probability of an event at analysis time t is

$P(Event|t) =\frac{ P_{d}|t}{P_{tot}}$ At times before the completion of accrual, $$P_{d}|t$$ is as follows:

$P_{d}|t = \frac{(\frac{1}{\lambda}e^{-\lambda t})+t-\frac{1}{\lambda}}{t_{acc}}$

At all other times, $$P_{d}|t$$ is as follows:

$P_{d}|t = 1 - \frac{e^{-\lambda (t-t_{acc})}(1-e^{-\lambda t_{acc}})}{\lambda t_{acc}}$

## Statistical Code

The program is written in R.

View Analysis Time for a Given Proportion of Total Events Code


function(hazard, medsurv, survtime, survprob, accrual_time, fu_time, N, pct_events, survival_input, pct_cured) {

if (survival_input == "Median Survival") {
hazard = -1 * log(0.5) / medsurv
}
if (survival_input == "Survival Probability") {
hazard = -1 * log(survprob) / survtime
}

perdeath = function(hazard, accrual_time, fu_tume, time) {
ptot = 1 - exp(-1 * hazard * fu_tume) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
if (time < accrual_time) {
pd = ((1 / hazard) * exp(-1 * hazard * time) + time - 1 / hazard) / accrual_time
}
else {
pd = 1 - exp(-1 * hazard * (time - accrual_time)) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
}
return(pd / ptot)
}

aperdeath = function(hazard, accrual, follow, p) {
v = .5
dv = .5
x = 0
while (dv > 1e-6) {
x = 1 / v - 1
dv = dv / 2
if (perdeath(hazard, accrual, follow, x) > p) {
v = v + dv
} else {
v = v - dv
}
}
return(x)
}

eea = (1 - pct_cured) * N * (1 - exp(-1 * hazard * fu_time) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time))
analysis_time = aperdeath(hazard, accrual_time, fu_time, pct_events)
eet = eea * perdeath(hazard, accrual_time, fu_time, analysis_time)

result = list(hazard = signif(hazard, 2),
analysis_time = round(analysis_time, 2),
eet = floor(eet),
eea = floor(eea))
return(jsonlite::toJSON(result, pretty = TRUE))
}




View Expected Events for Given Analysis Time Code


function(hazard, medsurv, survtime, survprob, accrual_time, fu_time, N, analysis_time, survival_input, pct_cured) {

if (survival_input == "Median Survival") {
hazard = -1 * log(0.5) / medsurv
}
if (survival_input == "Survival Probability") {
hazard = -1 * log(survprob) / survtime
}

perdeath = function(hazard, accrual_time, fu_tume, time) {
ptot = 1 - exp(-1 * hazard * fu_tume) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
if (time < accrual_time) {
pd = ((1 / hazard) * exp(-1 * hazard * time) + time - 1 / hazard) / accrual_time
} else {
pd = 1 - exp(-1 * hazard * (time - accrual_time)) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
}
return(pd / ptot)
}

pct_eet = perdeath(hazard, accrual_time, fu_time, analysis_time)
pct_eet_100 = pct_eet * 100
eea = (1 - pct_cured) * N * (1 - exp(-1 * hazard * fu_time) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time))
eet = pct_eet * eea

result = list(hazard = signif(hazard, 2),
pct_eet_100 = round(pct_eet_100, 1),
eet = floor(eet),
eea = floor(eea))
return(jsonlite::toJSON(result, pretty = TRUE))
}




View Expected Event Table Code


function(hazard, medsurv, survtime, survprob, accrual_time, fu_time, N, time_unit, survival_input, pct_cured) {

if (survival_input == "Median Survival") {
hazard = -1 * log(0.5) / medsurv
}
if (survival_input == "Survival Probability") {
hazard = -1 * log(survprob) / survtime
}

end_time = (accrual_time + fu_time) * (ifelse(time_unit == 'Years', 12, 1))
follow_time = (fu_time) * (ifelse(time_unit == 'Years', 12, 1))
acc_time = (accrual_time) * (ifelse(time_unit == 'Years', 12, 1))
hazard_months = hazard / ifelse(time_unit == 'Years', 12, 1)

bymonth = matrix(nrow = end_time, ncol = 5)

perdeath = function(hazard, accrual_time, fu_tume, time) {
ptot = 1 - exp(-1 * hazard * fu_tume) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
if (time < accrual_time) {
pd = ((1 / hazard) * exp(-1 * hazard * time) + time - 1 / hazard) / accrual_time
} else {
pd = 1 - exp(-1 * hazard * (time - accrual_time)) * (1 - exp(-1 * hazard * accrual_time)) / (hazard * accrual_time)
}
return(pd / ptot)
}

p_t = perdeath(hazard_months, acc_time, follow_time, end_time)
eea = (1 - pct_cured) * N * (1 - exp(-1 * hazard_months * follow_time) * (1 - exp(-1 * hazard_months * acc_time)) / (hazard_months * acc_time))
eet = p_t * eea

for (i in 1:end_time) {
Ni = floor(min(N, i * (N / acc_time)))
p_i = perdeath(hazard_months, acc_time, follow_time, i)

ee_i = (1 - pct_cured) * eet * p_i
pct_i = ee_i / eet * 100
pct_accr = Ni * 100 / N

bymonth[i, ] = c(i, round(ee_i,1), round(pct_i,1), Ni, round(pct_accr,1))
}

bymonth = as.data.frame(bymonth)
names(bymonth) = c("TimeinMonths", "TotalEvents", "PercentTotalEvents", "TotalAccrual", "PercentAccrual")
bymonth$PercentTotalEvents = paste0(bymonth$PercentTotalEvents, "%")
bymonth$PercentAccrual = paste0(bymonth$PercentAccrual, "%")

result = list(hazard = signif(hazard, 2),
event_table = bymonth)
return(jsonlite::toJSON(result, pretty = TRUE))
}