Challenge 12 (Difference-in-Differences)
This challenge combines Difference-in-Differences with a Monte Carlo (MC) simulation and ridgeline plots to explore how measurement error attenuates regression estimates. The data is also from the Impact evaluations in data-scarce environments paper though it is a different dataset. By the end of the exercise you will have replicated Figure 2 in that paper. First, you will estimate a baseline model, add simulated noise to a continuous variable, and visualize the loss of statistical significance using joyplot.
Part 1 — Baseline Regression and Coefplot
- Download the
mc_data.dtadataset from the course webpage and then load it into Stata. - Regress yield on:
- the indicator variables for if the rice variety is swarna-sub1, is another modern variety, and is a traditional variety,
- the interactions between the three variety indicators and the flood indicators,
- the indicator for if the flood was greater than 12 days and that variable interacted with if the variety is swarna-sub1,
- fixed effects for group(block),
- and cluster standard errors at the village level.
- Store the results using
eststo baseline. - Use
coefplotto visualize the coefficients. Keep only the flood variables and the flood-variety interaction terms. Format the plot cleanly, include a vertical reference line at $0$, export it, and import it into your Overleaf document.
Part 2 — Monte Carlo Simulation (Measurement Error)
Now, we will test how robust the subfld coefficient is if we assume the continuous outcome variable (yield) is measured with error. To do this, we are going to use Stata’s custom program function. We will write a program that adds normally distributed noise to yield and then runs the same regression as in Part 12.1. We will then loop through different levels of noise and store the results. We’ve not dealt with programs before but it is covered in a lecture in week 6. [Note that the entire Monte Carlo simulation takes about 20 minutes to run on my machine.]
- Start by ensuring no other program is running using
capture program drop yld_reg. - Set up a
programcalledyld_regthat is anrclassprogram. Close the program usingend. - Within the program (between
programandend)- Create an argument (
args) that accepts a noise parameternp. - Calculate the mean and standard deviation of
yieldusingsumand save these as locals calledy_meanandy_sd. Multiply these bynpto get the error mean and standard deviation. Save these asl locals calledymmandysd. - Replace
yieldwithyieldplus some random noise that is normally distributed (rnormal()) with mean 0 and standard deviationysd. - Replace
yieldagain but this time setyield = 0ifyieldis less than 0. This is to ensure values of yield do not fall below 0. - Return a scalar called
meanthat is the mean ofyield. - Run the exact same baseline regression from Part 12.1.
- Create an argument (
- Now we will run the Monte Carlo simulation using a single loop. This goes after you’ve used
endto close the program.- Start by clearing memory and creating an empty temporary file (
building) to collect our results in. - The simulation will loop through noise levels from 0% to 10% by increments of 1%. Within the loop:
- Convert your loop index to a percentage (
local i = j/100). - Load the raw dataset (
use "$data/mc_data", clear) sosimulatebegins with a fresh copy of the data. - The
simulatecommand acts as an inner loop. It will run theyld_regprogram 5,000 times for the current noise level (reps(5000)), capturing the coefficients (_b), standard errors (_se), degrees of freedom (dfr), and returned mean (mean). - Because we purposefully don’t supply a
saving()option,simulatewill just overwrite our memory with a database of its 5,000 runs! We simply mark these specific results with our current noise parameter (gen noise =i’), append them into our emptybuildingtempfile, and save overbuilding` with the newly augmented list.
- Convert your loop index to a percentage (
- Start by clearing memory and creating an empty temporary file (
* prepare an empty file for results
clear
tempfile building
save `building', emptyok
* run mc simulations
set seed 5762
forvalues j = 0/10 {
local i = `j'/100
* load data and run simulation for current noise level
use "$data/mc_data.dta", clear
simulate _b _se dfr=(e(df_r)) mean=r(mean), ///
reps(5000): yld_reg `i'
* add noise indicator and append to master results file
gen noise = `i'
append using `building'
save `"`building'"', replace
}
- Now that we have a data set of all the results, let’s clean it up a bit.
- Rename
_eq2_dfrasdfrand rename_eq2_meanasmean. - Create a variable (
t_subfld) that holds the t-statistic for thesubfldcoefficient, calculated as_b_subfld / _se_subfld. - Create a variable (
p_subfld) that holds the two-tailed p-value for thesubfldcoefficient, calculated as2 * ttail(dfr, abs(t_subfld)). - Create a variable (
sig) that is equal to 1 ifp_subfldis less than or equal to 0.05, is 0 otherwise, and is missing whenp_subfldis missing. - To help with the visuals in the graphic, replace
noisewith 100 times itself. - Use the following loop to label the
noisevariable:
* label stuff for graph
capture label drop noise
forvalues i = 0/10 {
if `i' < 10 {
label define noise `i' "0.0`i'{&sigma}", add
}
else {
label define noise `i' "0.`i'{&sigma}", add
}
}
label values noise noise
How many regressions did we just run in total?
Part 3 — Visualize P-Value Attenuation
- Use
joyplotto visualize the distribution ofp_subfldgrouped by thenoiselevel. Include the following options to match the example plot exactly:- Add horizontal lines for each group using
yline. - Set the kernel density bandwidth to 0.01 using
bwid()and normalize the density curves so each group has equal height usingnorm(local). - Scale the density curves nicely using
rescaleand allow the density curves to overlap vertically up to 2 times usingoverlap(). - Set the transparency (alpha) of the curves to 60% using
alpha(). - Set the x-axis labels from 0 to 1 in increments of 0.1 using
xlabel(). - Set the x-axis title to “p-values” using
xtitle(). - Use the ‘crest’ color palette using
palette(). - Set the y-axis title to “Amount of Added Noise in Yield Measure” and add a right margin (
margin(r=4)) after the title but within theytitle()option. - Add a vertical line at 0.05 (
xline(0.05, lcolor(maroon))) so that we can see what portion of the distribution falls outside significance. - Use the
white_tableauscheme or similar to format the plot nicely.
- Add horizontal lines for each group using
- Export your ridgeline plot and import it into your Overleaf document.
Looking at your final ridgeline plot, as the amount of added noise to the yield measure increases, what happens to the distribution of p-values? At approximately what percentage of added noise do we entirely lose statistical significance at the 5% level?