Search code examples
rlarge-datadifferenceestimation

Diff-in-diff estimation with resampling from large dataset


I have a large dataset on which to perform a diff-in-diff estimation. Given the nature of the dataset my t-statistics denominators are inflated and coefficient are (surreptitiously) statistically significant. I want to step-by-step reducing the number of element in the database, and for each step resample a large number of times and re-estimating each time interaction coefficient and standard errors.

Then I want to take all the averages estimates and standard error, and plot them on a graph, to show at what point (if any) they are not statistically different from zero.

My code follows with a toy example.

  • I am not sure this is the most efficient way to tackle the problem
  • I cannot retrieve and thus plot the confidence interval
  • I am not sure the sampling is representative given the existence of different groups.

Toy example (Creds Torres-Reyna - ‎2015)

library(foreign)
library(dplyr)
library(ggplot2)


df_0 <- NULL
for (i in 1:length(seq(5,nrow(mydata)-1,5))){
 index <- seq(5,nrow(mydata),5)[i]
 df_1 <- NULL
 for (j in 1:10){

  mydata_temp <- mydata[sample(nrow(mydata), index), ]    

  didreg = lm(y ~ treated + time + did, data = mydata_temp)
  out <- summary(didreg)
  new_line <- c(out$coefficients[,1][4], out$coefficients[,2][4], index)
  new_line <- data.frame(t(new_line))
  names(new_line) <- c("c","s","i")
  df_1 <- rbind(df_1,new_line)
  }
 df_0 <- rbind(df_0,df_1)
}

df_0 <- df_0 %>% group_by(i) %>% summarise(coefficient <- mean(c, na.rm = T),
                                          standard_error <- mean(s, na.rm = T)) 

names(df_0) <- c("i","c","s")
View(df_0)

Solution

  • Consider the following refactored code using base R functions: within, %in%, nested lapply, setNames, aggregate, and do.call. This approach avoids calling rbind in a loop and compactly re-writes code without constantly using $ column referencing.

    library(foreign)
    
    mydata = read.dta("http://dss.princeton.edu/training/Panel101.dta")
    
    mydata <- within(mydata, {
      time <- ifelse(year >= 1994, 1, 0)
      treated <- ifelse(country %in% c("E", "F", "G"), 1, 0)
      did <- time * treated
    })
    
    # OUTER LIST OF DATA FRAMES
    df_0_list <- lapply(1:length(seq(5,nrow(mydata)-1,5)), function(i) {      
      index <- seq(5,nrow(mydata),5)[i]
    
      # INNER LIST OF DATA FRAMES  
      df_1_list <- lapply(1:100, function(j) {        
        mydata_temp <- mydata[sample(nrow(mydata), index), ]    
    
        didreg <- lm(y ~ treated + time + did, data = mydata_temp)
        out <- summary(didreg)
        new_line <- c(out$coefficients[,1][4], out$coefficients[,2][4], index)
        new_line <- setNames(data.frame(t(new_line)), c("c","s","i"))
      })
    
      # APPEND ALL INNER DFS
      df <- do.call(rbind, df_1_list)
      return(df)
    })
    
    # APPEND ALL OUTER DFS
    df_0 <- do.call(rbind, df_0_list)
    
    # AGGREGATE WITH NEW COLUMNS
    df_0 <- within(aggregate(cbind(c, s) ~ i, df_0, function(x) mean(x, na.rm=TRUE)), { 
                   upper = c + s 
                   lower = c - s 
            })
    
    # RUN PLOT
    within(df_0, {
      plot(i, c, ylim=c(min(c)-5000000000, max(c)+5000000000), type = "l",
           cex.lab=0.75, cex.axis=0.75, cex.main=0.75, cex.sub=0.75)
      polygon(c(i, rev(i)), c(lower, rev(upper)),
              col = "grey75", border = FALSE)
      lines(i, c, lwd = 2)
    })
    

    Plot Output