R/significance.r

Defines functions integrand.power.exact twostage.power.exact integrand.prime integrand get.alpha2 get.beta1 getestimates find.maximum.power

# R code to estimate two-stage design parameters
#
# revised: march 5, 2003
#
# jaya m. satagopan (satagopj@mskcc.org)
#
# reference: Satagopan JM, Elston RC (2003): Optimal two-stage genotyping in population-based
#                 association studies. Genetic Epidemiology 25: 149-157.
#
#
# how to use these functions:
#
# First read this file in R using the "source" command.
# For example, if you name this file as "twostage.s", then
# in R, use the command - source("twostage.s"). Remember
# to give the appropriate path. You may want to say -
# source("c:/twostagecode/twostage.s") - if you have saved
# this file under the directory c:\twostagecode. 
#
# The main function is "find.maximum.power". Run this 
# function to get the required results. 
#
# Example to run this function:
# Suppose we have m=25, D=1, alpha (overall significance level)=0.05, power (of onestage method)=0.80, 
# cost fraction=0.75, and alpha1 (significance level at Stage 1) = 0.20. Then, use the following command:
# 
#       find.maximum.power(m=25, Dvalue=1, alpha=0.05, power=0.80, cost.frac=0.75, alpha1=0.20)
#
# Note: The code given here does not perform the grid search to find the optimum power and optimum
# cost. This must be coded by the user. It can be done easily by using the function find.maximum.power
# iteratively. In fact, if you give a vector of values for alpha1, the function find.maximum.power will output
# the values of alpha1, beta1, and alpha2 at which the maximum power occurs (and the value of the
# maximum power), for a given cost. So, the iteration is only required to iterate over various values of
# cost.frac. 
#
# Should you have any questions regarding these functions, please contact 
# Jaya M. Satagopan at 646-735-8122 or satagopj@mskcc.org
#

###############################
# main function to generate the required results
###############################
find.maximum.power <- function(m=100, Dvalue=1, alpha=0.05, power=0.80, cost.frac=0.25, alpha1 =0.25){
  vec.len <- length(alpha1)
  beta1 <- rep(0,vec.len)
  alpha2 <- rep(0,vec.len)
  power.twostage <- rep(0, vec.len)
  power.twostage.exact <- rep(0, vec.len)
  for(i in 1:vec.len){
    temp <- getestimates(m=m, Dvalue=Dvalue, alpha=alpha, power=power, cost.frac=cost.frac, alpha1.start=alpha1[i])
    beta1[i] <- temp$beta1
    alpha2[i] <- temp$alpha2
    power.twostage[i] <- temp$power.twostage
  }
  max.loc <- (1:vec.len)[power.twostage >= max(power.twostage)]
    return(list(m=m, D=Dvalue, alpha=alpha, power=power, cost.frac=cost.frac,
                 opt.alpha1=alpha1[max.loc], opt.pow1=1-beta1[max.loc], opt.alpha2=alpha2[max.loc], opt.power=power.twostage[max.loc]))
}


####################################
# function to calculate the estimates
####################################
getestimates <- function(m=100, Dvalue=1, alpha=0.05, power=0.80, cost.frac=0.55, 
                                        alpha1.start=0.10, beta1.start=0.000001, alpha2.start=0.00000001){

    alpha1 <- alpha1.start

    beta1 <- get.beta1(m=m, Dvalue=Dvalue, alpha=alpha, power=power, alpha1=alpha1.start, 
                                   cost.frac=cost.frac,beta1.start=beta1.start)
    alpha2 <- get.alpha2(m=m, alpha=alpha, power=power, 
                                      alpha1=alpha1, beta1=beta1, alpha2.start=alpha2.start)

    twostage.power.exact <- twostage.power.exact(m=m, alpha=alpha, power=power, alpha1=alpha1, beta1=beta1, alpha2=alpha2)

    return( list(m=m, alpha=alpha, power=power,
                 cost.frac=cost.frac, Dvalue=Dvalue, 
                 alpha1=alpha1, beta1=beta1,
                 power1=1-beta1, alpha2=alpha2,
                 power.twostage=twostage.power.exact))

}

############################################
# estimate beta1 using newton raphson method
############################################
get.beta1 <- function(m=100, Dvalue=1, alpha=0.05, power=0.80, alpha1=0.001, 
                                   cost.frac=0.8, beta1.start=0.000001, threshold=0.000001){
  epsilon <- 1
  iteration <- 0
  beta1.start <- beta1.start
  while(epsilon > threshold){
      f.beta1 <- ( m*(qnorm(1-alpha1)+qnorm(1-beta1.start))^2 + 
                     ( (m-Dvalue)*alpha1 + Dvalue*(1-beta1.start) ) * 
                       ( (qnorm(1-alpha/m)+qnorm(power))^2 - (qnorm(1-alpha1)+qnorm(1-beta1.start))^2 ) ) /
                     ( m * (qnorm(1-alpha/m)+qnorm(power))^2 ) - cost.frac
      f.prime.beta1 <- 2*(qnorm(1-alpha1)+qnorm(1-beta1.start))/dnorm(qnorm(1-beta1.start)) * 
                              ( (m-Dvalue)*alpha1 + Dvalue*(1-beta1.start) - m) -
                              Dvalue*( (qnorm(1-alpha/m)+qnorm(power))^2 - (qnorm(1-alpha1)+qnorm(1-beta1.start))^2 )
      f.prime.beta1 <- f.prime.beta1 / ( m * (qnorm(1-alpha/m)+qnorm(power))^2 ) 
      beta1.new <- beta1.start - f.beta1/f.prime.beta1
      if(beta1.new < 0){
        print("negative beta1 estimate. convergence problem!! change the starting value of beta1")
        break
      }
      iteration <- iteration + 1
      if(iteration > 20){
        print("convergence problem! change the starting value of beta1")
        break
      }
      epsilon <- abs(beta1.new - beta1.start)
      beta1.start <- beta1.new
  }
  return(beta1.new)
}

#############################################
# estimate alpha2 using newton raphson method
#############################################
get.alpha2 <- function(m=100, alpha=0.05, power=0.80, 
                                    alpha1=0.001, beta1=0.03, alpha2.start=0.000000001, threshold=0.000001){
  epsilon <- 1
  iteration <- 1
  alpha2.start <- alpha2.start

  while(epsilon > threshold){
    f.alpha2 <- integrate(integrand, lower=qnorm(1-alpha1), upper=10, m=m, alpha=alpha, power=power, alpha1=alpha1, beta1=beta1, alpha2=alpha2.start)$value - alpha/m
    f.prime.alpha2 <- integrate(integrand.prime, lower=qnorm(1-alpha1), upper=10, m=m, alpha=alpha, power=power, alpha1=alpha1, beta1=beta1, 
                                           alpha2=alpha2.start)$value
    alpha2.new <- alpha2.start - f.alpha2/f.prime.alpha2
    epsilon <- abs(alpha2.new - alpha2.start)
    alpha2.start <- alpha2.new
  }
  return(alpha2.new)
}

#######################################
# integrand for calculating alpha2
#######################################
integrand <- function(z.value, m, alpha, power, alpha1, beta1, alpha2){
  temp1 <- qnorm(1-alpha/m) + qnorm(power)
  temp2 <- qnorm(1-alpha1) + qnorm(1-beta1)
  numerator <- qnorm(1-alpha2) * temp1 -z.value*temp2
  denominator <- sqrt( temp1^2 - temp2^2 )
  (1 - pnorm(numerator/denominator) ) *dnorm(z.value)
}

#########################################################
# integrand for the derivative of alpha/m with respect to alpha2
#########################################################
integrand.prime <- function(z.value, m, alpha, power, alpha1, beta1, alpha2){
  temp1 <- qnorm(1-alpha/m) + qnorm(power)
  temp2 <- qnorm(1-alpha1) + qnorm(1-beta1)
  numerator <- qnorm(1-alpha2) * temp1 - z.value * temp2
  denominator <- sqrt(temp1^2-temp2^2)
  1/dnorm(qnorm(1-alpha2)) * temp1/sqrt(temp1^2-temp2^2) * dnorm(numerator/denominator) * dnorm(z.value)
}

##################################
# power P of the two-stage design
##################################
twostage.power.exact <- function(m=100, alpha=0.05, power=0.80, alpha1=0.10, beta1=0.05, alpha2=0.0005){
  power.value.exact <- integrate(integrand.power.exact, lower=qnorm(1-alpha1), upper=10, m=m, alpha=alpha, power=power, alpha1=alpha1, beta1=beta1, alpha2=alpha2)$value
  return(power.value.exact)
}

##################################
# integrand of the power P (see above function twostage.power.exact)
##################################
integrand.power.exact <- function(z.value, m, alpha, power, alpha1, beta1, alpha2){
  temp1 <- qnorm(1-alpha/m) + qnorm(power)
  temp2 <- qnorm(1-alpha1) + qnorm(1-beta1)
  temp3 <- temp1^2 - temp2^2
  numerator <- qnorm(1-alpha2) * temp1 - z.value*temp2 - temp3
  denominator <- sqrt(temp3)
  integrand.value <- ( 1 - pnorm(numerator/denominator) ) * dnorm(z.value - temp2)
  return(integrand.value)
}

Try the genepi package in your browser

Any scripts or data that you put into this service are public.

genepi documentation built on Aug. 31, 2023, 5:11 p.m.