This week we pivot from describing data to using Stata as a tool for thinking about causal questions and research design. This forms the bridge between representing correlational relationships with tables and figures to estimating causal relationships with regression analysis.
This lecture focuses on:
- What a data generating process (DGP) is
- What identification means (and why it’s different from association)
- How simulations and conditional means help you reason about research design before we learn regression
The data generating process (DGP)
A data generating process is the (usually hidden) set of rules that create the data we observe.
Examples:
- Gravity is part of the DGP that generates data on falling objects
- Supply and demand are part of the DGP that generates price/quantity data
- In economics, preferences, technologies, policies, and constraints are pieces of a DGP
The DGP is the causal story that created the dataset. We don’t observe that story directly—we only observe the variables it leaves behind. Identification is the problem of deciding when the variation we do observe is enough to pin down the causal effect we care about.
Stata gives us a superpower here: we can simulate data from a DGP we choose, so that we actually know the truth. Then we can see when simple comparisons get the right answer and when they’re biased.
A simple DGP in Stata: fertilizer, soil, and yield
We’ll simulate a world where:
- Plots differ in soil quality
- Plots with better soil are more likely to adopt fertilizer
- Fertilizer increases yield
- Soil quality also increases yield
This is a classic confounding setup: soil quality is a common cause of both fertilizer use and yield.
A simple causal diagram (we’ll formalize these next lecture):
soil_quality → fert
soil_quality → yield
fert → yield
Simulating the DGP
* simulate a DGP with confounding
clear all
set seed 12345
set obs 2000
* unobserved soil quality (higher is better)
gen soil_q = rnormal(0, 1)
* fertilizer adoption: more likely on better plots
gen fert_latent = 0.5*soil_q + rnormal(0, 1)
gen fert = (fert_latent > 0)
label define fertlbl 0 "no fertilizer" 1 "fertilizer"
label values fert fertlbl
* true causal effect of fertilizer on yield is 0.5 tons/ha
* soil quality also matters
gen eps = rnormal(0, 1)
gen yield_lat = 2 + 0.5*fert + 1*soil_q + eps
gen yield = max(yield_lat, 0)
drop yield_lat
label var yield "yield (tons/ha)"
* peek at the data
sum soil_q fert yield
What the DGP implies (before looking at results)
- The true causal effect of fertilizer on yield is 0.5 (by construction)
- Soil quality affects yield (coefficient 1.0)
- Fertilizer is not randomly assigned: better soil → more fertilizer
If you ignore soil quality and just compare mean yield with and without fertilizer, you’re mixing:
- The causal effect of fertilizer
- Selection: good soil increases fertilizer use and yield
Identification vs raw associations
What happens if we just compare average yield across fertilizer status?
* naive difference in means
tabstat yield, by(fert) stat(mean n)
* compute difference in means manually using stored results
qui sum yield if fert == 0, meanonly
scalar y0 = r(mean)
qui sum yield if fert == 1, meanonly
scalar y1 = r(mean)
display "Naive diff-in-means (fert - no fert): " %9.3f (y1 - y0)
This gives you the association between fertilizer and yield. But it does not have to equal the causal effect (0.5). The gap is bias from confounding by soil quality.
Conditioning to reduce confounding
In this DGP, soil quality is the confounder. There is what is known as a backdoor path fert ← soil_q → yield. If we could hold soil quality fixed, we’d block that path (fert ← [soil_q] → yield) and be able to identify the causal effect of fertilizer on yield.
We can approximate this by comparing treated and untreated plots within soil quality groups (quartiles):
* create soil quality quartiles
xtile soil_q4 = soil_q, nq(4)
label define soilq4 1 "worst soil" 2 "low" 3 "high" 4 "best soil"
label values soil_q4 soilq4
* mean yield by fert within each soil quartile
bysort soil_q4 fert: ///
sum yield
A simple visual check
* conditional difference in means in a soil group
tabstat yield if soil_q4 == 2, by(fert) stat(mean n)
* graph
graph bar (mean) yield if soil_q4 == 2, over(fert) ///
ytitle("Mean yield") ///
title("Fertilizer vs no fertilizer within soil group 2")
Variation vs identifying variation
Two ideas:
- Variation: how a variable changes across observations
- Identification: using knowledge of the DGP to isolate variation that reveals the causal effect
In our simulation:
- There is variation in fertilizer and yield
- Some variation in fertilizer is driven by soil quality and is not identifying
- Conditioning on soil quality gets closer to identifying variation
Randomized experiments in Stata
Most economists believe that the cleanest research design is randomized treatment assignment:
- Treatment is randomly assigned by the researcher (say via a lottery)
- By construction, treatment is independent of pre-treatment characteristics
Here is the same yield model with randomized fertilizer:
* randomized treatment: fert independent of soil_q
clear all
set seed 9876
set obs 2000
gen soil_q = rnormal(0, 1)
* randomized fertilizer: 50% treated
gen u = runiform()
gen fert = (u < 0.5)
label define fertlbl 0 "control" 1 "treatment"
label values fert fertlbl
* same causal effect and same soil effect (truncate at 0)
gen eps = rnormal(0, 1)
gen yield_lat = 2 + 0.5*fert + 1*soil_q + eps
gen yield = max(yield_lat, 0)
drop yield_lat
* naive diff-in-means is now a valid causal estimate
tabstat yield, by(fert) stat(mean n)
In this world, the true causal effect is still 0.5, and the naive difference in means is a valid estimate (up to sampling noise).
Connecting to real data and upcoming topics
In this lecture we practiced:
- Using simulations to make DGPs concrete
- Seeing how identification depends on research design
- Using difference-in-means and conditional means to reason about confounding
Next week, regression with controls will automate conditioning. Later, FE, DiD, event studies, and IV are all about finding identifying variation when simple conditioning isn’t enough.
Summary
- Identification isolates the precise variation required to infer a causal effect.
- The Data Generating Process (DGP) is the theoretical structural model creating your observed data.
- A solid research design ensures you only estimate the pathway of interest, ignoring confounding variance.