You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix tutorial 07: use correct post_periods for event study
The notebook was passing all periods (pre and post) as post_periods
to MultiPeriodDiD, causing HonestDiD to fail with "No pre-period
effects found" since the results had no pre-period classification.
Fix: pass only actual post-treatment periods [5-9] to post_periods.
MultiPeriodDiD automatically estimates pre-period coefficients for
the event study, and HonestDiD can now correctly identify them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/tutorials/07_pretrends_power.ipynb
+4-81Lines changed: 4 additions & 81 deletions
Original file line number
Diff line number
Diff line change
@@ -131,28 +131,7 @@
131
131
"id": "cell-6",
132
132
"metadata": {},
133
133
"outputs": [],
134
-
"source": [
135
-
"# Fit event study with ALL periods (pre and post) relative to reference period\n",
136
-
"# For pre-trends power analysis, we need coefficients for pre-periods too\n",
137
-
"mp_did = MultiPeriodDiD()\n",
138
-
"\n",
139
-
"# Use period 4 as the reference period (last pre-period, excluded from estimation)\n",
140
-
"# Estimate coefficients for all other periods: 0, 1, 2, 3 (pre) and 5, 6, 7, 8, 9 (post)\n",
141
-
"all_estimation_periods = [0, 1, 2, 3, 5, 6, 7, 8, 9] # All except reference period 4\n",
142
-
"\n",
143
-
"event_results = mp_did.fit(\n",
144
-
" df,\n",
145
-
" outcome='outcome',\n",
146
-
" treatment='treated',\n",
147
-
" time='period',\n",
148
-
" post_periods=all_estimation_periods # Include all periods for full event study\n",
149
-
")\n",
150
-
"\n",
151
-
"# Note: For standard DiD analysis, we'd normally use post_periods=[5,6,7,8,9]\n",
152
-
"# But for pre-trends power analysis, we need pre-period coefficients too\n",
153
-
"\n",
154
-
"print(event_results.summary())"
155
-
]
134
+
"source": "# Fit event study with ALL periods (pre and post) relative to reference period\n# For pre-trends power analysis, we need coefficients for pre-periods too\nmp_did = MultiPeriodDiD()\n\n# Use period 4 as the reference period (last pre-period, excluded from estimation)\n# Specify post_periods as the actual post-treatment periods; MultiPeriodDiD\n# automatically estimates pre-period coefficients for the event study.\nevent_results = mp_did.fit(\n df,\n outcome='outcome',\n treatment='treated',\n time='period',\n post_periods=[5, 6, 7, 8, 9]\n)\n\nprint(event_results.summary())"
156
135
},
157
136
{
158
137
"cell_type": "code",
@@ -199,24 +178,7 @@
199
178
"id": "cell-10",
200
179
"metadata": {},
201
180
"outputs": [],
202
-
"source": [
203
-
"# Create a PreTrendsPower object\n",
204
-
"pt = PreTrendsPower(\n",
205
-
" alpha=0.05, # Significance level for pre-trends test\n",
206
-
" power=0.80, # Target power for MDV calculation\n",
207
-
" violation_type='linear' # Type of violation to consider\n",
208
-
")\n",
209
-
"\n",
210
-
"# Define the actual pre-treatment periods (those before treatment starts at period 5)\n",
211
-
"# These are the periods we want to analyze for pre-trends power\n",
212
-
"pre_treatment_periods = [0, 1, 2, 3]\n",
213
-
"\n",
214
-
"# Fit to the event study results, specifying which periods are pre-treatment\n",
215
-
"# This is needed because we estimated all periods as post_periods in the event study\n",
"source": "# Create a PreTrendsPower object\npt = PreTrendsPower(\n alpha=0.05, # Significance level for pre-trends test\n power=0.80, # Target power for MDV calculation\n violation_type='linear' # Type of violation to consider\n)\n\n# Define the actual pre-treatment periods (those before treatment starts at period 5)\n# These are the periods we want to analyze for pre-trends power\npre_treatment_periods = [0, 1, 2, 3]\n\n# Fit to the event study results, specifying which periods are pre-treatment\npt_results = pt.fit(event_results, pre_periods=pre_treatment_periods)\n\nprint(pt_results.summary())"
220
182
},
221
183
{
222
184
"cell_type": "markdown",
@@ -558,46 +520,7 @@
558
520
"id": "cell-30",
559
521
"metadata": {},
560
522
"outputs": [],
561
-
"source": [
562
-
"# Typical workflow for pre-trends power analysis\n",
563
-
"\n",
564
-
"# Step 1: Estimate event study with ALL periods (pre and post) relative to reference\n",
565
-
"# For pre-trends power analysis, we need pre-period coefficients\n",
566
-
"mp_did = MultiPeriodDiD()\n",
567
-
"\n",
568
-
"# Reference period is 4 (last pre-period)\n",
569
-
"# Estimate coefficients for periods 0, 1, 2, 3 (pre) and 5, 6, 7, 8, 9 (post)\n",
"print(f\"Robust 95% CI (M=MDV): [{honest_results.ci_lb:.3f}, {honest_results.ci_ub:.3f}]\")\n",
599
-
"print(f\"Conclusion: {'Effect is robust' if honest_results.is_significant else 'Effect may not be robust'}\")"
600
-
]
523
+
"source": "# Typical workflow for pre-trends power analysis\n\n# Step 1: Estimate event study with proper pre/post period classification\nmp_did = MultiPeriodDiD()\n\n# Specify actual post-treatment periods; pre-period coefficients are\n# estimated automatically by MultiPeriodDiD for the event study\npre_treatment_periods = [0, 1, 2, 3] # Define which are pre-treatment\n\nresults = mp_did.fit(\n df, \n outcome='outcome',\n treatment='treated', \n time='period',\n post_periods=[5, 6, 7, 8, 9]\n)\n\n# Step 2: Assess power of the pre-trends test \nprint(\"Step 2: Pre-Trends Power Analysis\")\npt = PreTrendsPower(alpha=0.05, power=0.80, violation_type='linear')\npt_results = pt.fit(results, pre_periods=pre_treatment_periods)\nprint(f\"MDV (80% power): {pt_results.mdv:.3f}\")\nprint(\"\")\n\n# Step 3: Interpret\nprint(\"Step 3: Interpretation\")\nprint(f\"Your pre-trends test could only detect violations >= {pt_results.mdv:.3f}\")\nprint(f\"Violations smaller than this would likely go undetected.\")\nprint(\"\")\n\n# Step 4: Connect to Honest DiD for robust inference\nprint(\"Step 4: Robust Inference with Honest DiD\")\nhonest = HonestDiD(method='smoothness', M=pt_results.mdv)\nhonest_results = honest.fit(results)\nprint(f\"Robust 95% CI (M=MDV): [{honest_results.ci_lb:.3f}, {honest_results.ci_ub:.3f}]\")\nprint(f\"Conclusion: {'Effect is robust' if honest_results.is_significant else 'Effect may not be robust'}\")"
0 commit comments