This tab shows why the estimand has to come before the estimator. The same DiD design can answer different economic questions depending on whether the target is the typical unit, the population total, or a level effect. With heavy-tailed outcomes, these estimands can differ sharply, and sometimes even imply effects with opposite signs. Use the sliders below to change the data-generating process and see how the true estimands and the estimated coefficients move.
The simulation creates a matched treated–control panel that simplifies the setting for educational purposes, isolating three ingredients: outcome concentration (the share of outcomes in the top decile), heterogeneous treatment effects (separate effects for the viral head and the long tail), and treatment-induced changes in variance (the proportional change in treated-unit volatility). Treated and control units have the same pre-period baseline levels by construction, so differences across estimators come from the estimand they target and how they weight the outcome distribution. For the case where treated and control units start at different levels, see the Levels-OLS bias map tab →
(pre-treatment distribution)
Each estimator targets a different estimand and applies a different implicit or explicit weighting scheme. Log(1+Y) OLS weights observations equally, so the many low-volume units dominate the estimate. Weighted log OLS uses explicit pre-period outcome shares. PPML weights through the predicted mean and is the natural estimator for the population-total percent effect. Levels OLS targets an effect in units of the outcome. When treatment also changes outcome variance, log-transformed specifications can introduce a bias and even reverse sign. Setting Δ variance to zero isolates the role of weighting and estimand choice.
The DGP carries over from Tab 1 — the treatment effects, the variance shift, the outcome concentration, and the panel structure are whatever the Tab 1 sliders currently say. This tab layers two additional choices on top, defined with their sliders below; their product is the levels-OLS bias.
Move the b and g sliders (or drag the ✕) to see how the bias changes.
Under common proportional growth g, absolute changes scale with baseline levels: a treated unit (1+b) times larger mechanically adds (1+b) times more under the no-treatment counterfactual, and a levels DiD attributes the difference to treatment. With balanced windows the bias is exactly [b/(1+b)] × [(Ḡpost − Ḡpre)/Ḡpost], with Ḡ the window-average growth factor; in this 10+10 design the trend-scale factor is 1 − (1+g)−10. Either parameter at zero closes the channel: matching on baseline levels shrinks b toward zero, and no common growth means no trend-scale factor. The bias is separate from the treatment effect and adds to the scaled levels estimate. Proportional estimators (PPML, log specifications) impose proportional counterfactual trends and carry no bias from this channel. See Roth & Sant’Anna (2023) on when parallel trends is sensitive to functional form.
The applet generates the data; the scripts estimate. The buttons below export the simulated panel for the current slider settings as a CSV file, and each code below (Python, R, and Julia) reads that file, runs the four specifications from Tabs 1 and 2, and prints estimates with confidence intervals. A reference panel for the default settings is bundled in the zip, and every script includes reference values for it, so you can verify your setup before swapping in your own export.
did_lab_replication.py (requires numpy, pandas, scipy, pyfixest — click to view)
did_lab_replication.R (requires fixest — click to view)
did_lab_replication.jl (requires DataFrames, FixedEffectModels, GLFixedEffectModels — click to view)
DGP and specification details
Balanced matched-pair panel. Each treated unit i has baseline b0i(1+b); its matched control has b0i, where b is the Tab 2 baseline-gap slider (b = 0 on Tab 1). The b0i sit at the midpoint quantiles of lognormal(0, σ²pop), and σpop is solved numerically on that quantile grid so the realized top-decile share of the total equals the “% of outcome in top decile” slider. Panel: 10 pre + 10 post periods. Outcomes: Yit = b0i·(1+g)t·(1+θi)Dit·εit·100, rounded to integer counts, with g the Tab 2 common-growth slider (g = 0 on Tab 1). θi equals the head slider for the top size decile and the tail slider for the rest. εit is mean-one multiplicative lognormal noise, eσZ−σ²/2, composed of a pair-common component (cv 0.12, shared by the two units of a pair in each period) and a unit-idiosyncratic component. Baseline total cv: σi = 0.3·(b0i/b0,med)−0.2, clipped to [0.12, 0.60]. Treatment multiplies the idiosyncratic component of treated-unit volatility by √(1+Δvar) in post periods, for all treated units; the pair-common component is unchanged. True estimands: typical-unit = equal-weighted mean of θi; population-total = baseline-weighted mean of θi. Specifications: every estimator uses unit and period fixed effects with a single Treat×Post regressor — OLS in levels, OLS on log(1+Y), weighted OLS on log(1+Y) with pre-period mean outcome weights, and Poisson pseudo-maximum-likelihood (log link, reported as eδ−1). Standard errors are CRV1, clustered by matched pair, with t critical values on pairs−1 degrees of freedom; two-way clustering by unit and pair is identical here because units are nested within pairs. The levels coefficient is reported as a percent of the treated pre-period mean multiplied by the control post/pre growth ratio, with a delta-method confidence interval. The Tab 2 bias surface is the exact probability limit [b/(1+b)] · [(Ḡpost−Ḡpre)/Ḡpost], with Ḡ the within-window mean of (1+g)t.