R/test.NI.binary.R

Defines functions test.NI.binary

Documented in test.NI.binary

test.NI.binary <- function(n.control=NULL, n.experim=NULL, e.control=NULL, e.experim=NULL,
                           formula=NULL, data=NULL, control.level=0,
                           NI.margin, sig.level=0.025, summary.measure="RD", 
                           print.out=TRUE, unfavourable=TRUE, test.type=NULL,
                           M.boot=2000, bootCI.type="bca", BB.adj=0.0001, 
                           recursive.p.estim=FALSE) {
  covariates<-NULL
  if (any(is.null(n.control), is.null(n.experim), is.null(e.control), is.null(e.experim))&&any(is.null(data), is.null(formula))) {
    stop("Either counts of events and participants or formula+data must be provided.\n")
  }
  if (!is.null(formula)) {
    if (is.character(formula)) formula<-as.formula(formula)
    stopifnot(is.data.frame(data), inherits(formula,"formula"))
    if (is_tibble(data)) data<-as.data.frame(data)
    terms.form <- attr(terms(formula), "term.labels")
    treat.index <- which(grepl("treat\\(", terms.form))
    if (length(treat.index)==0) stop("Treatment variable in the formula must be provided within brackets and preceded by treat, e.g. treat(treatment).\n")
    treatment <- factor(data[,all.vars(formula[[3]])[treat.index]])
    stopifnot(any(treatment==control.level), nlevels(treatment)==2)
    treatment<-relevel(treatment, ref=as.character(control.level))
    covariates <- terms.form[-treat.index]
    outcomes <- data[,all.vars(formula[[2]])]
    n.control<-sum(treatment==control.level)
    n.experim<-length(treatment)-n.control
    e.control<-sum(outcomes[treatment==control.level]==1)
    e.experim<-sum(outcomes[treatment!=control.level]==1)
    covariate.formula<-NULL
    if (length(covariates)!=0) {
      covariate.formula<-"+"
      for (cc in 1:length(covariates)) {
        covariate.formula <- paste(covariate.formula, covariates[cc])
        if (cc!=length(covariates)) covariate.formula<-paste(covariate.formula, "+")
      }
    }
    myformula<-as.formula(paste("outcomes~treatment", covariate.formula))
    mydata <- data.frame(outcomes, treatment, data[,covariates])
    if (length(covariates)>0) colnames(mydata)[3:ncol(mydata)]<-covariates
    assign("mydata", mydata, envir = .GlobalEnv)
    
  } 
  stopifnot(is.numeric(n.control), n.control>0)
  stopifnot(is.numeric(n.experim), n.experim>0)
  stopifnot(is.numeric(e.control), e.control>=0, n.control>=e.control)
  stopifnot(is.numeric(e.experim), e.experim>=0, n.experim>=e.experim)
  stopifnot(is.numeric(NI.margin))
  stopifnot(is.numeric(sig.level), sig.level < 0.5, sig.level > 0)
  stopifnot(is.character(summary.measure),(( summary.measure == "RD" ) || ( summary.measure == "RR" ) || ( summary.measure == "OR" ) || ( summary.measure == "AS" )))
  stopifnot(is.logical(print.out), !is.na(print.out))
  stopifnot(is.logical(unfavourable), !is.na(unfavourable))
  stopifnot(is.logical(recursive.p.estim), !is.na(recursive.p.estim))
  stopifnot(is.numeric(M.boot), M.boot>1)
  stopifnot(is.character(bootCI.type), bootCI.type%in%c("norm","perc","bca","basic"))
  stopifnot(is.numeric(BB.adj), BB.adj>0)
  adjusted<-(!is.null(covariates)&&any(dim(covariates)>0))
  if (is.null(formula)) {
    outcomes<-c(rep(1, e.experim),rep(0, n.experim-e.experim),rep(1, e.control), rep(0, n.control-e.control))
    treatment<-factor(c(rep(1,n.experim), rep(0, n.control)))
    treat.index<-1
    mydata<-data.frame(outcomes,treatment)
    myformula<-as.formula("outcomes~treatment")
  }
  if (is.null(test.type)) {
    if (!adjusted) {
      if (summary.measure=="RD") {
        test.type<-"Newcombe10"
      } else if (summary.measure=="RR") {
        test.type<-"Koopman"
      } else if (summary.measure=="OR") {
        test.type<-"Baptista.Pike.midp"
      } else {
        test.type<-"Wald"
      } 
    } else {
        test.type<-"logistic"
    }
    
  }
  stopifnot(is.character(test.type))
  if (summary.measure=="RD") {
    if (!adjusted) {
      stopifnot(test.type%in%c("Wald", "Wald.cc", "Hauck.Anderson", "Gart.Nam",
                               "Newcombe10", "Newcombe11", "Haldane", "Jeffreys.Perks",
                               "Agresti.Caffo", "Miettinen.Nurminen", "Farrington.Manning",
                               "logistic", "binreg", "bootstrap", "Agresti.Min", "Brown.Li.Jeffreys", 
                               "Chan.Zhang", "BLNM", "Mee", "uncond.midp", "Berger.Boos",
                               "MUE.Lin", "MUE.parametric.bootstrap"))
      
    } else {
      stopifnot(test.type%in%c("logistic", "binreg", "bootstrap"))
      
    }
   } else if (summary.measure=="RR") {
     if (!adjusted) {
       stopifnot(test.type%in%c("Wald.Katz", "adjusted.Wald.Katz", "inverse.hyperbolic.sine", "Koopman",
                                "MOVER.R", "Miettinen.Nurminen", "MOVER", "Gart.Nam", "score.cc",
                                "logregression", "logistic", "bootstrap", "Bailey", "Noether", 
                                "Chan.Zhang", "Agresti.Min", "uncond.midp", "Berger.Boos"))
     } else {
       stopifnot(test.type%in%c("logregression", "logistic", "bootstrap"))
       
     }
  } else if (summary.measure=="OR") {
    if (!adjusted) {
      stopifnot(test.type%in%c("Wald.Woolf", "adjusted.Wald.Woolf", "inverse.hyperbolic.sine", "Cornfield.exact",
                               "MOVER.R", "Miettinen.Nurminen", "MOVER", "Gart.Nam", "score.cc",
                               "logistic", "bootstrap", "Cornfield.midp", "Baptista.Pike.exact", "Baptista.Pike.midp", 
                               "Chan.Zhang", "Agresti.Min", "uncond.midp", "Berger.Boos"))
    } else {
      stopifnot(test.type%in%c("logistic", "bootstrap"))
      
    }
  } else {
    if (!adjusted) {
      stopifnot(test.type%in%c("Wald","logistic", "bootstrap"))
    } else {
      stopifnot(test.type%in%c("logistic", "bootstrap"))
    }
  }

  estimate<-se<-Z<-p<-NULL
  
  if (summary.measure=="RD") {
    t2x2<-matrix(c(e.control, n.control-e.control, e.experim, n.experim-e.experim), nrow = 2, byrow = TRUE)
    if ((unfavourable == T)&&(NI.margin<=0)) stop("When outcome is unfavourable, a risk difference NI margin needs to be positive.\n")
    if ((unfavourable == F)&&(NI.margin>=0)) stop("When outcome is favourable, a risk difference NI margin needs to be negative.\n")
    if (NI.margin>=1) stop("NI.margin cannot be greater than 1, i.e. 100 percentage points, or otherwise the test is meaningless.\n ")
    if (NI.margin<=-1) stop("NI.margin cannot be lower than -1, i.e. -100 percentage points, or otherwise the test is meaningless.\n ")
    NIm<- NI.margin
    if (test.type=="Wald") {
      se <- sqrt(e.experim/n.experim*(1-e.experim/n.experim)/n.experim+e.control/n.control*(1-e.control/n.control)/n.control)
      estimate <- e.experim/n.experim-e.control/n.control
      Z <- ifelse( unfavourable==T, (estimate - NIm)/se, -(estimate - NIm)/se)
      p <- pnorm(Z)
      CI <- c(estimate-qnorm(1-sig.level)*se,estimate+qnorm(1-sig.level)*se)
    } else if (test.type=="Wald.cc") {
      se <- sqrt(e.experim/n.experim*(1-e.experim/n.experim)/n.experim+e.control/n.control*(1-e.control/n.control)/n.control)
      estimate <- e.experim/n.experim-e.control/n.control
      Z <- ifelse( unfavourable==T, (estimate - NIm)/se, -(estimate - NIm)/se)
      Z<-Z+(1/n.control+1/n.experim)/2*(1-2*(unfavourable==F))
      p <- pnorm(Z)
      CI <- c(estimate-(qnorm(1-sig.level)*se+(1/n.control+1/n.experim)/2),
              estimate+(qnorm(1-sig.level)*se+(1/n.control+1/n.experim)/2))
    } else if (test.type=="Newcombe10") {
        test<-BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "score")
        CI <- test[2:3]
        estimate<-test[1]
    } else if (test.type=="Newcombe11") {
      test<-BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "scorecc")
      CI <- test[2:3]
      estimate<-test[1]
    } else if (test.type=="Gart.Nam") {
      test<-scasci(e.experim,n.experim,e.control,n.control, level=(1-sig.level*2))$estimates
      CI <-test[c(1,3)]
      estimate<-test[2]
    } else if (test.type=="Agresti.Caffo") {
      se <- sqrt((e.experim+1)/(n.experim+2)*(1-(e.experim+1)/(n.experim+2))/(n.experim+2)+(e.control+1)/(n.control+2)*(1-(e.control+1)/(n.control+2))/(n.control+2))
      estimate <- (e.experim+1)/(n.experim+2)-(e.control+1)/(n.control+2)
      Z <- ifelse( unfavourable==T, (estimate - NIm)/se, -(estimate - NIm)/se)
      p <- pnorm(Z)
      CI <- c(estimate-qnorm(1-sig.level)*se,estimate+qnorm(1-sig.level)*se)
    } else if (test.type=="Haldane") {
      test<-BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "hal")
      CI <- test[2:3]
      estimate<-test[1]
    } else if (test.type=="Hauck.Anderson") {
      test<-BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "ha")
      CI <- test[2:3]
      estimate<-test[1]
    } else if (test.type=="Jeffreys.Perks") {
      test<-BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "jp")
      CI <- test[2:3]
      estimate<-test[1]
    } else if (test.type=="Miettinen.Nurminen") {
      test<-BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "mn")
      CI <- test[2:3]
      estimate<-test[1]
    } else if (test.type=="Mee") {
      test<-BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "mee")
      CI <- test[2:3]
      estimate<-test[1]
    } else if (test.type=="Farrington.Manning") {
      alt.type<-ifelse(isTRUE(unfavourable), "less", "greater")
      test <- farrington.manning(c(rep(TRUE, e.experim), rep(FALSE, n.experim-e.experim)),c(rep(TRUE, e.control), rep(FALSE, n.control-e.control)), delta=NI.margin, alpha = sig.level, alternative = alt.type)
      CI<-test$conf.int
      estimate<-test$estimate
      Z<-test$statistic
      p<-test$p.value
      se<-(estimate - NIm)/Z
    } else if (test.type=="Brown.Li.Jeffreys") {
      test<-BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "blj")
      CI <- test[2:3]
      estimate<-test[1]
    } else if (test.type=="BLNM") {
        test1 <- BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "blj")
        test2 <- BinomDiffCI(e.experim, n.experim, e.control, n.control, conf.level = (1-sig.level*2), method = "mn")
        CI <- test1[2:3]/3 + 2 * test2[2:3]/3
        estimate<-test1[1]/3 + 2 * test2[1]/3
      } else if (test.type=="logistic") {
        
        fit<-glm(myformula, data=mydata, family = binomial)
        fit.std<-avg_comparisons(fit, conf_level = (1-sig.level*2))
        CI <- c(fit.std[fit.std$term=="treatment","conf.low"], fit.std[fit.std$term=="treatment","conf.high"])
        estimate<-fit.std[fit.std$term=="treatment","estimate"]
        se<-fit.std[fit.std$term=="treatment","std.error"]
        
      } else if (test.type=="binreg") {
        
        fit<-glm(myformula, data=mydata, family = binomial(link = "identity"))
        estimate<-coef(summary(fit))[treat.index+1,"Estimate"]
        se<-coef(summary(fit))[treat.index+1,"Std. Error"]
        CI <- c(estimate-qnorm(1-sig.level)*se,estimate+qnorm(1-sig.level)*se)
        
      } else if ( test.type == "bootstrap") {
  
        rdif <- function(dat, indices) {
          d <- dat[indices,] # allows boot to select sample
          rd <- mean(d[d$treatment!=control.level,"outcomes"]) - mean(d[d$treatment==control.level,"outcomes"])
          return(rd)
        } 
        res.b<-boot(mydata, rdif, R=M.boot)
        CI<-boot.ci(res.b, type=bootCI.type, conf=1-sig.level*2)[[4]][4:5-2*(bootCI.type=="norm")]
        estimate<-res.b$t0
        
      } else if (test.type == "Agresti.Min") {
        fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "square", conf.int = T)
        CI <- as.numeric(fit$conf.int)
        estimate<-as.numeric(fit$estimate)
      } else if (test.type == "Chan.Zhang") {
        fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "central", conf.int = T)
        CI <- as.numeric(fit$conf.int)
        estimate<-as.numeric(fit$estimate)
      } else if (test.type == "uncond.midp") {
        fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "square", midp=T, conf.int = T)
        CI <- as.numeric(fit$conf.int)
        estimate<-as.numeric(fit$estimate)
      } else if (test.type == "Berger.Boos") {
        fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "square", gamma=BB.adj, conf.int = T)
        CI <- as.numeric(fit$conf.int)
        estimate<-as.numeric(fit$estimate)
      } else if (test.type == "MUE.Lin") {
        p0.tilde<-ifelse(((e.control>0)&&(e.control<n.control)),(qbeta(0.5,e.control,n.control-e.control+1)+qbeta(0.5,e.control+1,n.control-e.control))/2,
                           ifelse(e.control==0,(1-0.5^(1/n.control))/2,(1+0.5^(1/n.control))/2))
        p1.tilde<-ifelse(((e.experim>0)&&(e.experim<n.experim)),(qbeta(0.5,e.experim,n.experim-e.experim+1)+qbeta(0.5,e.experim+1,n.experim-e.experim))/2,
                         ifelse(e.experim==0,(1-0.5^(1/n.experim))/2,(1+0.5^(1/n.experim))/2))
        probs.mat<-matrix(NA,(n.control+1)*(n.experim+1),7)
        kk=1
        for (ii in 0:n.control) {
          for (jj in 0:n.experim) {
            probs.mat[kk,6]<-ii
            probs.mat[kk,7]<-jj
            probs.mat[kk,2]<-ifelse(((ii>0)&&(ii<n.control)),(qbeta(0.5,ii,n.control-ii+1)+qbeta(0.5,ii+1,n.control-ii))/2,
                                    ifelse(ii==0,(1-0.5^(1/n.control))/2,(1+0.5^(1/n.control))/2))
            
            probs.mat[kk,3]<-ifelse(((jj>0)&&(jj<n.experim)),(qbeta(0.5,jj,n.experim-jj+1)+qbeta(0.5,jj+1,n.experim-jj))/2,
                                    ifelse(jj==0,(1-0.5^(1/n.experim))/2,(1+0.5^(1/n.experim))/2))
            
            probs.mat[kk,4]<-probs.mat[kk,3]-probs.mat[kk,2]
            probs.mat[kk,1]<-exp(lchoose(n.control,ii)+lchoose(n.experim,jj)+log(p0.tilde)*ii+log(p1.tilde)*jj+log(1-p0.tilde)*(n.control-ii)+log(1-p1.tilde)*(n.experim-jj))
            kk=kk+1
          }
        }
        probs.mat<-probs.mat[order(probs.mat[,4]),]
        probs.mat[,5]<-cumsum(probs.mat[,1])
        
        ci.l.l<-max(which(probs.mat[,5]<=sig.level))
        ci.l.u<-min(which(probs.mat[,5]>=sig.level))
        ci.l<-(probs.mat[ci.l.l,4]*(probs.mat[ci.l.u,5]-sig.level)+probs.mat[ci.l.u,4]*(-probs.mat[ci.l.l,5]+sig.level))/(probs.mat[ci.l.u,5]-probs.mat[ci.l.l,5])
        ci.u.l<-max(which(probs.mat[,5]<=(1-sig.level)))
        ci.u.u<-min(which(probs.mat[,5]>=(1-sig.level)))
        ci.u<-(probs.mat[ci.u.l,4]*(probs.mat[ci.u.u,5]-(1-sig.level))+probs.mat[ci.u.u,4]*(-probs.mat[ci.u.l,5]+1-sig.level))/(probs.mat[ci.u.u,5]-probs.mat[ci.u.l,5])
        CI<-c(ci.l,ci.u)
        estimate<-mean(c(ci.l, ci.u))
      } else if (test.type == "MUE.parametric.bootstrap") {
        p0.tilde<-ifelse(((e.control>0)&&(e.control<n.control)),(qbeta(0.5,e.control,n.control-e.control+1)+qbeta(0.5,e.control+1,n.control-e.control))/2,
                         ifelse(e.control==0,(1-0.5^(1/n.control))/2,(1+0.5^(1/n.control))/2))
        p1.tilde<-ifelse(((e.experim>0)&&(e.experim<n.experim)),(qbeta(0.5,e.experim,n.experim-e.experim+1)+qbeta(0.5,e.experim+1,n.experim-e.experim))/2,
                         ifelse(e.experim==0,(1-0.5^(1/n.experim))/2,(1+0.5^(1/n.experim))/2))
        y<-c(rep(1, e.experim),rep(0, n.experim-e.experim),rep(1, e.control), rep(0, n.control-e.control))
        treat<-factor(c(rep(1,n.experim), rep(0, n.control)))
        dd<-data.frame(y,treat)
        rdif <- function(dat) {
          p0.tilde.i<-ifelse(((as.numeric(dat[1,1])>0)&&(as.numeric(dat[1,1])<n.control)),(qbeta(0.5,as.numeric(dat[1,1]),n.control-as.numeric(dat[1,1])+1)+qbeta(0.5,as.numeric(dat[1,1])+1,n.control-as.numeric(dat[1,1])))/2,
                             ifelse(as.numeric(dat[1,1])==0,(1-0.5^(1/n.control))/2,(1+0.5^(1/n.control))/2))
          p1.tilde.i<-ifelse(((as.numeric(dat[1,2])>0)&&(as.numeric(dat[1,2])<n.experim)),(qbeta(0.5,as.numeric(dat[1,2]),n.experim-as.numeric(dat[1,2])+1)+qbeta(0.5,as.numeric(dat[1,2])+1,n.experim-as.numeric(dat[1,2])))/2,
                             ifelse(as.numeric(dat[1,2])==0,(1-0.5^(1/n.experim))/2,(1+0.5^(1/n.experim))/2))
          
          rd <- p1.tilde.i-p0.tilde.i
          return(rd)
        } 
        rg <- function(dat, mle) {
          # Function to generate random exponential variates.
          # mle will contain the mean of the original data
          out <- data.frame(matrix(NA,1,2))
          out[1,1] <- rbinom(1,mle[2], mle[1])
          out[1,2] <- rbinom(1,mle[4], mle[3])
          out
        }
        res.b<-boot(dd, rdif, R = M.boot, sim = "parametric",
                    ran.gen = rg, mle = c(p0.tilde,n.control,p1.tilde,n.experim))
        CI<-boot.ci(res.b, type=bootCI.type, conf=1-sig.level*2)[[4]][4:5-2*(bootCI.type=="norm")]
        estimate<-res.b$t0
    }
    estimate.n<-mean(CI)
    if (is.null(se)) {
      se<-(CI[2]-CI[1])/(2*qnorm(1-sig.level))
      is.se.est<-T
    } else {
      is.se.est<-F
    }
    if (isTRUE(recursive.p.estim)) {
      
      if (estimate==NI.margin) {
        p=0.5
      } else {
        sig.lev.est<-try(uniroot(func.to.opt, c(10^(-15), 0.5-10^(-15)), 
                                 n.control=n.control, n.experim=n.experim, 
                                 e.control=e.control, e.experim=e.experim,
                                 NI.margin=NI.margin, summary.measure=summary.measure, 
                                 unfavourable=unfavourable, test.type=test.type,
                                 M.boot=M.boot, BB.adj=BB.adj,
                                 tol = 0.000001)$root, silent=TRUE)
        if (!inherits(sig.lev.est,"try-error")) {
          p<-ifelse(((unfavourable==T)&&(estimate>NI.margin))||
                      ((unfavourable==F)&&(estimate<NI.margin)),
                    1-sig.lev.est, sig.lev.est)
        } else {
          p<-NULL
          warning("recursive estimation of p failed. Providing standard estimate.\n")
        }

      }
      
      
    }
    if (is.null(p)) {
      Z <- ifelse(unfavourable==T,(estimate.n - NIm)/se,(-estimate.n + NIm)/se)
      p <- pnorm(Z)
      is.p.est<-T
    } else {
      is.p.est<-F
    }
    if ((unfavourable==T&&CI[2]<NI.margin)||(unfavourable==F&&CI[1]>NI.margin)) { 
      non.inferiority<-T
    } else {
      non.inferiority<-F
    }
    
    if (print.out==T) {
      cat("Testing for non-inferiority.\nSummary measure: Risk difference.\nNon-inferiority margin = ", NI.margin, ".\nMethod: ",test.type,
          ".\nEstimate = ", estimate, 
          "\nConfidence interval (Two-sided ", (1-sig.level*2)*100,"%): (", CI[1], ",", CI[2], 
          ")\np-value = ", p, ".\n" , sep="")
      if ((unfavourable==T&&CI[2]<NI.margin)||(unfavourable==F&&CI[1]>NI.margin)) { 
        cat("The confidence interval does not cross the null ( RD = ", NI.margin, " ), and hence we have evidence of non-inferiority.\n", sep="")
      } else {
        cat("The confidence interval crosses the null ( RD = ", NI.margin, " ), and hence we have NO evidence of non-inferiority.\n", sep="")
      }
      if (is.p.est==T) {
        if (is.se.est==T) {
          cat("Note: with the test = ",test.type, " for summary measure = ", summary.measure,", p-value and standard error are only approximations based on a Z test with given logarithm of estimate and CI.\n")
        } else {
          cat("Note: with the test = ",test.type, " for summary measure = ", summary.measure,", p-value is only an approximation based on a Z test with given logarithm of estimate and CI.\n")
        }
      }
      
    }
    
  } else if (summary.measure == "RR") {
    t2x2<-matrix(c(e.experim, n.experim-e.experim, e.control, n.control-e.control), nrow = 2, byrow = TRUE)
    if ((unfavourable == T)&&(NI.margin<=1)) stop("When outcome is unfavourable, a NI margin on the risk ratio scale needs to be >1.")
    if ((unfavourable == F)&&(NI.margin>=1)) stop("When outcome is favourable, a NI margin on the risk ratio scale needs to be <1.")
    if (NI.margin<=0) stop("A risk ratio margin must be >0.\n")
    NIm<- log(NI.margin)
    if (test.type=="Wald.Katz") {
      if ((e.control==0)||(e.experim==0)) stop("Wald.Katz interval not computable in presence of zero cell counts (e.control=0 or e.experim=0).\n")
      se <- sqrt(1/e.control-1/n.control+1/e.experim-1/n.experim)
      estimate <- log((e.experim/n.experim)/(e.control/n.control))
      Z <- ifelse( unfavourable==T, (estimate - NIm)/se, -(estimate - NIm)/se)
      p <- pnorm(Z)
      CI <- exp(c(estimate-qnorm(1-sig.level)*se,estimate+qnorm(1-sig.level)*se))
      estimate <- exp(estimate)
    } else if (test.type=="adjusted.Wald.Katz") {
      se <- sqrt(1/(e.control+0.5)-1/(n.control+0.5)+1/(e.experim+0.5)-1/(n.experim+0.5))
      estimate <- log(((e.experim+0.5)/(n.experim+0.5))/((e.control+0.5)/(n.control+0.5)))
      Z <- ifelse( unfavourable==T, (estimate - NIm)/se, -(estimate - NIm)/se)
      p <- pnorm(Z)
      CI <- exp(c(estimate-qnorm(1-sig.level)*se,estimate+qnorm(1-sig.level)*se))
      estimate <- exp(estimate)
    } else if (test.type=="inverse.hyperbolic.sine") {
      if (e.experim==0) t2x2[1,1]<-round(qnorm(1-sig.level)^2)
      if (e.control==0) t2x2[2,1]<-round(qnorm(1-sig.level)^2)
      test<-Inv_sinh_CI_ratio_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="Koopman") {
      test<-Koopman_asymptotic_score_CI_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="Miettinen.Nurminen") {
      test<-MiettinenNurminen_asymptotic_score_CI_ratio_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="MOVER.R") {
      test<-MOVER_R_Wilson_CI_ratio_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="MOVER") {
      test<-moverci(e.experim,n.experim,e.control,n.control,contrast = "RR", level = 1-2*sig.level)
      CI<-test[c(1,3)]
      estimate<-test[2]
    } else if (test.type=="Gart.Nam") {
      test<-scasci(e.experim,n.experim,e.control,n.control,contrast = "RR", level = 1-2*sig.level)$estimates
      CI<-test[c(1,3)]
      estimate<-test[2]
    } else if (test.type=="score.cc") {
      test<-ratesci::scoreci(e.experim,n.experim,e.control,n.control,contrast = "RR", level = 1-2*sig.level, cc=T)$estimates
      CI<-test[c(1,3)]
      estimate<-test[2]
    } else if (test.type=="Bailey") {
      test<-BinomRatioCI(x1 = e.experim, n1 = n.experim, x2 = e.control, n2 = n.control, method = "bailey")
      CI<-test[2:3]
      estimate<-test[1]
    } else if (test.type=="Noether") {
      test<-BinomRatioCI(x1 = e.experim, n1 = n.experim, x2 = e.control, n2 = n.control, method = "noether")
      CI<-test[2:3]
      estimate<-test[1]
    } else if (test.type=="bootstrap") {
      
      rrat <- function(dat, indices) {
        d <- dat[indices,] # allows boot to select sample
        rr <- log(mean(d[d$treatment!=control.level,"outcomes"])) - log(mean(d[d$treatment==control.level,"outcomes"]))
        return(rr)
      } 
      res.b<-boot(mydata, rrat, R=M.boot)
      CI<-exp(boot.ci(res.b, type=bootCI.type, conf=1-sig.level*2)[[4]][4:5-2*(bootCI.type=="norm")])
      estimate<-exp(res.b$t0)
      
    } else if (test.type == "Agresti.Min") {
      fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "square", conf.int = T, parmtype="ratio")
      CI <- as.numeric(fit$conf.int)
      estimate<-as.numeric(fit$estimate)
    } else if (test.type == "Chan.Zhang") {
      fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "central", conf.int = T, parmtype="ratio")
      CI <- as.numeric(fit$conf.int)
      estimate<-as.numeric(fit$estimate)
    } else if (test.type == "uncond.midp") {
      fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "square", midp=T, conf.int = T, parmtype="ratio")
      CI <- as.numeric(fit$conf.int)
      estimate<-as.numeric(fit$estimate)
    } else if (test.type == "Berger.Boos") {
      fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "square", gamma=BB.adj, conf.int = T, parmtype="ratio")
      CI <- as.numeric(fit$conf.int)
      estimate<-as.numeric(fit$estimate)
    } else if (test.type=="logistic") {
      fit<-glm(myformula, data=mydata, family = binomial)
      fit.std<-avg_comparisons(fit, conf_level = (1-sig.level*2), comparison="lnratio", transform = exp)
      CI <- c(fit.std[fit.std$term=="treatment","conf.low"], fit.std[fit.std$term=="treatment","conf.high"])
      estimate<-fit.std[fit.std$term=="treatment","estimate"]

    } else if (test.type=="logregression") {
      if (e.experim==0||e.control==0) stop("logregression not possible with zero cell counts (e.control=0 or e.experim=0).\n")
      fit<-glm(myformula, data=mydata, family = binomial(link="log"))
      row.treat<-which(grepl("treatment", row.names(coef(summary(fit)))))
      estimate<-exp(coef(summary(fit)))[row.treat,"Estimate"]
      CI <- exp(suppressMessages(confint(fit, level = 1-sig.level*2))[row.treat,])
    } 
    estimate.n<-mean(log(CI))
    if (is.null(se)) {
      se<-(log(CI[2])-log(CI[1]))/(2*qnorm(1-sig.level))
      is.se.est<-T
    } else {
      is.se.est<-F
    }
    if (isTRUE(recursive.p.estim)) {
      
      if (estimate==NI.margin) {
        p=0.5
      } else {
        sig.lev.est<-try(uniroot(func.to.opt, c(10^(-15), 0.5-10^(-15)), 
                                 n.control=n.control, n.experim=n.experim, 
                                 e.control=e.control, e.experim=e.experim,
                                 NI.margin=NI.margin, summary.measure=summary.measure, 
                                 unfavourable=unfavourable, test.type=test.type,
                                 M.boot=M.boot, BB.adj=BB.adj,
                                 tol = 0.000001)$root, silent=TRUE)
        if (!inherits(sig.lev.est,"try-error")) {
          p<-ifelse(((unfavourable==T)&&(estimate>NI.margin))||
                      ((unfavourable==F)&&(estimate<NI.margin)),
                    1-sig.lev.est, sig.lev.est)
        } else {
          p<-NULL
          warning("Recursive estimation of p failed. Providing standard estimate.\n")
        }
      }
    }
    if (is.null(p)) {
      Z <- ifelse(unfavourable==T,(estimate.n - NIm)/se,(-estimate.n + NIm)/se)
      p <- pnorm(Z)
      is.p.est<-T
    } else {
      is.p.est<-F
    }
    if ((unfavourable==T&&CI[2]<NI.margin)||(unfavourable==F&&CI[1]>NI.margin)) { 
      non.inferiority<-T
    } else {
      non.inferiority<-F
    }
    if (print.out==T) {
      cat("Testing for non-inferiority.\nSummary measure: Risk ratio.\nNon-inferiority margin = ", NI.margin, ".\nMethod: ",test.type,
          ".\nEstimate = ", estimate, 
          "\nConfidence interval (Two-sided ", (1-sig.level*2)*100,"%): (", CI[1], ",", CI[2], 
          ")\np-value = ", p, ".\n" , sep="")
      if ((unfavourable==T&&CI[2]<NI.margin)||(unfavourable==F&&CI[1]>NI.margin)) { 
        cat("The confidence interval does not cross the null ( RR = ", NI.margin, " ), and hence we have evidence of non-inferiority.\n", sep="")
      } else {
        cat("The confidence interval crosses the null ( RR = ", NI.margin, " ), and hence we have NO evidence of non-inferiority.\n", sep="")
      }
      if (is.p.est==T) {
        if (is.se.est==T) {
          cat("Note: with the test = ",test.type, " for summary measure = ", summary.measure,", p-value and standard error are only approximations based on a Z test with given logarithm of estimate and CI.\n")
        } else {
          cat("Note: with the test = ",test.type, " for summary measure = ", summary.measure,", p-value is only an approximation based on a Z test with given logarithm of estimate and CI.\n")
        }
      }
      
    }
    
  } else if (summary.measure == "AS") {
    is.p.est<-is.se.est<-F
    NIm<-NI.margin
    if ((unfavourable == T)&&(NI.margin<=0)) stop("When outcome is unfavourable, a NI margin on the arc-sine difference scale needs to be >0.")
    if ((unfavourable == F)&&(NI.margin>=0)) stop("When outcome is favourable, a NI margin on the arc-sine difference scale needs to be <0.")
    if (test.type=="Wald") {
      se <- sqrt(1/(4*n.control)+1/(4*n.experim))
      estimate <- asin(sqrt(e.experim/n.experim))-asin(sqrt(e.control/n.control))
      Z <- (estimate - NIm)/se
      p <- pnorm(Z)
      CI <- c(estimate-qnorm(1-sig.level)*se,estimate+qnorm(1-sig.level)*se)
    } else if (test.type=="logistic") {
      fit<-glm(myformula, data=mydata, family = binomial)
      fit.std<-avg_comparisons(fit, conf_level = (1-sig.level*2), comparison=function(hi, lo) asin(sqrt(hi))-asin(sqrt(lo)))
      CI <- c(fit.std[fit.std$term=="treatment","conf.low"], fit.std[fit.std$term=="treatment","conf.high"])
      estimate<-fit.std[fit.std$term=="treatment","estimate"]
      se<-fit.std[fit.std$term=="treatment","std.error"]
      p<-NULL
    } else if (test.type=="bootstrap") {
      
      asdif <- function(dat, indices) {
        d <- dat[indices,] # allows boot to select sample
        as<-asin(sqrt(mean(d[d$treatment!=control.level,"outcomes"])))-asin(sqrt(mean(d[d$treatment==control.level,"outcomes"])))
        return(as)
      } 
      res.b<-boot(mydata, asdif, R=M.boot)
      CI<-boot.ci(res.b, type=bootCI.type, conf=1-sig.level*2)[[4]][4:5-2*(bootCI.type=="norm")]
      estimate<-res.b$t0
      
    }
    estimate.n<-mean(CI)
    if (is.null(p)) {
      Z <- ifelse(unfavourable==T,(estimate.n - NIm)/se,(-estimate.n + NIm)/se)
      p <- pnorm(Z)
      is.p.est<-T
    } else {
      is.p.est<-F
    }
    if (isTRUE(recursive.p.estim)) {
      
      if (estimate==NI.margin) {
        p=0.5
      } else {
        sig.lev.est<-try(uniroot(func.to.opt, c(10^(-15), 0.5-10^(-15)), 
                                 n.control=n.control, n.experim=n.experim, 
                                 e.control=e.control, e.experim=e.experim,
                                 NI.margin=NI.margin, summary.measure=summary.measure, 
                                 unfavourable=unfavourable, test.type=test.type,
                                 M.boot=M.boot, BB.adj=BB.adj,
                                 tol = 0.000001)$root, silent=TRUE)
        if (!inherits(sig.lev.est, "try-error")) {
          p<-ifelse(((unfavourable==T)&&(estimate>NI.margin))||
                      ((unfavourable==F)&&(estimate<NI.margin)),
                    1-sig.lev.est, sig.lev.est)
        } else {
          warning("Recursive estimation of p failed. Providing standard estimate.\n")
        }
      }
      
      
    }
    
    if ((unfavourable==T&&CI[2]<NI.margin)||(unfavourable==F&&CI[1]>NI.margin)) { 
      non.inferiority<-T
    } else {
      non.inferiority<-F
    }
    if (print.out==T) {
      cat("Testing for non-inferiority.\nSummary measure: Arc-sine difference.\nNon-inferiority margin = ", NI.margin, ".\nMethod: ",test.type,
          ".\nEstimate = ", estimate, 
          "\nConfidence interval (Two-sided ", (1-sig.level*2)*100,"%): (", CI[1], ",", CI[2], 
          ")\np-value = ", p, ".\n" , sep="")
      if ((unfavourable==T&&CI[2]<NI.margin)||(unfavourable==F&&CI[1]>NI.margin)) { 
        cat("The confidence interval does not cross the null ( ASD = ", NI.margin, " ), and hence we have evidence of non-inferiority.\n", sep="")
      } else {
        cat("The confidence interval crosses the null ( ASD = ", NI.margin, " ), and hence we have NO evidence of non-inferiority.\n", sep="")
        }
      } 
    } else if (summary.measure == "OR") {
      t2x2<-matrix(c(e.experim, n.experim-e.experim, e.control, n.control-e.control), nrow = 2, byrow = TRUE)
    if ((unfavourable == T)&&(NI.margin<=1)) stop("When outcome is unfavourable, a NI margin on the odds ratio scale needs to be >1.")
    if ((unfavourable == F)&&(NI.margin>=1)) stop("When outcome is favourable, a NI margin on the odds ratio scale needs to be <1.")
    if (NI.margin<=0) stop("A odds ratio margin must be >0.\n")
    NIm<- log(NI.margin)
    if (test.type=="Wald.Woolf") {
      if (e.experim==0||e.control==0) stop("Wald.Woolf not informative with zero cell counts (e.control=0 or e.experim=0).\n")
      se <- sqrt(1/e.control+1/(n.control-e.control)+1/e.experim+1/(n.experim-e.experim))
      estimate <- log((e.experim/(n.experim-e.experim))/(e.control/(n.control-e.control)))
      Z <- ifelse( unfavourable==T, (estimate - NIm)/se, -(estimate - NIm)/se)
      p <- pnorm(Z)
      CI <- exp(c(estimate-qnorm(1-sig.level)*se,estimate+qnorm(1-sig.level)*se))
      estimate <- exp(estimate)
    } else if (test.type=="adjusted.Wald.Woolf") {
      se <- sqrt(1/(e.control+0.5)+1/(n.control-e.control+0.5)+1/(e.experim+0.5)+1/(n.experim-e.experim+0.5))
      estimate <- log(((e.experim+0.5)/(n.experim-e.experim+0.5))/((e.control+0.5)/(n.control-e.control+0.5)))
      Z <- ifelse( unfavourable==T, (estimate - NIm)/se, -(estimate - NIm)/se)
      p <- pnorm(Z)
      CI <- exp(c(estimate-qnorm(1-sig.level)*se,estimate+qnorm(1-sig.level)*se))
      estimate <- exp(estimate)
    } else if (test.type=="IndSmooth.logit") {
      test<-Independence_smoothed_logit_CI_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="Cornfield.exact") {
      test<-Cornfield_exact_conditional_CI_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="Baptista.Pike.exact") {
      test<-BaptistaPike_exact_conditional_CI_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="Cornfield.midp") {
      test<-Cornfield_midP_CI_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="Baptista.Pike.midp") {
      test<-BaptistaPike_midP_CI_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="inverse.hyperbolic.sine") {
      test<-Inv_sinh_CI_OR_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="Miettinen.Nurminen") {
      test<-MiettinenNurminen_asymptotic_score_CI_OR_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="MOVER.R") {
      test<-MOVER_R_Wilson_CI_OR_2x2(t2x2, alpha = 2*sig.level)
      CI<-as.numeric(test[1:2])
      estimate<-as.numeric(test[3])
    } else if (test.type=="MOVER") {
      test<-moverci(e.experim,n.experim,e.control,n.control,contrast = "OR", level = 1-2*sig.level)
      CI<-as.numeric(test[c(1,3)])
      estimate<-as.numeric(test[2])
    } else if (test.type=="Gart.Nam") {
      test<-scasci(e.experim,n.experim,e.control,n.control,contrast = "OR", level = 1-2*sig.level)$estimates
      CI<-as.numeric(test[c(1,3)])
      estimate<-as.numeric(test[2])
    } else if (test.type=="score.cc") {
      test<-ratesci::scoreci(e.experim,n.experim,e.control,n.control,contrast = "OR", level = 1-2*sig.level, cc=T)$estimates
      CI<-as.numeric(test[c(1,3)])
      estimate<-as.numeric(test[2])
    }  else if (test.type=="MLE") {
      test<-OddsRatio(t2x2, method = "mle", conf.level = 1-sig.level*2)
      CI<-as.numeric(test[c(2,3)])
      estimate<-as.numeric(test[1])
    } else if ( test.type == "bootstrap") {
      if (e.control==0||e.experim==0) stop("bootstrap method not appropriate for zero cell counts (e.control=0 or e.experim=0).\n")
      oddsr <- function(dat, indices) {
        d <- dat[indices,] # allows boot to select sample
        or <- log((sum(d[d$treatment!=control.level,"outcomes"], na.rm=T)/(sum(d$treatment!=control.level, na.rm=T)-sum(d[d$treatment!=control.level,"outcomes"], na.rm=T)))/(sum(d[d$treatment==control.level,"outcomes"], na.rm=T)/(sum(d$treatment==control.level, na.rm=T)-sum(d[d$treatment==control.level,"outcomes"], na.rm=T))))
        return(or)
      } 
      
      res.b<-boot(mydata, oddsr, R=M.boot)
      CI<-exp(boot.ci(res.b, type=bootCI.type, conf=1-sig.level*2)[[4]][4:5-2*(bootCI.type=="norm")])
      estimate<-exp(res.b$t0)
    } else if (test.type == "Agresti.Min") {
      fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "square", conf.int = T, parmtype="oddsratio")
      CI <- as.numeric(fit$conf.int)
      estimate<-as.numeric(fit$estimate)
    } else if (test.type == "Chan.Zhang") {
      fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "central", conf.int = T, parmtype="oddsratio")
      CI <- as.numeric(fit$conf.int)
      estimate<-as.numeric(fit$estimate)
    } else if (test.type == "uncond.midp") {
      fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "square", midp=T, conf.int = T, parmtype="oddsratio")
      CI <- as.numeric(fit$conf.int)
      estimate<-as.numeric(fit$estimate)
    } else if (test.type == "Berger.Boos") {
      fit<-uncondExact2x2(e.control,n.control,e.experim,n.experim, method="score", tsmethod = "square", gamma=BB.adj, conf.int = T, parmtype="oddsratio")
      CI <- as.numeric(fit$conf.int)
      estimate<-as.numeric(fit$estimate)
    } else if (test.type=="logistic") {
      if (e.experim==0||e.control==0) stop("With zero cell counts (e.control=0 or e.experim=0) logistic method not informative.\n")
      fit<-glm(myformula, data=mydata, family = binomial)
      fit.std<-avg_comparisons(fit, conf_level = (1-sig.level*2), comparison="lnor", transform = exp)
      CI <- c(fit.std[fit.std$term=="treatment","conf.low"], fit.std[fit.std$term=="treatment","conf.high"])
      estimate<-fit.std[fit.std$term=="treatment","estimate"]
     }  
    estimate.n<-mean(log(CI))
    if (is.null(se)) {
      se<-(log(CI[2])-log(CI[1]))/(2*qnorm(1-sig.level))
      is.se.est<-T
    } else {
      is.se.est<-F
    }

    if (isTRUE(recursive.p.estim)) {
      
      if (estimate==NI.margin) {
        p=0.5
      } else {
        sig.lev.est<-try(uniroot(func.to.opt, c(10^(-15), 0.5-10^(-15)), 
                                 n.control=n.control, n.experim=n.experim, 
                                 e.control=e.control, e.experim=e.experim,
                                 NI.margin=NI.margin, summary.measure=summary.measure, 
                                 unfavourable=unfavourable, test.type=test.type,
                                 M.boot=M.boot, BB.adj=BB.adj,
                                 tol = 0.000001)$root, silent=TRUE)
        if (!inherits(sig.lev.est, "try-error")) {
          p<-ifelse(((unfavourable==T)&&(estimate>NI.margin))||
                    ((unfavourable==F)&&(estimate<NI.margin)),
                  1-sig.lev.est, sig.lev.est)
        } else {
          p<-NULL
          warning("Recursive estimation of p failed. Providing standard estimate.\n")
        }
      }
      
      
    }
    if (is.null(p)) {
      Z <- ifelse(unfavourable==T,(estimate.n - NIm)/se,(-estimate.n + NIm)/se)
      p <- pnorm(Z)
      is.p.est<-T
      
    } else {
      is.p.est<-F
    }
    if ((unfavourable==T&&CI[2]<NI.margin)||(unfavourable==F&&CI[1]>NI.margin)) { 
      non.inferiority<-T
    } else {
      non.inferiority<-F
    }
    if (print.out==T) {
      cat("Testing for non-inferiority.\nSummary measure: Odds ratio.\nNon-inferiority margin = ", NI.margin, ".\nMethod: ",test.type,
          ".\nEstimate = ", estimate, 
          "\nConfidence interval (Two-sided ", (1-sig.level*2)*100,"%): (", CI[1], ",", CI[2], 
          ")\np-value = ", p, ".\n" , sep="")
      if ((unfavourable==T&&CI[2]<NI.margin)||(unfavourable==F&&CI[1]>NI.margin)) { 
        cat("The confidence interval does not cross the null ( OR = ", NI.margin, " ), and hence we have evidence of non-inferiority.\n", sep="")
      } else {
        cat("The confidence interval crosses the null ( OR = ", NI.margin, " ), and hence we have NO clear evidence of non-inferiority.\n", sep="")
      }
      if (is.p.est==T) {
        if (is.se.est==T) {
          cat("Note: with the test = ",test.type, " for summary measure = ", summary.measure,", p-value and standard error are only approximations based on a Z test with given logarithm of estimate and CI.\n")
        } else {
          cat("Note: with the test = ",test.type, " for summary measure = ", summary.measure,", p-value is only an approximation based on a Z test with given logarithm of estimate and CI.\n")
        }
      }
      
    }    
  }
  results <- list(estimate, se, p, CI, test.type, summary.measure, is.p.est, sig.level, non.inferiority)
  names(results)<-c("estimate", "se", "p", "CI", "test.type", "summary.measure", "is.p.est", "sig.level", "non.inferiority")
  return(results)
}
Matteo21Q/dani documentation built on Aug. 29, 2024, 12:48 a.m.