Skip to main content

power-optimization-patterns

Direct and tradeoff-based optimization strategies for clinical trial design. Use when optimizing sample size, selecting design parameters, or performing sensitivity analysis.

Aller à l'installation

Informations de source

Dépôt
choxos/BiostatAgent
Dernière activité de la source
10 janvier 2026 à 18:48
Langue détectée de SKILL.md
anglais
Étoiles
11
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
power-optimization-patterns
description
Direct and tradeoff-based optimization strategies for clinical trial design. Use when optimizing sample size, selecting design parameters, or performing sensitivity analysis.
# Power Optimization Patterns ## When to Use This Skill - Optimizing sample size for target power - Selecting design parameters (randomization ratio, event count) - Trading off between competing objectives - Performing sensitivity analysis - Finding optimal regions across scenarios ## Clinical Trial Optimization Framework ### Problem Formulation **Components:** - Data Model D(θ): Parameterized by θ (treatment effects, rates, etc.) - Analysis Model A(λ): Parameterized by λ (sample size, events, etc.) - Criterion ψ(λ | θ): Power or other metric **Objective:** Find λ* that optimizes ψ(λ | θ) subject to constraints. ## Direct Optimization ### Sample Size Determination **Objective:** Find minimum n such that Power(n) ≥ target **Binary Search Algorithm:** ```r find_sample_size <- function(target_power, effect_size, alpha = 0.025, n_low = 50, n_high = 500, n_sims = 10000) { while (n_high - n_low > 5) { n_mid <- round((n_low + n_high) / 2) # Run CSE with n_mid data.model <- DataModel() + OutcomeDist(outcome.dist = "NormalDist") + SampleSize(n_mid) + Sample(id = "Control", outcome.par = parameters(mean = 0, sd = 1)) + Sample(id = "Treatment", outcome.par = parameters(mean = effect_size, sd = 1)) analysis.model <- AnalysisModel() + Test(id = "Primary", samples = samples("Control", "Treatment"), method = "TTest") evaluation.model <- EvaluationModel() + Criterion(id = "Power", method = "MarginalPower", tests = tests("Primary"), labels = "Power", par = parameters(alpha = alpha)) results <- CSE(data.model, analysis.model, evaluation.model, SimParameters(n.sims = n_sims, proc.load = "full", seed = 12345)) power <- results$simulation.results$Power if (power >= target_power) { n_high <- n_mid } else { n_low <- n_mid } } return(n_high) } ``` ### Event Count Optimization (TTE) ```r # Grid search over event counts event_grid <- seq(200, 400, by = 25) power_results <- numeric(length(event_grid)) for (i in seq_along(event_grid)) { results <- sim_fixed_n( n_sim = 10000, sample_size = 500, target_event = event_grid[i], enroll_rate = enroll_rate, fail_rate = fail_rate, timing_type = 2 ) power_results[i] <- mean(results$z < qnorm(0.025)) } # Find minimum events for 90% power min_events <- event_grid[min(which(power_results >= 0.90))] ``` ## Tradeoff-Based Optimization ### Additive Criterion **Formula:** ``` ψ_combined(λ) = w₁ × ψ₁(λ) + w₂ × ψ₂(λ) ``` **Example: Power vs Sample Size** ```r # Weights: 70% power importance, 30% sample size (negative for minimization) w1 <- 0.7 w2 <- -0.3 # Negative because we want to minimize sample size sample_sizes <- seq(60, 120, by = 10) combined_scores <- numeric(length(sample_sizes)) for (i in seq_along(sample_sizes)) { n <- sample_sizes[i] # Simulate power # ... CSE simulation ... power <- results$simulation.results$Power # Normalize sample size to [0,1] scale n_normalized <- (n - min(sample_sizes)) / (max(sample_sizes) - min(sample_sizes)) combined_scores[i] <- w1 * power + w2 * n_normalized } optimal_n <- sample_sizes[which.max(combined_scores)] ``` ### Constrained Optimization **Problem:** Maximize ψ₁(λ) subject to ψ₂(λ) ≥ c **Example: Maximize secondary power subject to primary power ≥ 90%** ```r # Grid search with constraint secondary_power <- numeric(length(weight_grid)) primary_power <- numeric(length(weight_grid)) for (i in seq_along(weight_grid)) { w <- weight_grid[i] # Configure multiplicity with weight w for primary # ... run CSE ... primary_power[i] <- results$simulation.results$Primary_Power secondary_power[i] <- results$simulation.results$Secondary_Power } # Find optimal weight satisfying constraint valid_idx <- which(primary_power >= 0.90) optimal_w <- weight_grid[valid_idx[which.max(secondary_power[valid_idx])]] ``` ## Sensitivity Analysis ### Qualitative Sensitivity (Pivoting) Evaluate optimal λ across multiple θ scenarios. ```r # Define scenarios scenarios <- list( conservative = parameters(mean = 0.3, sd = 1), expected = parameters(mean = 0.5, sd = 1), optimistic = parameters(mean = 0.7, sd = 1) ) optimal_n <- list() for (scenario_name in names(scenarios)) { effect <- scenarios[[scenario_name]] # Find optimal n for this scenario optimal_n[[scenario_name]] <- find_sample_size( target_power = 0.90, effect_size = effect$mean ) } # Report range cat("Sample size range:", min(unlist(optimal_n)), "-", max(unlist(optimal_n))) ``` ### Quantitative Sensitivity (Bootstrap) Perturb θ and evaluate robustness of optimal λ. ```r # Bootstrap perturbation of effect size n_bootstrap <- 1000 bootstrap_power <- numeric(n_bootstrap) optimal_n <- 100 # Fixed design choice for (b in 1:n_bootstrap) { # Perturb effect size (e.g., from prior distribution) effect_b <- rnorm(1, mean = 0.5, sd = 0.1) # Simulate power at optimal_n # ... CSE with effect_b ... bootstrap_power[b] <- results$simulation.results$Power } # Robustness metrics cat("Mean power:", mean(bootstrap_power), "\n") cat("Power 95% CI:", quantile(bootstrap_power, c(0.025, 0.975)), "\n") cat("P(power >= 80%):", mean(bootstrap_power >= 0.80), "\n") ``` ## Optimal Intervals and Regions ### Optimal Interval The η-optimal interval contains all λ values within η% of optimal power. ```r # Define optimal interval eta <- 0.95 # 95% of maximum power sample_sizes <- seq(50, 150, by = 5) power_curve <- numeric(length(sample_sizes)) for (i in seq_along(sample_sizes)) { # ... simulate power ... power_curve[i] <- power_at_n } max_power <- max(power_curve) threshold <- eta * max_power # Find interval boundaries optimal_interval <- sample_sizes[power_curve >= threshold] cat("95%-optimal interval: [", min(optimal_interval), ",", max(optimal_interval), "]") ``` ### Joint Optimal Region Intersection of optimal intervals across scenarios. ```r # Find joint optimal region intervals <- list() for (scenario in scenarios) { # Get optimal interval for this scenario intervals[[scenario]] <- find_optimal_interval(scenario, eta = 0.95) } # Joint region = intersection joint_region <- Reduce(intersect, intervals) cat("Joint optimal sample sizes:", joint_region) ``` ## Compound Criteria ### Minimum Power **Use:** Ensure robustness across scenarios ```r # Evaluate minimum power across scenarios evaluate_min_power <- function(n, scenarios) { powers <- numeric(length(scenarios)) for (i in seq_along(scenarios)) { # ... simulate power for scenario i ... powers[i] <- power_i } return(min(powers)) } # Optimize for minimum power min_powers <- sapply(sample_sizes, evaluate_min_power, scenarios = scenarios) optimal_n <- sample_sizes[which.max(min_powers)] ``` ### Average Power **Use:** Balance across scenarios ```r evaluate_avg_power <- function(n, scenarios, weights = NULL) { if (is.null(weights)) weights <- rep(1/length(scenarios), length(scenarios)) powers <- numeric(length(scenarios)) for (i in seq_along(scenarios)) { powers[i] <- simulate_power(n, scenarios[[i]]) } return(sum(weights * powers)) } ``` ## Multiplicity Optimization ### Gamma Parameter Optimization ```r gamma_grid <- seq(0.5, 1.0, by = 0.05) results_list <- list() for (i in seq_along(gamma_grid)) { g <- gamma_grid[i] analysis.model <- AnalysisModel() + # Tests ... MultAdjProc( proc = "ParallelGatekeepingAdj", par = parameters( family = families(family1 = c(1, 2), family2 = c(3, 4)), proc = families(family1 = "HolmAdj", family2 = "HolmAdj"), gamma = families(family1 = g, family2 = 1) ) ) results_list[[i]] <- CSE(data.model, analysis.model, evaluation.model, SimParameters(n.sims = 10000, proc.load = "full", seed = i)) } # Extract powers and find optimal gamma # ... (subject to FWER constraint) ``` ### Weight Allocation Optimization ```r # Optimize weights in chain procedure weight_grid <- expand.grid( w1 = seq(0.3, 0.7, by = 0.1), w2 = seq(0.3, 0.7, by = 0.1) ) |> subset(w1 + w2 == 1) # Evaluate each weight combination # ... and select optimal weights ``` ## Best Practices 1. **Define Clear Objective**: Power, sample size, cost, or combination 2. **Consider All Scenarios**: Use qualitative sensitivity for range 3. **Validate Constraints**: Check FWER, minimum power thresholds 4. **Document Trade-offs**: Explain rationale for chosen parameters 5. **Report Robustness**: Show performance across scenarios 6. **Pre-specify Optimization**: Define optimization strategy in SAP
Voir sur GitHub