My problem: I have a fixed, imbalanced, case-control cohort where I am using two (2) low occurrence predictors (rare variants) to try to find an association between the predictors and disease. I will be doing this on a gene-by-gene basis, but want to figure out the minimum amount of the predictor counts I should see to have a well-powered test and reduce the total amount of tests, as a large portion of the genes will have very low predictor counts. I am using R for this analysis.
- The data is:
- Sample ID: ~2963 cases and ~5015 controls
- Binary outcome: disease, no disease
- Per sample number of rare mutations of type 1 from whole exome sequencing data: technically binomial - any value 0 to infinity ; practically a binomial from 0-2 - one homozygous or one heterozygous variant - and heavily 0 weighted with frequency <=1%)
- Per sample number of rare mutations of type 2 from whole exome sequencing data: with the same characteristics and distribution as mutations of type 1
- Covariates: 4 principal components that are related to ancestry and sex
- My predictors are the type 1 and type 2 mutations and my response is disease (hypothesis is that type 1 or type 2 mutations cause disease under a dominant model - whereby a single mutation (heterozygote) leads to disease)
- I am using a generalized linear model to see if the effect of type 1 mutations + type 2 mutations > 0 (H0 - beta_1 + beta_2 = 0 ; H1 - beta_1 + beta_2 > 0) at a significance level of 0.01 lets say. HOWEVER, we can start with a test statistic based on a single parameter (H0 - beta_1 = 0 ; H1 - beta_1 > 0).
Here is a example of data I expect to see:
df <- data.frame(id = 1:8001, disease = 0, type1 = 0, type2 = 0, PC1 = seq(-0.009,0.035, by= 0.0000055), sex =0)
df$disease[sample(nrow(df), 3000)] <- 1
df$type1[sample(nrow(df), 30)] <- 1
df$type2[sample(nrow(df), 60)] <- 1
df$sex[sample(nrow(df), 3511)] <- 1
I set up the glz like this:
test.model.null <- glm(disease ~ PC1 + sex, family = binomial(link = "logit"), data = df)
test.model.full <- glm(disease ~ type1 + type2 + PC1 + sex, family = binomial(link = "logit"), data = df)
Question:
- How can I set up simulations to test for how effect size affects power in these models - translating this to the minimum amount of type1 mutations and/or type2 mutations for a well powered test?
I know I can randomize my covariates and then create the model again over and over, but I do not know how to evaluate false positives (for type 1 error I would do simulations with the null model, but how do I know if I have a false positive?) and false negatives (simulations with my full model?).
My simulations development for based on a simplified model with only a single parameter:
Here is my attempt at simulations with an outcome (0 for controls - Y0
, 1 for cases - Y1
) and just a single predictor ($predictor
), where power is tested at a specific predictor occurrence rate (indicated in the prob
variable in the binomial()
command), based on this link I found in another thread in CrossValidated:
alpha <- 0.05 # Standard significance level
sims <- 500 # Number of simulations to conduct for each N
significant.experiments <- rep(NA, sims) # Empty object to count significant experiments
#### Loop to conduct experiments "sims" times ####
for (i in 1:sims){
Y0 <- data.frame(outcome = rep(0, 5015), predictor = rbinom(5015, size=2, prob=2/5015)) # 5015 controls get the predictor (0,1, or 2) pulled from binomial distribution at a particular rate
tau <- 1 # Hypothesize treatment effect - gets disease
Y1 <- data.frame(outcome =rep(tau, 2963), predictor = rbinom(2963, size=2, prob=11/2963)) # 2963 cases get the predictor (0,1, or 2) pulled from binomial distribution at a particular rate
Y.sim <- rbind(Y0, Y1)
fit.sim <- glm(Y.sim$outcome ~ Y.sim$predictor, family = binomial(link = "logit")) # Do analysis (Simple regression)
p.value <- summary(fit.sim)$coefficients[2,4] # Extract p-values
significant.experiments[i] <- (p.value <= alpha) # Determine significance according to p <= 0.05
}
power <- mean(significant.experiments) # store average success rate (power)
power
Next, I adjusted my code to test for power across a fixed probability of the predictor in cases (prob.sim.Y0
), compared to a set of probabilities of that same predictor in controls (prob.sim.Y1
):
# Set the probability of having an allele for cases and controls based on an hypothetical # of alleles
prob.sim.Y0 = 1/5015 # we will fix the probability of an allele in cases
prob.sim.Y1 = seq(from = 2/2963, to = 7/2963, by = 1/2963) #and we will vary the probability in cases
#Set up power object and other parameters
powers <- rep(NA, length(prob.sim.Y1)) # Empty object to collect simulation estimates
alpha <- 0.05 # Standard significance level
sims <- 500 # Number of simulations to conduct for each N
for (j in 1:length(prob.sim.Y1)){ #loop over the number of predictor frequencies
significant.experiments <- rep(NA, sims) # Empty object to count significant experiments
#### Loop to conduct experiments "sims" times ####
for (i in 1:sims){
#Ensure there is at least 1 predictor becuase if there are 0 predictors in
#both cases and controls, the glm does not return a beta coefficent
Y.sim <- data.frame(outcome = 0, predictor = 0)
while(sum(Y.sim$predictor) == 0) {
Y0 <- data.frame(outcome = rep(0, 5015), predictor = rbinom(5015, size=2, prob= prob.sim.Y0)) # 5015 controls get the predictor (0, 1, or 2) pulled from binomial distribution at a particular rate
tau <- 1 # Outcome: Disease status
Y1 <- data.frame(outcome = rep(tau, 2963), predictor = rbinom(2963, size=2, prob= prob.sim.Y1[j])) # 2963 cases get the predictor (0,1, or 2) pulled from binomial distribution at a particular rate
Y.sim <- rbind(Y0, Y1) #creating the joint object
}
fit.sim <- glm(Y.sim$outcome ~ Y.sim$predictor, family = binomial(link = "logit")) # Do analysis (Simple regression)
p.value <- summary(fit.sim)$coefficients[2,4] # Extract p-values
significant.experiments[i] <- (p.value <= alpha) # Determine significance according to p <= 0.05, storing TRUE or FALSE according to whether or not the value was <= 0.05
}
powers[j] <- mean(significant.experiments) # store average success rate (power) at each frequency tested by taking the mean() of a T,F vector - which calculates the frequency of TRUE
}
powers
plot(prob.sim.Y1, powers, ylim=c(0,1))