Bayes Fast

Author

Sarah Urbut

Published

October 30, 2024

Bayes Fast

This document presents a Bayesian analysis of a clinical trial comparing fasting and no fasting in patients undergoing surgery. The analysis focuses on the event rates of complications in both groups and evaluates the statistical significance and clinical relevance of the findings.

We’re using a Bayesian model to estimate the true event rates in each group For each group, we’re modeling the number of events as a binomial distribution We use Beta(1.5, 1.5) as a weakly informative prior for both groups

Generated Quantities:

We calculate two key measures:

The absolute difference between groups (p_nofasting - p_fasting) The relative risk (p_nofasting / p_fasting)

Post-Processing:

We extract the posterior distributions Calculate key statistics:

95% credible intervals for the difference Probability that no-fasting is superior (p(diff < 0)) Relative risk with credible intervals

Code
# Load required libraries
library(rstan)
library(bayesplot)
library(tidyverse)

# Data from the study
n_fasting <- 356  # Sample size for fasting group
n_nofasting <- 356 # Sample size for no fasting group
y_fasting <- 68    # Events in fasting group
y_nofasting <- 43  # Events in no fasting group

# Stan model code for Bayesian analysis
stan_code <- "
data {
  int<lower=0> n_fasting;
  int<lower=0> n_nofasting;
  int<lower=0> y_fasting;
  int<lower=0> y_nofasting;
}
parameters {
  real<lower=0,upper=1> p_fasting;
  real<lower=0,upper=1> p_nofasting;
}
model {
  // Weakly informative priors
  p_fasting ~ beta(1.5, 1.5);
  p_nofasting ~ beta(1.5, 1.5);
  
  // Likelihood
  y_fasting ~ binomial(n_fasting, p_fasting);
  y_nofasting ~ binomial(n_nofasting, p_nofasting);
}
generated quantities {
  real diff = p_nofasting - p_fasting;
  real rel_risk = p_nofasting / p_fasting;
}
"

# Prepare data for Stan
stan_data <- list(
  n_fasting = n_fasting,
  n_nofasting = n_nofasting,
  y_fasting = y_fasting,
  y_nofasting = y_nofasting
)

# Compile and run the model
#fit <- stan(model_code = stan_code, data = stan_data, 
 #          chains = 4, iter = 4000, seed = 123)

fit=readRDS("~/Dropbox (Personal)/bayesfast.rds")
# Extract posterior samples
posterior <- as.data.frame(fit)

# Calculate key statistics
diff_quantiles <- quantile(posterior$diff, c(0.025, 0.5, 0.975))
p_superior <- mean(posterior$diff < 0)
rel_risk_quantiles <- quantile(posterior$rel_risk, c(0.025, 0.5, 0.975))

# Check for issues in the trial design
power_analysis <- function(n1, n2, p1, p2, reps = 1000) {
  results <- replicate(reps, {
    y1 <- rbinom(1, n1, p1)
    y2 <- rbinom(1, n2, p2)
    test <- prop.test(c(y1, y2), c(n1, n2))
    test$p.value < 0.05
  })
  mean(results)
}

# Estimate power for small clinical differences
est_power <- power_analysis(356, 356, 0.19, 0.17)

# Print results
cat("Posterior difference (no fasting - fasting):\n")
Posterior difference (no fasting - fasting):
Code
print(diff_quantiles)
       2.5%         50%       97.5% 
-0.12222258 -0.06941386 -0.01675554 
Code
cat("\nProbability of superiority:", p_superior)

Probability of superiority: 0.99375
Code
cat("\nRelative Risk (95% CI):", rel_risk_quantiles)

Relative Risk (95% CI): 0.4523262 0.6414205 0.8972121
Code
cat("\nEstimated power for 2% difference:", est_power)

Estimated power for 2% difference: 0.085
Code
# Plot posterior distributions
ggplot(posterior, aes(x = diff)) +
  geom_density(fill = "blue", alpha = 0.3) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  labs(title = "Posterior Distribution of Treatment Effect",
       x = "Difference in Proportions (No Fasting - Fasting)",
       y = "Density")

Key Points About This Analysis:

Direct Parameter Estimation:

Instead of just testing non-inferiority, we’re estimating the actual difference between groups This gives us more information about the magnitude of any effect

Power Considerations:

We’re checking if the study was powered appropriately for the observed effect sizes The much higher-than-expected event rate affects the interpretation

Visualization:

The code includes a plot of the posterior distribution of the treatment effect which helps visualize the uncertainty in the estimates. The analysis suggests that while the study’s main safety conclusion (regarding aspiration) is likely valid, there are some methodological considerations worth noting, particularly around:

  • The choice of composite endpoint
  • The much higher than expected event rate
  • The clinical significance of the observed differences

Based on this Bayesian analysis, there are several points worth considering about the study:

Non-informative Prior Choice: The study used informative Beta priors, which could potentially bias results. Our analysis used weakly informative priors to be more conservative.

Event Rate Discrepancy: The observed event rate (19.1% vs 12.0%) was much higher than what was used for the sample size calculation (5.9% vs 5.1%). This suggests the initial assumptions for power calculations may have been flawed.

Multiple Components: The primary endpoint is a composite of four different outcomes (aspiration pneumonia, hypotension, hyperglycemia, hypoglycemia) with very different clinical significance. The fact that aspiration (the main safety concern) had zero events in both groups suggests the composite endpoint may not be clinically meaningful.

Potential Bias Sources:

The trial was unblinded, which could affect treatment decisions The higher-than-expected event rate suggests possible detection bias The definition of hypotension (any SBP < 90 or requiring intervention) may be too sensitive

Power and Clinical Significance: While the study shows statistical superiority, the clinical significance of the difference (mainly driven by hypotension and hyperglycemia) is debatable.