This vignette contains two kinds of output, and it is important to distinguish them.
A quick toy example, executed when this vignette
is built. It uses n_sim = 10, n_boot = 10 and
a coarse tau_grid so that the vignette builds in seconds.
It illustrates the workflow and function usage only. Its
numerical results are based on far too few simulated trials and
bootstrap resamples to be stable, and should not be interpreted
as simulation or inferential results.
Precomputed full-setting results, using 100 simulated trials and 100 bootstrap resamples per trial. The complete code producing each result is shown but not evaluated at build time; the stored output is displayed instead. All substantive statements in the text below refer to these results.
Every precomputed result is reproducible after a single
set.seed() call with seed 202608. Precomputed blocks are
marked Precomputed; the toy block is marked Toy
example.
Toy example.
n_sim = 10,n_boot = 10, coarsetau_grid. These settings exist so the vignette builds quickly. The feasibility classifications and selected truncation time produced here are unstable and are not the results discussed in the rest of this vignette.
set.seed(202608)
toy_result <- twostage_tau(
N = 60, A = 24, F_followup = 6,
tau_clin = 24,
tau_grid = seq(6, 24, by = 6),
effect_model = list(type = "ph", lambda0 = -log(0.5) / 24, HR = 0.5),
delta = 12, epsilon = 0.05,
n_sim = 10, n_boot = 10)
toy_result
#> Two-Stage Truncation-Time Selection
#> -----------------------------------
#> Stage 1 (tau_clin = 24): Fail
#> Final selection: tau* = 12
#>
#> Selected tau* = 12, replacing the clinically proposed tau_clin =
#> 24. tau_clin did not meet the feasibility criteria (Stage 1 status:
#> Fail), so the best feasible candidate within the clinical window
#> was selected.For real design work, use the package defaults
(n_sim = 100, n_boot = 100) or larger, with a
finer tau_grid. Everything below uses those settings.
We use a single running example: a two-arm trial with 60 participants, 24 months of accrual, and 6 additional months of follow-up, under a proportional-hazards effect with a hazard ratio of 0.5.
The clinical team has proposed a truncation time of 24 months.
set.seed(202608)
assess_tau(
N = 60, A = 24, F_followup = 6,
tau = 24,
effect_model = effect_model,
n_sim = 100, n_boot = 100)#> Truncation-Time Feasibility Assessment
#> --------------------------------------
#> Proposed truncation time: tau = 24
#> Feasibility status: Fail
#>
#> metric value pass_threshold
#> Expected total risk-set size at tau 8.9 30
#> Expected control-arm risk-set size at tau 3.8 10
#> Expected treatment-arm risk-set size at tau 5.1 10
#> Risk-set proportion at tau 0.1477 0.1
#> Estimability probability 0.9700 0.9
#> Feasibility Fail
#> fail_threshold
#> 20
#> 5
#> 5
#> 0.1
#> 0.8
#>
Precomputed (100 simulations, 100 bootstrap resamples).
This output can be summarized as follows:
\(\quad\) For a trial with (N = 60), a 24-month accrual period, and only 6 months of additional follow-up, the statistic at 24 months could be successfully computed in all simulation runs. However, only approximately nine patients in total were expected to remain in the risk set at that time point, with about four to five patients in each treatment arm. This provides severely insufficient statistical support. Therefore, the clinically specified truncation time, (\(\tau_{clin} = 24\)) months, was deemed infeasible. Importantly, this failure was driven primarily by the limited follow-up design, rather than by an inadequate treatment effect or a failure of the computational procedure.
There are three main ways to improve the feasibility of using \(\tau = 24\) months.
The most direct solution is to increase the additional follow-up period. For example, if \[F = 6 \] is increased to approximately \[F = 24 ,\] then even the last enrolled patient would have the opportunity to complete 24 months of follow-up.
\(\quad\) Under this design, nearly all patients could potentially contribute to the risk set at 24 months. The expected total risk-set size would therefore increase substantially, from approximately 9 patients to approximately 36 patients: \[30 \times 0.5 + 30 \times 0.707 \approx 36.2.\]
\(\quad\) Thus, extending the additional follow-up period is the most direct and efficient way to make (\(\tau = 24\)) months feasible.
set.seed(202608)
assess_tau(N = 60, A = 24, F_followup = 24, tau = 24,
effect_model = effect_model,
n_sim = 100, n_boot = 100)#> Truncation-Time Feasibility Assessment
#> --------------------------------------
#> Proposed truncation time: tau = 24
#> Feasibility status: Pass
#>
#> metric value pass_threshold
#> Expected total risk-set size at tau 36.3 30
#> Expected control-arm risk-set size at tau 15.2 10
#> Expected treatment-arm risk-set size at tau 21.1 10
#> Risk-set proportion at tau 0.6043 0.1
#> Estimability probability 1.0000 0.9
#> Feasibility Pass
#> fail_threshold
#> 20
#> 5
#> 5
#> 0.1
#> 0.8
#>
Precomputed (100 simulations, 100 bootstrap resamples).
Another solution is to use an earlier truncation time.
Under the current design:
At (\(\tau = 12\)) months,
approximately 75% of patients have the opportunity to reach the
specified follow-up time.
At (\(\tau = 18\)) months, approximately 50% of patients have the opportunity to reach the specified follow-up time.
At (\(\tau = 24\)) months, approximately 25% of patients have the opportunity to reach the specified follow-up time.
Therefore, optimize_tau() would likely identify a feasible or optimal truncation time substantially earlier than 24 months, possibly some where within the range of 12 to 18 months.
set.seed(202608)
assess_tau(N = 60, A = 24, F_followup = 6, tau = 12,
effect_model = effect_model,
n_sim = 100, n_boot = 100)#> Truncation-Time Feasibility Assessment
#> --------------------------------------
#> Proposed truncation time: tau = 12
#> Feasibility status: Pass
#>
#> metric value pass_threshold
#> Expected total risk-set size at tau 34.7 30
#> Expected control-arm risk-set size at tau 15.8 10
#> Expected treatment-arm risk-set size at tau 19.0 10
#> Risk-set proportion at tau 0.5785 0.1
#> Estimability probability 1.0000 0.9
#> Feasibility Pass
#> fail_threshold
#> 20
#> 5
#> 5
#> 0.1
#> 0.8
#>
Precomputed (100 simulations, 100 bootstrap resamples).
This approach improves statistical support at the cost of evaluating treatment effects over a shorter time horizon.
Increasing the sample size also increases the number of patients remaining in the risk set at 24 months.
\(\quad\) Under the current design, the expected proportion of patients remaining in the risk set at 24 months is only approximately \[0.15.\]
\(\quad\) Therefore, to obtain an expected risk-set of approximately 30 patients, the required total sample size would be roughly \[N \approx \frac{30}{0.15} \approx 200.\]
set.seed(202608)
assess_tau(N = 200, A = 24, F_followup = 6, tau = 24,
effect_model = effect_model,
n_sim = 100, n_boot = 100)#> Truncation-Time Feasibility Assessment
#> --------------------------------------
#> Proposed truncation time: tau = 24
#> Feasibility status: Borderline
#>
#> metric value pass_threshold
#> Expected total risk-set size at tau 29.9 30
#> Expected control-arm risk-set size at tau 12.4 10
#> Expected treatment-arm risk-set size at tau 17.4 10
#> Risk-set proportion at tau 0.1492 0.1
#> Estimability probability 1.0000 0.9
#> Feasibility Borderline
#> fail_threshold
#> 20
#> 5
#> 5
#> 0.1
#> 0.8
#>
Precomputed (100 simulations, 100 bootstrap resamples).
\(\quad\) The rough calculation suggests that approximately (\(N = 200\)) patients would be needed to obtain an expected risk-set size near 30 at (\(\tau = 24\)) months. In the Monte Carlo assessment, (\(N = 200\)) produced an expected total risk-set size of 29.9 and was classified as Borderline. This near-threshold result illustrates that increasing sample size can improve support, but sample-size increase alone may be inefficient when the fundamental limitation is that few patients have sufficient follow-up to contribute information at the 24-month truncation time.
The built-in rules can be inspected directly:
default_fail_thresholds()
#> $total_risk
#> [1] 20
#>
#> $arm_risk
#> [1] 5
#>
#> $riskset_prop
#> [1] 0.1
#>
#> $estimability
#> [1] 0.8A user running an exploratory pilot may accept weaker support, and can override any subset of them:
set.seed(202608)
assess_tau(N = 60, A = 24, F_followup = 6, tau = 24,
effect_model = effect_model,
fail_thresholds = list(total_risk = 5, arm_risk = 2),
n_sim = 100, n_boot = 100)#> Truncation-Time Feasibility Assessment
#> --------------------------------------
#> Proposed truncation time: tau = 24
#> Feasibility status: Borderline
#>
#> metric value pass_threshold
#> Expected total risk-set size at tau 8.9 30
#> Expected control-arm risk-set size at tau 3.8 10
#> Expected treatment-arm risk-set size at tau 5.1 10
#> Risk-set proportion at tau 0.1477 0.1
#> Estimability probability 0.9700 0.9
#> Feasibility Borderline
#> fail_threshold
#> 5
#> 2
#> 2
#> 0.1
#> 0.8
#>
Precomputed (100 simulations, 100 bootstrap resamples).
Unspecified elements keep their defaults. Relaxing a rule changes only the classification, not the underlying statistical support.
set.seed(202608)
optimize_tau(
N = 60, A = 24, F_followup = 6,
tau_clin = 24,
tau_grid = seq(6, 36, by = 3),
effect_model = effect_model,
delta = 12, epsilon = 0.05,
n_sim = 100, n_boot = 100)#> Feasibility-Constrained Truncation-Time Optimization
#> ----------------------------------------------------
#> Stage 1 (tau_clin = 24): Fail
#> Number of admissible candidates: 1
#> Admissible candidate values: 12
#> Final selection: tau* = 12
#>
#> Selected tau* = 12, replacing the clinically proposed tau_clin =
#> 24. tau_clin did not meet the feasibility criteria (Stage 1 status:
#> Fail), so the best feasible candidate within the clinical window
#> was selected.
#>
#> Use $candidate_summary for the full tau-by-tau table.
Precomputed (100 simulations, 100 bootstrap resamples).
\(\quad\) The clinically proposed truncation time of 24 months failed the prespecified feasibility criteria because of inadequate risk-set support. Among the candidate truncation times satisfying both the feasibility requirements and the prespecified 12-month clinical-distance constraint, 12 months was the only admissible candidate and was therefore selected as the final truncation time.
set.seed(202608)
result <- twostage_tau(
N = 60, A = 24, F_followup = 6,
tau_clin = 24,
tau_grid = seq(6, 36, by = 3),
effect_model = effect_model,
delta = 12, epsilon = 0.05,
n_sim = 100, n_boot = 100)
summary(result)#> Two-Stage Truncation-Time Selection
#> -----------------------------------
#> Stage 1 (tau_clin = 24): Fail
#> Final selection: tau* = 12
#>
#> Selected tau* = 12, replacing the clinically proposed tau_clin =
#> 24. tau_clin did not meet the feasibility criteria (Stage 1 status:
#> Fail), so the best feasible candidate within the clinical window
#> was selected.
#>
#> Candidate-level selection table:
#> tau E_Y_total E_Y_ctr E_Y_trt p_riskset p_estimable mean_log_AH_ratio
#> 6 52.8 25.2 27.6 0.8797 0.95 -0.71
#> 9 43.4 20.1 23.2 0.7232 0.99 -0.86
#> 12 34.7 15.8 19.0 0.5787 1.00 -0.87
#> 15 27.7 12.3 15.4 0.4613 1.00 -0.85
#> 18 20.7 8.9 11.8 0.3445 1.00 -0.85
#> 21 15.0 6.3 8.7 0.2503 1.00 -0.82
#> 24 9.4 4.0 5.5 0.1573 0.98 -0.78
#> 27 4.5 1.9 2.6 0.0748 0.73 -0.78
#> 30 0.0 0.0 0.0 0.0000 0.00 NA
#> 33 0.0 0.0 0.0 0.0000 0.00 NA
#> 36 0.0 0.0 0.0 0.0000 0.00 NA
#> empirical_SD mean_boot_SE power_overall feasibility dist_to_clin within_window
#> 0.83 0.74 0.07 Pass 18 FALSE
#> 0.74 0.70 0.25 Pass 15 FALSE
#> 0.62 0.65 0.26 Pass 12 TRUE
#> 0.63 0.62 0.30 Borderline 9 TRUE
#> 0.61 0.61 0.40 Borderline 6 TRUE
#> 0.61 0.61 0.37 Fail 3 TRUE
#> 0.57 0.59 0.24 Fail 0 TRUE
#> 0.65 0.61 0.09 Fail 3 TRUE
#> NA NA 0.00 Fail 6 TRUE
#> NA NA 0.00 Fail 9 TRUE
#> NA NA 0.00 Fail 12 TRUE
#> utility admissible selected
#> 0.85 FALSE FALSE
#> 1.16 FALSE FALSE
#> 1.41 TRUE TRUE
#> 1.36 FALSE FALSE
#> 1.39 FALSE FALSE
#> 1.36 FALSE FALSE
#> 1.38 FALSE FALSE
#> 1.21 FALSE FALSE
#> NA FALSE FALSE
#> NA FALSE FALSE
#> NA FALSE FALSE
#>
#> Final decision summary:
#> quantity result
#> Clinical time (tau_clin) 24
#> Stage 1 status of clinical time Fail
#> Clinical-distance tolerance (delta) 12
#> Pass candidate set 6, 9, 12
#> Number of admissible candidates 1
#> Admissible candidate values 12
#> Preliminary optimal candidate (tau_tilde) 12
#> Retention tolerance (epsilon) 0.05
#> Clinical time retained Not applicable
#> Final selected time (tau*) 12
#> Decision type Constraint-driven
#> Absolute power gain NA
#> Relative utility improvement NA
#>
#> Independent evaluation table:
#> tau_role tau E_Y_total E_Y_ctr E_Y_trt p_riskset p_estimable mean_log_AH_ratio
#> tau_star 12 35.2 16.2 19.0 0.5863 0.99 -0.73
#> tau_clin 24 8.9 3.8 5.1 0.1485 0.98 -0.80
#> empirical_SD mean_boot_SE utility power_overall feasibility
#> 0.71 0.65 1.03 0.24 Pass
#> 0.60 0.60 1.34 0.24 Fail
Precomputed (100 simulations, 100 bootstrap resamples).
\(\quad\) Under the planned design with 60 participants, 24 months of accrual, and 6 additional months of follow-up, the clinically proposed truncation time of 24 months failed the Stage 1 feasibility assessment because of inadequate risk-set support. The truncation times of 6, 9, and 12 months passed the feasibility criteria, but only 12 months fell within the prespecified clinical-distance tolerance of 12 months from the proposed clinical time. Thus, 12 months was the only admissible candidate and was selected as the final truncation time. An independent evaluation confirmed that the selected 12-month time remained feasible, whereas the original 24-month clinical time remained infeasible.
\(\quad\) \(\tau^{\star}\) is chosen as the best of many candidates, so its performance in the selection table is subject to the winner’s curse. The independent evaluation therefore re-simulates fresh trials and evaluates only the clinical time and the already-fixed \(\tau^{\star}\), which gives unbiased estimates for the design that was selected.