### Install HonestDiD from GitHub Source: https://context7.com/asheshrambachan/honestdid/llms.txt Installs the HonestDiD package from GitHub. Ensure the 'remotes' package is installed first. Set R_REMOTES_NO_ERRORS_FROM_WARNINGS to true to prevent warnings from stopping the installation. ```r # Install remotes package if not installed install.packages("remotes") # Turn off warning-error-conversion Sys.setenv("R_REMOTES_NO_ERRORS_FROM_WARNINGS" = "true") # Install from GitHub remotes::install_github("asheshrambachan/HonestDiD") ``` -------------------------------- ### Load Data and Packages in R Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Installs and loads necessary R packages and reads the dataset for analysis. Ensure packages are installed before running. ```r #Install here, dplyr, did, haven, ggplot2, fixest packages from CRAN if not yet installed #install.packages(c("here", "dplyr", "did", "haven", "ggplot2", "fixest")) library(here) library(dplyr) library(did) library(haven) library(ggplot2) library(fixest) library(HonestDiD) df <- read_dta("https://raw.githubusercontent.com/Mixtape-Sessions/Advanced-DID/main/Exercises/Data/ehec_data.dta") head(df,5) ``` -------------------------------- ### Install HonestDiD Package Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Install the HonestDiD package from GitHub using the remotes package. Ensure warnings do not stop the installation by setting the R_REMOTES_NO_ERRORS_FROM_WARNINGS environment variable. ```r # Install remotes package if not installed install.packages("remotes") # Turn off warning-error-conversion, because the tiniest warning stops installation Sys.setenv("R_REMOTES_NO_ERRORS_FROM_WARNINGS" = "true") # install from github remotes::install_github("asheshrambachan/HonestDiD") ``` -------------------------------- ### Running HonestDiD with Universal Base Period Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Example demonstrating how to run the `honest_did` function with the 'universal' base-period option, which is a requirement for the function. ```APIDOC ## Running HonestDiD with Universal Base Period ### Description This snippet shows a practical example of how to utilize the `honest_did` function, emphasizing the necessity of using a universal base period for the event study estimates. ### Method (Illustrative R code) ### Endpoint N/A (This is a function call within an R environment) ### Parameters None directly for this example snippet, assumes `es_object` is pre-defined. ### Request Example ```r # Assuming 'es_object' is an AGGTEobj from the 'did' package # and it was created using a universal base period. # Perform sensitivity analysis for the 'on impact' effect (e=0) # using the default 'smoothness' type. sensitivity_results <- honest_did(es_object) # Print the results print(sensitivity_results) ``` ### Response #### Success Response (200) The `print(sensitivity_results)` command will output a list containing the sensitivity analysis results, original confidence intervals, and the type of analysis performed. #### Response Example ```r # Example output structure: # $robust_ci # List containing detailed sensitivity analysis results. # # $orig_ci # List containing original confidence interval details. # # $type # [1] "smoothness" (or "relative_magnitude" if specified) ``` ``` -------------------------------- ### Run CS Event-Study with Universal Base Period Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Example of how to run a Counterfactual Sensitivity (CS) event-study analysis using the 'universal' base-period option. ```r ### # Run the CS event-study with 'universal' base-period option ``` -------------------------------- ### Run Sun & Abraham with fixest Source: https://context7.com/asheshrambachan/honestdid/llms.txt Example of running the Sun & Abraham staggered DiD estimator using the fixest package, including data preparation for treated years. ```r # Run Sun & Abraham with fixest df$year_treated <- ifelse(is.na(df$yexp2), Inf, df$yexp2) res_sunab <- fixest::feols( dins ~ sunab(year_treated, year) | stfips + year, cluster = "stfips", data = df ) ``` -------------------------------- ### Sun and Abraham (fixest) Integration Source: https://context7.com/asheshrambachan/honestdid/llms.txt Helper function and example for integrating HonestDiD with the Sun and Abraham estimator using the `fixest` package. ```APIDOC ## Integration with Staggered DiD Estimators: Sun and Abraham (fixest) ### Description This section provides a helper function `sunab_beta_vcv` to extract beta and variance-covariance matrix from `fixest::feols` results when using the `sunab` function, and an example of running the Sun & Abraham model with `fixest`. ### Helper Function: sunab_beta_vcv #### Description Extracts the estimated coefficients (beta) and their variance-covariance matrix (vcv) from a `fixest` object estimated using `sunab`. #### Parameters - **sunab_fixest** (object) - Required - A `fixest` object estimated with `sunab`. #### Returns - **beta** (matrix) - The estimated coefficients. - **sigma** (matrix) - The variance-covariance matrix of the coefficients. - **cohorts** (numeric vector) - The unique cohort identifiers. ### Example Usage #### Description Demonstrates how to prepare data and run the Sun & Abraham model using `fixest::feols` with the `sunab` function. #### Code ```r # Assuming 'df' is your data frame with appropriate columns df$year_treated <- ifelse(is.na(df$yexp2), Inf, df$yexp2) res_sunab <- fixest::feols( dins ~ sunab(year_treated, year) | stfips + year, cluster = "stfips", data = df ) ``` ``` -------------------------------- ### Sensitivity Analysis for Average Effects in R Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Use `l_vec = c(0.5,0.5)` to calculate sensitivity results for the average of two post-treatment periods. This setup is useful for understanding the robustness of the estimated average effects. ```r delta_rm_results_avg <- HonestDiD::createSensitivityResults_relativeMagnitudes(betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mbarvec = seq(0,2,by=0.5), l_vec = c(0.5,0.5)) originalResults_avg <- HonestDiD::constructOriginalCS(betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, l_vec = c(0.5,0.5)) HonestDiD::createSensitivityPlot_relativeMagnitudes(delta_rm_results_avg, originalResults_avg) ``` -------------------------------- ### Parallel Computation for Sensitivity Analysis Source: https://context7.com/asheshrambachan/honestdid/llms.txt Enables parallel computation for HonestDiD sensitivity analysis using 'doParallel' and 'foreach'. Remember to register the parallel backend and stop the cluster when finished. ```r library(doParallel) library(foreach) # Register parallel backend registerDoParallel(cores = 4) # Run sensitivity analysis in parallel results_parallel <- HonestDiD::createSensitivityResults_relativeMagnitudes( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mbarvec = seq(0, 2, by = 0.1), parallel = TRUE ) # Stop parallel backend stopImplicitCluster() ``` -------------------------------- ### Create Basis Vector for Post-Treatment Period Analysis Source: https://context7.com/asheshrambachan/honestdid/llms.txt Generates a basis vector to specify the post-treatment period for analysis. By default, inference is on the first post-treatment period. ```r # Create basis vector for second post-period (size = numPostPeriods) l_vec_second <- HonestDiD::basisVector(index = 2, size = 2) # Returns: [0, 1] # Inference on second post-treatment period delta_rm_period2 <- HonestDiD::createSensitivityResults_relativeMagnitudes( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mbarvec = seq(0.5, 2, by = 0.5), l_vec = HonestDiD::basisVector(index = 2, size = 2) ) ``` -------------------------------- ### Implement honest_did for AGGTEobj Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Computes a sensitivity analysis for event study estimates when the input is an `AGGTEobj` from the `did` package. Requires a universal base period and checks for consecutive time periods. Supports 'smoothness' and 'relative_magnitude' types of analysis. ```r #' @title honest_did.AGGTEobj #' #' @description a function to compute a sensitivity analysis #' using the approach of Rambachan and Roth (2021) when #' the event study is estimating using the `did` package #' #' @param es Result from aggte (object of class AGGTEobj). #' @param e event time to compute the sensitivity analysis for. #' The default value is `e=0` corresponding to the "on impact" #' effect of participating in the treatment. #' @param type Options are "smoothness" (which conducts a #' sensitivity analysis allowing for violations of linear trends #' in pre-treatment periods) or "relative_magnitude" (which #' conducts a sensitivity analysis based on the relative magnitudes #' of deviations from parallel trends in pre-treatment periods). #' @param gridPoints Number of grid points used for the underlying test #' inversion. Default equals 100. User may wish to change the number of grid #' points for computational reasons. #' @param ... Parameters to pass to `createSensitivityResults` or #' `createSensitivityResults_relativeMagnitudes`. honest_did.AGGTEobj <- function(es, e = 0, type = c("smoothness", "relative_magnitude"), gridPoints = 100, ...) { type <- match.arg(type) # Make sure that user is passing in an event study if (es$type != "dynamic") { stop("need to pass in an event study") } # Check if used universal base period and warn otherwise if (es$DIDparams$base_period != "universal") { stop("Use a universal base period for honest_did") } # Recover influence function for event study estimates es_inf_func <- es$inf.function$dynamic.inf.func.e # Recover variance-covariance matrix n <- nrow(es_inf_func) V <- t(es_inf_func) %*% es_inf_func / n / n # Check time vector is consecutive with referencePeriod = -1 referencePeriod <- -1 consecutivePre <- !all(diff(es$egt[es$egt <= referencePeriod]) == 1) consecutivePost <- !all(diff(es$egt[es$egt >= referencePeriod]) == 1) if ( consecutivePre | consecutivePost ) { msg <- "honest_did expects a time vector with consecutive time periods;" msg <- paste(msg, "please re-code your event study and interpret the results accordingly.", sep="\n") stop(msg) } # Remove the coefficient normalized to zero hasReference <- any(es$egt == referencePeriod) if ( hasReference ) { referencePeriodIndex <- which(es$egt == referencePeriod) V <- V[-referencePeriodIndex,-referencePeriodIndex] beta <- es$att.egt[-referencePeriodIndex] } else { beta <- es$att.egt } nperiods <- nrow(V) npre <- sum(1*(es$egt < referencePeriod)) npost <- nperiods - npre if ( !hasReference & (min(c(npost, npre)) <= 0) ) { if ( npost <= 0 ) { msg <- "not enough post-periods" } else { msg <- "not enough pre-periods" } msg <- paste0(msg, " (check your time vector; note honest_did takes -1 as the reference period)") stop(msg) } baseVec1 <- basisVector(index=(e+1),size=npost) orig_ci <- constructOriginalCS(betahat = beta, sigma = V, numPrePeriods = npre, numPostPeriods = npost, l_vec = baseVec1) if (type=="relative_magnitude") { robust_ci <- createSensitivityResults_relativeMagnitudes(betahat = beta, sigma = V, numPrePeriods = npre, numPostPeriods = npost, l_vec = baseVec1, gridPoints = gridPoints, ...) } else if (type == "smoothness") { robust_ci <- createSensitivityResults(betahat = beta, sigma = V, numPrePeriods = npre, numPostPeriods = npost, l_vec = baseVec1, ...) } return(list(robust_ci=robust_ci, orig_ci=orig_ci, type=type)) } ``` -------------------------------- ### Extract Coefficients and Run Sensitivity Analysis (HonestDiD) Source: https://context7.com/asheshrambachan/honestdid/llms.txt Extracts coefficients and the variance-covariance matrix from a sunab object and performs sensitivity analysis using HonestDiD. ```r beta_vcv <- sunab_beta_vcv(res_sunab) sensitivity_results <- HonestDiD::createSensitivityResults_relativeMagnitudes( betahat = beta_vcv$beta, sigma = beta_vcv$sigma, numPrePeriods = sum(beta_vcv$cohorts < 0), numPostPeriods = sum(beta_vcv$cohorts > -1), Mbarvec = seq(0.5, 2, by = 0.5) ) ``` -------------------------------- ### Run CS Event Study and Sensitivity Analysis (did & HonestDiD) Source: https://context7.com/asheshrambachan/honestdid/llms.txt Runs a Callaway and Sant'Anna (CS) event study using the 'did' package and then performs sensitivity analysis with HonestDiD. Requires specifying the outcome, time, unit, and treatment group variables, along with control group and base period settings. ```r library(did) # Run CS event study with universal base period cs_results <- did::att_gt( yname = "dins", tname = "year", idname = "stfips", gname = "yexp2", data = df %>% mutate(yexp2 = ifelse(is.na(yexp2), 3000, yexp2)), control_group = "notyettreated", base_period = "universal" ) es <- did::aggte(cs_results, type = "dynamic", min_e = -5, max_e = 5) # Extract variance-covariance matrix from influence function es_inf_func <- es$inf.function$dynamic.inf.func.e n <- nrow(es_inf_func) V <- t(es_inf_func) %*% es_inf_func / n / n # Remove reference period coefficient (normalized to 0) referencePeriod <- -1 referencePeriodIndex <- which(es$egt == referencePeriod) V <- V[-referencePeriodIndex, -referencePeriodIndex] beta <- es$att.egt[-referencePeriodIndex] npre <- sum(es$egt < referencePeriod) npost <- length(beta) - npre # Run sensitivity analysis sensitivity_results <- HonestDiD::createSensitivityResults_relativeMagnitudes( betahat = beta, sigma = V, numPrePeriods = npre, numPostPeriods = npost, Mbarvec = seq(0.5, 2, by = 0.5) ) ``` -------------------------------- ### Handle Regressions with Controls using fixest Source: https://context7.com/asheshrambachan/honestdid/llms.txt Estimates a TWFE regression with controls using the 'fixest' package and prepares the coefficients and covariance matrix for HonestDiD sensitivity analysis. Requires specifying the outcome, time, unit, and control variables, and identifying the position of the control variable in the coefficient summary. ```r # TWFE with controls twfe_with_controls <- fixest::feols( dins ~ i(year, D, ref = 2013) + control_var | stfips + year, cluster = "stfips", data = df_nonstaggered ) betahat_full <- summary(twfe_with_controls)$coefficients sigma_full <- summary(twfe_with_controls)$cov.scaled # Identify position of control variable (e.g., position 8) control_position <- 8 # Subset to event-study coefficients only betahat <- betahat_full[-control_position] sigma <- sigma_full[-control_position, -control_position] # Now use with HonestDiD functions results <- HonestDiD::createSensitivityResults( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mvec = seq(0, 0.05, by = 0.01) ) ``` -------------------------------- ### Plot Sensitivity Analysis (Smoothness Restrictions) Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Visualizes the sensitivity analysis results obtained from `createSensitivityResults` with smoothness restrictions. Requires both the sensitivity results and the original OLS results. ```r createSensitivityPlot(delta_sd_results, originalResults) ``` -------------------------------- ### createEventStudyPlot Source: https://context7.com/asheshrambachan/honestdid/llms.txt Creates an event study plot with coefficient estimates and confidence intervals. ```APIDOC ## createEventStudyPlot ### Description Creates an event study plot with coefficient estimates and confidence intervals. ### Method HonestDiD::createEventStudyPlot ### Parameters #### Request Body - **betahat** (numeric vector) - Required - Point estimates of the treatment effect for each time period. - **sigma** (matrix) - Required - Variance-covariance matrix of the estimates. - **numPrePeriods** (integer) - Required - Number of pre-treatment periods. - **numPostPeriods** (integer) - Required - Number of post-treatment periods. - **alpha** (numeric) - Required - Significance level for the confidence intervals. - **timeVec** (numeric vector) - Optional - Vector of time points for the event study. - **referencePeriod** (numeric) - Optional - The reference period for the event study. - **useRelativeEventTime** (logical) - Optional - Whether to use relative event time. ``` -------------------------------- ### createSensitivityPlot_relativeMagnitudes Source: https://context7.com/asheshrambachan/honestdid/llms.txt Creates a visualization for relative magnitudes sensitivity analysis, showing how confidence intervals change as Mbar varies. ```APIDOC ## createSensitivityPlot_relativeMagnitudes ### Description Creates a visualization for relative magnitudes sensitivity analysis, showing how confidence intervals change as Mbar varies. ### Method HonestDiD::createSensitivityPlot_relativeMagnitudes ### Parameters #### Request Body - **robustResults** (object) - Required - Results from a robustness check. - **originalResults** (object) - Required - Original estimation results. ``` -------------------------------- ### Plot Sensitivity Analysis (Relative Magnitudes) Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Visualizes the sensitivity analysis results obtained from `createSensitivityResults_relativeMagnitudes`. Requires both the sensitivity results and the original OLS results. ```r HonestDiD::createSensitivityPlot_relativeMagnitudes(delta_rm_results, originalResults) ``` -------------------------------- ### Run Fixest Regression with Sunab and Plot Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md This R code demonstrates how to run a 'fixest' regression using the 'sunab' option to define aggregated event study periods. It then visualizes the results using 'fixest::iplot'. Ensure the 'df' data frame and 'year_treated' variable are correctly defined. ```r # Run fixest with sunab df$year_treated <- ifelse(is.na(df$yexp2), Inf, df$yexp2) formula_sunab <- dins ~ sunab(year_treated, year) | stfips + year res_sunab <- fixest::feols(formula_sunab, cluster="stfips", data=df) fixest::iplot(res_sunab) ``` -------------------------------- ### Create Sensitivity Results (Smoothness Restrictions) Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Calculates robust confidence intervals for DiD estimates by imposing smoothness restrictions on the trend changes between periods. Requires pre-calculated coefficients and covariance matrix. ```r delta_sd_results <- HonestDiD::createSensitivityResults(betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mvec = seq(from = 0, to = 0.05, by =0.01)) delta_sd_results ``` -------------------------------- ### Sensitivity Analysis for Event Study Magnitudes Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md This R code performs sensitivity analysis on event study results extracted using the 'sunab_beta_vcv' function. It constructs the original results and then generates sensitivity results for relative magnitudes using 'HonestDiD'. The 'kwargs' list should contain 'betahat', 'sigma', 'numPrePeriods', and 'numPostPeriods'. ```r # Extract the beta and vcv beta_vcv <- sunab_beta_vcv(res_sunab) # Run sensitivity analysis for relative magnitudes kwargs <- list(betahat = beta_vcv$beta, sigma = beta_vcv$sigma, numPrePeriods = sum(beta_vcv$cohorts < 0), numPostPeriods = sum(beta_vcv$cohorts > -1)) extra <- list(Mbarvec=seq(from = 0.5, to = 2, by = 0.5), gridPoints=100) original_results <- do.call(HonestDiD::constructOriginalCS, kwargs) sensitivity_results <- do.call(HonestDiD::createSensitivityResults_relativeMagnitudes, c(kwargs, extra)) HonestDiD::createSensitivityPlot_relativeMagnitudes(sensitivity_results, original_results) ``` -------------------------------- ### Create Relative Magnitudes Sensitivity Plot Source: https://context7.com/asheshrambachan/honestdid/llms.txt Generates a visualization to assess how confidence intervals change with variations in Mbar for relative magnitudes sensitivity analysis. ```r # Create sensitivity plot for relative magnitudes HonestDiD::createSensitivityPlot_relativeMagnitudes( robustResults = delta_rm_results, originalResults = originalResults ) ``` -------------------------------- ### Create Sensitivity Results (Relative Magnitudes) Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Calculates robust confidence intervals for DiD estimates under varying assumptions about the magnitude of parallel trend violations. Requires pre-calculated coefficients and covariance matrix. ```r delta_rm_results <- HonestDiD::createSensitivityResults_relativeMagnitudes( betahat = betahat, #coefficients sigma = sigma, #covariance matrix numPrePeriods = 5, #num. of pre-treatment coefs numPostPeriods = 2, #num. of post-treatment coefs Mbarvec = seq(0.5,2,by=0.5) #values of Mbar ) delta_rm_results ``` -------------------------------- ### Find Optimal Fixed-Length Confidence Interval (FLCI) Source: https://context7.com/asheshrambachan/honestdid/llms.txt Computes the optimal FLCI that minimizes the worst-case length across a specified Delta set. This is recommended for smoothness restrictions. ```r # Find optimal FLCI for M = 0.02 flci_result <- HonestDiD::findOptimalFLCI( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, M = 0.02, alpha = 0.05 ) # Access results flci_result$FLCI # [lower_bound, upper_bound] flci_result$optimalVec # Optimal weighting vector flci_result$optimalHalfLength # Half-length of CI ``` -------------------------------- ### basisVector Source: https://context7.com/asheshrambachan/honestdid/llms.txt Creates a basis vector for specifying which post-treatment period to analyze. By default, inference is on the first post-treatment period. ```APIDOC ## basisVector ### Description Creates a basis vector for specifying which post-treatment period to analyze. By default, inference is on the first post-treatment period. ### Method HonestDiD::basisVector ### Parameters #### Request Body - **index** (integer) - Required - The index of the post-treatment period to analyze. - **size** (integer) - Required - The total number of post-treatment periods. ``` -------------------------------- ### Extract Beta and VCV from Sun & Abraham (fixest) Source: https://context7.com/asheshrambachan/honestdid/llms.txt A helper function to extract aggregated beta coefficients and their variance-covariance matrix from a Sun & Abraham model estimated with fixest. ```r # Helper function to extract beta and vcv from sunab sunab_beta_vcv <- function(sunab_fixest) { sunab_agg <- sunab_fixest$model_matrix_info$sunab$agg_period sunab_names <- names(sunab_fixest$coefficients) sunab_sel <- grepl(sunab_agg, sunab_names, perl = TRUE) sunab_names <- sunab_names[sunab_sel] if (!is.null(sunab_fixest$weights)) { sunab_wgt <- colSums(sunab_fixest$weights * sign(model.matrix(sunab_fixest)[, sunab_names, drop = FALSE])) } else { sunab_wgt <- colSums(sign(model.matrix(sunab_fixest)[, sunab_names, drop = FALSE])) } sunab_cohorts <- as.numeric(gsub(paste0(".*", sunab_agg, ".*"), "\2", sunab_names, perl = TRUE)) sunab_mat <- model.matrix(~ 0 + factor(sunab_cohorts)) sunab_trans <- solve(t(sunab_mat) %*% (sunab_wgt * sunab_mat)) %*% t(sunab_wgt * sunab_mat) sunab_coefs <- sunab_trans %*% cbind(sunab_fixest$coefficients[sunab_sel]) sunab_vcov <- sunab_trans %*% sunab_fixest$cov.scaled[sunab_sel, sunab_sel] %*% t(sunab_trans) list(beta = sunab_coefs, sigma = sunab_vcov, cohorts = sort(unique(sunab_cohorts))) } ``` -------------------------------- ### Add Shape and Sign Restrictions to Sensitivity Analysis Source: https://context7.com/asheshrambachan/honestdid/llms.txt Demonstrates adding monotonicity and sign restrictions to sensitivity analyses using HonestDiD. Specify the direction for monotonicity ('increasing' or 'decreasing') or bias ('positive' or 'negative'). ```r # Smoothness with monotonicity restriction (increasing trend) results_monotonic <- HonestDiD::createSensitivityResults( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mvec = seq(0, 0.05, by = 0.01), monotonicityDirection = "increasing" # or "decreasing" ) # Relative magnitudes with sign restriction (positive bias) results_signed <- HonestDiD::createSensitivityResults_relativeMagnitudes( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mbarvec = seq(0.5, 2, by = 0.5), biasDirection = "positive" # or "negative" ) ``` -------------------------------- ### Estimate Baseline DiD with TWFE in R Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Filters data to a specific time frame, creates a treatment dummy, and runs a two-way fixed effects regression. The results are saved for further analysis and plotting. ```r df <- read_dta("https://raw.githubusercontent.com/Mixtape-Sessions/Advanced-DID/main/Exercises/Data/ehec_data.dta") #Keep years before 2016. Drop the 2016 cohort df_nonstaggered <- df %>% filter(year < 2016 & (is.na(yexp2)| yexp2 != 2015) ) #Create a treatment dummy df_nonstaggered <- df_nonstaggered %>% mutate(D = case_when( yexp2 == 2014 ~ 1, T ~ 0)) #Run the TWFE spec twfe_results <- fixest::feols(dins ~ i(year, D, ref = 2013) | stfips + year, cluster = "stfips", data = df_nonstaggered) betahat <- summary(twfe_results)$coefficients #save the coefficients sigma <- summary(twfe_results)$cov.scaled #save the covariance matrix fixest::iplot(twfe_results) ``` -------------------------------- ### Create Event Study Plot Source: https://context7.com/asheshrambachan/honestdid/llms.txt Generates an event study plot displaying coefficient estimates and their confidence intervals. ```r # Create event study plot HonestDiD::createEventStudyPlot( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, alpha = 0.05, timeVec = c(-5, -4, -3, -2, -1, 1, 2), referencePeriod = 0, useRelativeEventTime = TRUE ) ``` -------------------------------- ### Construct Original Confidence Intervals Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Calculates the original confidence intervals for DiD estimates based on OLS results. This is a prerequisite for plotting sensitivity analyses. ```r originalResults <- HonestDiD::constructOriginalCS(betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2) ``` -------------------------------- ### Create Sensitivity Analysis Plot Source: https://context7.com/asheshrambachan/honestdid/llms.txt Generates a plot visualizing sensitivity analysis results, comparing original and robust confidence intervals across different smoothness parameter (M) values. Can be used with rescaling and axis limits. ```r # Create sensitivity plot for smoothness restrictions HonestDiD::createSensitivityPlot( robustResults = delta_sd_results, originalResults = originalResults ) # With rescaling (e.g., to percentage points) HonestDiD::createSensitivityPlot( robustResults = delta_sd_results, originalResults = originalResults, rescaleFactor = 100, # Convert to percentage points maxM = 0.04 # Limit x-axis ) ``` -------------------------------- ### Construct Original Confidence Set (Parallel Trends Assumption) Source: https://context7.com/asheshrambachan/honestdid/llms.txt Constructs the original, non-robust confidence set under the standard parallel trends assumption. This serves as a baseline for comparison with robust confidence intervals. Can be used for average effects by specifying weights in l_vec. ```r # Construct original confidence set under parallel trends originalResults <- HonestDiD::constructOriginalCS( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2 ) # For average effect across post-periods originalResults_avg <- HonestDiD::constructOriginalCS( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, l_vec = c(0.5, 0.5) # Equal weights for averaging ) ``` -------------------------------- ### Create Sensitivity Plot for Relative Magnitudes Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md This code generates a plot to visualize the results of the relative magnitude sensitivity analysis. It uses the `createSensitivityPlot_relativeMagnitudes` function from the `HonestDiD` package, taking the robust and original confidence intervals as input. ```R HonestDiD::createSensitivityPlot_relativeMagnitudes(sensitivity_results$robust_ci, sensitivity_results$orig_ci) ``` -------------------------------- ### Compute Upper Bound for M (DeltaSD) Source: https://context7.com/asheshrambachan/honestdid/llms.txt Calculates an upper bound for M based on pre-period data, useful for determining a reasonable range for M values in sensitivity analysis. ```r # Get upper bound for M from pre-periods Mub <- HonestDiD::DeltaSD_upperBound_Mpre( betahat = betahat, sigma = sigma, numPrePeriods = 5, alpha = 0.05 ) # Use to create Mvec grid Mvec <- seq(from = 0, to = Mub, length.out = 10) ``` -------------------------------- ### Create Robust Confidence Intervals with Relative Magnitudes Restrictions (Delta^RM) Source: https://context7.com/asheshrambachan/honestdid/llms.txt Constructs robust confidence intervals using relative magnitudes restrictions (Delta^RM). This method bounds post-treatment violations of parallel trends relative to the maximum pre-treatment violation. Requires pre-estimated coefficients and covariance matrix. ```r # Sensitivity analysis with relative magnitudes restrictions delta_rm_results <- HonestDiD::createSensitivityResults_relativeMagnitudes( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mbarvec = seq(0.5, 2, by = 0.5) ) # Output: # lb ub method Delta Mbar # 0.0241 0.0673 C-LF DeltaRM 0.5 # 0.0171 0.0720 C-LF DeltaRM 1 # 0.00859 0.0796 C-LF DeltaRM 1.5 # -0.00107 0.0883 C-LF DeltaRM 2 ``` -------------------------------- ### Aggregate Difference-in-Differences Results Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md This code aggregates the results from the `att_gt` estimation using the `aggte` function. It specifies a 'dynamic' type of aggregation and sets the minimum and maximum event times for the aggregation. ```R es <- did::aggte(cs_results, type = "dynamic", min_e = -5, max_e = 5) ``` -------------------------------- ### Run Difference-in-Differences Estimation Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md This code performs a difference-in-differences estimation using the `att_gt` function from the `did` package. It requires specifying the outcome variable, time variable, unit ID variable, and treatment group variable. The `base_period` is set to 'universal' for normalization. ```R cs_results <- did::att_gt(yname = "dins", tname = "year", idname = "stfips", gname = "yexp2", data = df %>% mutate(yexp2 = ifelse(is.na(yexp2), 3000, yexp2)) , control_group = "notyettreated", base_period = "universal") ``` -------------------------------- ### Extract Sunab Event Study Coefficients and VCV Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md This R function extracts aggregated event-study coefficients and their variance-covariance matrix from a 'fixest' regression that used the 'sunab' option. It requires the 'fixest' regression object as input and returns a list containing the coefficients ('beta'), the variance-covariance matrix ('sigma'), and the corresponding cohorts ('cohorts'). ```r sunab_beta_vcv <- function(sunab_fixest){ ## The following code block extracts the weights on individual coefs used in # the fixest aggregation ## sunab_agg <- sunab_fixest$model_matrix_info$sunab$agg_period sunab_names <- base::names(sunab_fixest$coefficients) sunab_sel <- base::grepl(sunab_agg, sunab_names, perl=TRUE) sunab_names <- sunab_names[sunab_sel] if(!base::is.null(sunab_fixest$weights)){ sunab_wgt <- base::colSums(sunab_fixest$weights * base::sign(stats::model.matrix(sunab_fixest)[, sunab_names, drop=FALSE])) } else { sunab_wgt <- base::colSums(base::sign(stats::model.matrix(sunab_fixest)[, sunab_names, drop=FALSE])) } #Construct matrix sunab_trans such that sunab_trans %*% non-aggregated coefs = aggregated coefs, sunab_cohorts <- base::as.numeric(base::gsub(base::paste0(".*", sunab_agg, ".*"), "\\2", sunab_names, perl=TRUE)) sunab_mat <- stats::model.matrix(~ 0 + base::factor(sunab_cohorts)) sunab_trans <- base::solve(base::t(sunab_mat) %*% (sunab_wgt * sunab_mat)) %*% base::t(sunab_wgt * sunab_mat) #Get the coefs and vcv sunab_coefs <- sunab_trans %*% base::cbind(sunab_fixest$coefficients[sunab_sel]) sunab_vcov <- sunab_trans %*% sunab_fixest$cov.scaled[sunab_sel, sunab_sel] %*% base::t(sunab_trans) base::return(base::list(beta = sunab_coefs, sigma = sunab_vcov, cohorts = base::sort(base::unique(sunab_cohorts)))) } ``` -------------------------------- ### Run Sensitivity Analysis for Relative Magnitudes Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md This code performs a sensitivity analysis using the `honest_did` function to assess the robustness of the aggregated difference-in-differences results to potential unobserved confounders. It specifically focuses on 'relative_magnitude' and tests a range of multiplier values (Mbarvec). ```R sensitivity_results <- honest_did(es, e=0, type="relative_magnitude", Mbarvec=seq(from = 0.5, to = 2, by = 0.5)) ``` -------------------------------- ### Define honest_did Generic Function Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md Defines the generic `honest_did` function for sensitivity analysis. It uses `UseMethod` to dispatch to specific methods based on the input object type. ```r #' @title honest_did #' #' @description a function to compute a sensitivity analysis #' using the approach of Rambachan and Roth (2021) #' #' @param ... Parameters to pass to the relevant method. honest_did <- function(...) UseMethod("honest_did") ``` -------------------------------- ### findOptimalFLCI Source: https://context7.com/asheshrambachan/honestdid/llms.txt Computes the optimal Fixed-Length Confidence Interval (FLCI) that minimizes worst-case length over a specified Delta set. This is the recommended method for smoothness restrictions. ```APIDOC ## findOptimalFLCI ### Description Computes the optimal Fixed-Length Confidence Interval (FLCI) that minimizes worst-case length over a specified Delta set. This is the recommended method for smoothness restrictions. ### Method HonestDiD::findOptimalFLCI ### Parameters #### Request Body - **betahat** (numeric vector) - Required - Point estimate of the treatment effect. - **sigma** (matrix) - Required - Variance-covariance matrix of the estimates. - **numPrePeriods** (integer) - Required - Number of pre-treatment periods. - **numPostPeriods** (integer) - Required - Number of post-treatment periods. - **M** (numeric) - Required - The maximum allowable bias magnitude. - **alpha** (numeric) - Required - Significance level for the confidence interval. ### Response #### Success Response (200) - **FLCI** (numeric vector) - The lower and upper bounds of the FLCI. - **optimalVec** (numeric vector) - The optimal weighting vector. - **optimalHalfLength** (numeric) - The half-length of the optimal FLCI. ``` -------------------------------- ### Create Robust Confidence Intervals with Smoothness Restrictions (Delta^SD) Source: https://context7.com/asheshrambachan/honestdid/llms.txt Constructs robust confidence intervals using smoothness restrictions (Delta^SD). This method bounds how much the slope of differential trends can change between consecutive periods. Requires pre-estimated coefficients and covariance matrix from a TWFE event study. ```r library(HonestDiD) library(fixest) library(haven) library(dplyr) # Load Medicaid expansion data df <- read_dta("https://raw.githubusercontent.com/Mixtape-Sessions/Advanced-DID/main/Exercises/Data/ehec_data.dta") # Prepare non-staggered sample df_nonstaggered <- df %>% filter(year < 2016 & (is.na(yexp2) | yexp2 != 2015)) %>% mutate(D = case_when(yexp2 == 2014 ~ 1, TRUE ~ 0)) # Run TWFE event study twfe_results <- fixest::feols( dins ~ i(year, D, ref = 2013) | stfips + year, cluster = "stfips", data = df_nonstaggered ) # Extract coefficients and covariance matrix betahat <- summary(twfe_results)$coefficients sigma <- summary(twfe_results)$cov.scaled # Sensitivity analysis with smoothness restrictions delta_sd_results <- HonestDiD::createSensitivityResults( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mvec = seq(from = 0, to = 0.05, by = 0.01) ) # Output: # lb ub method Delta M # 0.0259 0.0607 FLCI DeltaSD 0 # 0.0132 0.0787 FLCI DeltaSD 0.01 # 0.00286 0.0907 FLCI DeltaSD 0.02 # -0.00714 0.101 FLCI DeltaSD 0.03 # -0.0171 0.111 FLCI DeltaSD 0.04 # -0.0271 0.121 FLCI DeltaSD 0.05 ``` -------------------------------- ### Handling Controls in TWFE Regressions with R Source: https://github.com/asheshrambachan/honestdid/blob/master/README.md When regressions include control variables, subset `betahat` and `sigma` to exclude coefficients and covariance entries related to these controls. This ensures that HonestDiD uses only the event-study coefficients. ```r # CREATE A FAKE CONTROL FOR ILLUSTRATION set.seed(0) df_nonstaggered$control <- rnorm(NROW(df_nonstaggered), 0, 1) #Run the TWFE spec with the control added # (Note that TWFEs with controls may not yield ATT under het effects; see Abadie 2005) twfe_results <- fixest::feols(dins ~ i(year, D, ref = 2013) + control | stfips + year, cluster = "stfips", data = df_nonstaggered) betahat <- summary(twfe_results)$coefficients #save the coefficients sigma <- summary(twfe_results)$cov.scaled #save the covariance matrix #Subset the coefficients to exclude the control, which here is in position 8 betahat <- betahat[-8] sigma <-sigma[-8,-8] HonestDiD::createSensitivityResults(betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mvec = seq(from = 0, to = 0.05, by =0.01)) ``` -------------------------------- ### Compute Conditional Confidence Set (DeltaRM) Source: https://context7.com/asheshrambachan/honestdid/llms.txt Computes conditional confidence sets specifically for relative magnitudes restrictions using test inversion. ```r # Compute conditional confidence set with relative magnitudes conditional_cs_rm <- HonestDiD::computeConditionalCS_DeltaRM( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, Mbar = 1.0, alpha = 0.05, hybrid_flag = "LF", gridPoints = 1000 ) ``` -------------------------------- ### Compute Conditional Confidence Set (DeltaSD) Source: https://context7.com/asheshrambachan/honestdid/llms.txt Calculates conditional confidence sets for smoothness restrictions using test inversion. Supports hybrid methods like 'ARP', 'FLCI', and 'LF'. ```r # Compute conditional confidence set conditional_cs <- HonestDiD::computeConditionalCS_DeltaSD( betahat = betahat, sigma = sigma, numPrePeriods = 5, numPostPeriods = 2, M = 0.02, alpha = 0.05, hybrid_flag = "FLCI", # Options: "ARP", "FLCI", "LF" gridPoints = 1000 ) # Extract confidence interval bounds lb <- min(conditional_cs$grid[conditional_cs$accept == 1]) ub <- max(conditional_cs$grid[conditional_cs$accept == 1]) ```