R/calcES.R

Defines functions calcES

calcES <- function(data,treat,w,numeric.vars,estimand,multinom=FALSE,sw=NULL,get.means=FALSE){

  # with get.means, only one weight can be specified 
  if (get.means){
    if (  ifelse( is.null(ncol(w)) , FALSE , ncol(w)>1) ){
      stop("Only a single weight can be specified wtih gen.means=TRUE")
    }
  }
  
  N = nrow(data)
  N1 = sum(treat)
  N0 = N-N1
  
  # separate out treatment group for easy matrix operations
  w1 = w[treat==1,]                  # subset to treated weight matrix
  data1 = as.matrix(data[treat==1,]) # subset to treated data
  index.1 = !is.na(data1)            # only numeric variable will have missing data, which are dropped from ES calculation.
  den1 = t(w1)%*%index.1             # sum of weights changes depending on missing data -- only numeric variables should have missing values in data
  data1[!index.1] = 0                # change missing values to 0 so they dont contribute to the sum and dont mess up matrix operations
  m1 = t(w1)%*%data1 / den1          # calculate mean among treated
  

  
  # m0 and the SD depends on estimand
  if (estimand=="ATE"){
    # need variance based only on sw
    data = as.matrix(data)
    index = !is.na(data)
    data[!index] = 0         # change missing values to 0 so they dont contribute to the sum and dont mess up matrix operations
    den = sw%*%index
    m.sw = sw%*%data / den
    
    # pooled variance estimate for ATE
    var.p = sw%*%data^2/den - (m.sw)^2
    var.p = ifelse(var.p==0 , NA , var.p)
    var.p[,numeric.vars] =  var.p[,numeric.vars] * N / (N-1)
    
    if (get.means){
      # calculate E[X^2] among treated
      m1.2 =  t(w1)%*%(data1^2) / den1 
      var1=(m1.2-m1^2) 
      var1 = ifelse(var1==0 , NA , var1)
      var1[,numeric.vars] =  var1[,numeric.vars] * N1 / (N1-1)
    }
    
    if (multinom){
      # multinom ATE: m0 is full population mean
      m0 = m.sw
      
      if (get.means){
        var0=var.p
      }
      
      # this just handles that m0 and var.p are vectors when using multinom option
      std.effect = sweep(sweep( m1 , 2 , sqrt(var.p) , "/") , 2 , m0/sqrt(var.p) , "-")
    }else{
      # same steps as with treated, but now for controls
      w0 = w[treat==0,]
      data0 = as.matrix(data[treat==0,])
      index.0 = !is.na(data0)
      den0 = t(w0)%*%index.0
      data0[!index.0] = 0
      
      # calculate mean among control
      m0 = t(w0)%*%data0 / den0
      
      if (get.means){
        # calculate E[X^2] among control
        m0.2 =  t(w0)%*%(data0^2) / den0 
        var0=(m0.2-m0^2) 
        var0 = ifelse(var0==0 , NA , var0)
        var0[,numeric.vars] =  var0[,numeric.vars] * N0 / (N0-1)
      }
      
      # this just handles that var.p is a vector
      std.effect = sweep( m1-m0 , 2 , sqrt(var.p) , "/")
    }
  }else{ #ATT
    # same steps as with treated, but now for controls
    w0 = w[treat==0,]
    data0 = as.matrix(data[treat==0,])
    index.0 = !is.na(data0)
    den0 = t(w0)%*%index.0
    data0[!index.0] = 0
    
    # calculate mean among control
    m0 = t(w0)%*%data0 / den0
    
    # calculate E[X^2] among treated
    m1.2 =  t(w1)%*%(data1^2) / den1 
    var1=(m1.2-m1^2) 
    var1 = ifelse(var1==0 , NA , var1)
    var1[,numeric.vars] =  var1[,numeric.vars] * N1 / (N1-1)
    
    if (get.means){
      # calculate E[X^2] among control
      m0.2 =  t(w0)%*%(data0^2) / den0 
      var0=(m0.2-m0^2) 
      var0 = ifelse(var0==0 , NA , var0)
      var0[,numeric.vars] =  var0[,numeric.vars] * N0 / (N0-1)
    }
    
    std.effect = (m1-m0)/sqrt(var1)
  }
  
  if (get.means){
    ## surveyglm always uses total sample, not number of non-NA
    res = t(rbind(tx.mn=m1 , tx.sd=sqrt(var1), ct.mn=m0 , ct.sd=sqrt(var0) , std.eff.sz=std.effect ))
    colnames(res) = c("tx.mn", "tx.sd",  "ct.mn", "ct.sd", "std.eff.sz")
    return(res)
  }else{
    return(std.effect)
  }
}

Try the twang package in your browser

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

twang documentation built on May 29, 2024, 4:40 a.m.