|
33 | 33 | "import pandas as pd\n", |
34 | 34 | "\n", |
35 | 35 | "from diff_diff import (\n", |
36 | | - " MultiPeriodDiD,\n", |
| 36 | + " TwoWayFixedEffects,\n", |
37 | 37 | " PreTrendsPower,\n", |
38 | 38 | " compute_pretrends_power,\n", |
39 | 39 | " compute_mdv,\n", |
|
131 | 131 | "id": "cell-6", |
132 | 132 | "metadata": {}, |
133 | 133 | "outputs": [], |
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())" |
| 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 | + "twfe = TwoWayFixedEffects()\n", |
| 138 | + "\n", |
| 139 | + "# Use period 4 as the reference period (last pre-period, excluded from estimation)\n", |
| 140 | + "# Specify post_periods as the actual post-treatment periods; the event-study mode\n", |
| 141 | + "# estimates one coefficient per other period, pre-periods included.\n", |
| 142 | + "event_results = twfe.fit(\n", |
| 143 | + " df,\n", |
| 144 | + " outcome='outcome',\n", |
| 145 | + " treatment='treated',\n", |
| 146 | + " unit='unit',\n", |
| 147 | + " time='period',\n", |
| 148 | + " event_study=True,\n", |
| 149 | + " post_periods=[5, 6, 7, 8, 9]\n", |
| 150 | + ")\n", |
| 151 | + "\n", |
| 152 | + "print(event_results.summary())" |
| 153 | + ] |
135 | 154 | }, |
136 | 155 | { |
137 | 156 | "cell_type": "code", |
|
520 | 539 | "id": "cell-30", |
521 | 540 | "metadata": {}, |
522 | 541 | "outputs": [], |
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'}\")" |
| 542 | + "source": [ |
| 543 | + "# Typical workflow for pre-trends power analysis\n", |
| 544 | + "\n", |
| 545 | + "# Step 1: Estimate event study with proper pre/post period classification\n", |
| 546 | + "twfe = TwoWayFixedEffects()\n", |
| 547 | + "\n", |
| 548 | + "# Specify actual post-treatment periods; the event-study mode estimates\n", |
| 549 | + "# the pre-period coefficients automatically\n", |
| 550 | + "pre_treatment_periods = [0, 1, 2, 3] # Define which are pre-treatment\n", |
| 551 | + "\n", |
| 552 | + "results = twfe.fit(\n", |
| 553 | + " df, \n", |
| 554 | + " outcome='outcome',\n", |
| 555 | + " treatment='treated', \n", |
| 556 | + " unit='unit',\n", |
| 557 | + " time='period',\n", |
| 558 | + " event_study=True,\n", |
| 559 | + " post_periods=[5, 6, 7, 8, 9]\n", |
| 560 | + ")\n", |
| 561 | + "\n", |
| 562 | + "# Step 2: Assess power of the pre-trends test \n", |
| 563 | + "print(\"Step 2: Pre-Trends Power Analysis\")\n", |
| 564 | + "pt = PreTrendsPower(alpha=0.05, power=0.80, violation_type='linear')\n", |
| 565 | + "pt_results = pt.fit(results, pre_periods=pre_treatment_periods)\n", |
| 566 | + "print(f\"MDV (80% power): {pt_results.mdv:.3f}\")\n", |
| 567 | + "print(\"\")\n", |
| 568 | + "\n", |
| 569 | + "# Step 3: Interpret\n", |
| 570 | + "print(\"Step 3: Interpretation\")\n", |
| 571 | + "print(f\"Your pre-trends test could only detect violations >= {pt_results.mdv:.3f}\")\n", |
| 572 | + "print(f\"Violations smaller than this would likely go undetected.\")\n", |
| 573 | + "print(\"\")\n", |
| 574 | + "\n", |
| 575 | + "# Step 4: Connect to Honest DiD for robust inference\n", |
| 576 | + "print(\"Step 4: Robust Inference with Honest DiD\")\n", |
| 577 | + "honest = HonestDiD(method='smoothness', M=pt_results.mdv)\n", |
| 578 | + "honest_results = honest.fit(results)\n", |
| 579 | + "print(f\"Robust 95% CI (M=MDV): [{honest_results.ci_lb:.3f}, {honest_results.ci_ub:.3f}]\")\n", |
| 580 | + "print(f\"Conclusion: {'Effect is robust' if honest_results.is_significant else 'Effect may not be robust'}\")" |
| 581 | + ] |
524 | 582 | }, |
525 | 583 | { |
526 | 584 | "cell_type": "markdown", |
|
0 commit comments