diff-diff 1.2.1__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {diff_diff-1.2.1 → diff_diff-1.3.0}/PKG-INFO +141 -1
  2. {diff_diff-1.2.1 → diff_diff-1.3.0}/README.md +140 -0
  3. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/__init__.py +8 -0
  4. diff_diff-1.3.0/diff_diff/triple_diff.py +1300 -0
  5. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff.egg-info/PKG-INFO +141 -1
  6. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff.egg-info/SOURCES.txt +2 -0
  7. {diff_diff-1.2.1 → diff_diff-1.3.0}/pyproject.toml +1 -1
  8. diff_diff-1.3.0/tests/test_triple_diff.py +869 -0
  9. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/bacon.py +0 -0
  10. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/diagnostics.py +0 -0
  11. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/estimators.py +0 -0
  12. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/honest_did.py +0 -0
  13. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/power.py +0 -0
  14. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/prep.py +0 -0
  15. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/pretrends.py +0 -0
  16. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/results.py +0 -0
  17. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/staggered.py +0 -0
  18. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/sun_abraham.py +0 -0
  19. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/synthetic_did.py +0 -0
  20. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/twfe.py +0 -0
  21. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/utils.py +0 -0
  22. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff/visualization.py +0 -0
  23. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff.egg-info/dependency_links.txt +0 -0
  24. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff.egg-info/requires.txt +0 -0
  25. {diff_diff-1.2.1 → diff_diff-1.3.0}/diff_diff.egg-info/top_level.txt +0 -0
  26. {diff_diff-1.2.1 → diff_diff-1.3.0}/setup.cfg +0 -0
  27. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_bacon.py +0 -0
  28. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_diagnostics.py +0 -0
  29. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_estimators.py +0 -0
  30. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_honest_did.py +0 -0
  31. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_power.py +0 -0
  32. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_prep.py +0 -0
  33. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_pretrends.py +0 -0
  34. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_staggered.py +0 -0
  35. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_sun_abraham.py +0 -0
  36. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_utils.py +0 -0
  37. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_visualization.py +0 -0
  38. {diff_diff-1.2.1 → diff_diff-1.3.0}/tests/test_wild_bootstrap.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diff-diff
3
- Version: 1.2.1
3
+ Version: 1.3.0
4
4
  Summary: A library for Difference-in-Differences causal inference analysis
5
5
  Author: diff-diff contributors
6
6
  License-Expression: MIT
@@ -106,6 +106,7 @@ Signif. codes: '***' 0.001, '**' 0.01, '*' 0.05, '.' 0.1
106
106
  - **Panel data support**: Two-way fixed effects estimator for panel designs
107
107
  - **Multi-period analysis**: Event-study style DiD with period-specific treatment effects
108
108
  - **Staggered adoption**: Callaway-Sant'Anna (2021) and Sun-Abraham (2021) estimators for heterogeneous treatment timing
109
+ - **Triple Difference (DDD)**: Ortiz-Villavicencio & Sant'Anna (2025) estimators with proper covariate handling
109
110
  - **Synthetic DiD**: Combined DiD with synthetic control for improved robustness
110
111
  - **Event study plots**: Publication-ready visualization of treatment effects
111
112
  - **Parallel trends testing**: Multiple methods including equivalence tests
@@ -128,6 +129,8 @@ We provide Jupyter notebook tutorials in `docs/tutorials/`:
128
129
  | `04_parallel_trends.ipynb` | Testing parallel trends, equivalence tests, placebo tests, diagnostics |
129
130
  | `05_honest_did.ipynb` | Honest DiD sensitivity analysis, bounds, breakdown values, visualization |
130
131
  | `06_power_analysis.ipynb` | Power analysis, MDE, sample size calculations, simulation-based power |
132
+ | `07_pretrends_power.ipynb` | Pre-trends power analysis (Roth 2022), MDV, power curves |
133
+ | `08_triple_diff.ipynb` | Triple Difference (DDD) estimation with proper covariate handling |
131
134
 
132
135
  ## Data Preparation
133
136
 
@@ -901,6 +904,77 @@ print(f"Sun-Abraham ATT: {sa_results.overall_att:.3f}")
901
904
  # If results differ substantially, investigate heterogeneity
902
905
  ```
903
906
 
907
+ ### Triple Difference (DDD)
908
+
909
+ Triple Difference (DDD) is used when treatment requires satisfying two criteria: belonging to a treated **group** AND being in an eligible **partition**. The `TripleDifference` class implements the methodology from Ortiz-Villavicencio & Sant'Anna (2025), which correctly handles covariate adjustment (unlike naive implementations).
910
+
911
+ ```python
912
+ from diff_diff import TripleDifference, triple_difference
913
+
914
+ # Basic usage
915
+ ddd = TripleDifference(estimation_method='dr') # doubly robust (recommended)
916
+ results = ddd.fit(
917
+ data,
918
+ outcome='wages',
919
+ group='policy_state', # 1=state enacted policy, 0=control state
920
+ partition='female', # 1=women (affected by policy), 0=men
921
+ time='post' # 1=post-policy, 0=pre-policy
922
+ )
923
+
924
+ # View results
925
+ results.print_summary()
926
+ print(f"ATT: {results.att:.3f} (SE: {results.se:.3f})")
927
+
928
+ # With covariates (properly incorporated, unlike naive DDD)
929
+ results = ddd.fit(
930
+ data,
931
+ outcome='wages',
932
+ group='policy_state',
933
+ partition='female',
934
+ time='post',
935
+ covariates=['age', 'education', 'experience']
936
+ )
937
+ ```
938
+
939
+ **Estimation methods:**
940
+
941
+ | Method | Description | When to use |
942
+ |--------|-------------|-------------|
943
+ | `"dr"` | Doubly robust | Recommended. Consistent if either outcome or propensity model is correct |
944
+ | `"reg"` | Regression adjustment | Simple outcome regression with full interactions |
945
+ | `"ipw"` | Inverse probability weighting | When propensity score model is well-specified |
946
+
947
+ ```python
948
+ # Compare estimation methods
949
+ for method in ['reg', 'ipw', 'dr']:
950
+ est = TripleDifference(estimation_method=method)
951
+ res = est.fit(data, outcome='y', group='g', partition='p', time='t')
952
+ print(f"{method}: ATT={res.att:.3f} (SE={res.se:.3f})")
953
+ ```
954
+
955
+ **Convenience function:**
956
+
957
+ ```python
958
+ # One-liner estimation
959
+ results = triple_difference(
960
+ data,
961
+ outcome='wages',
962
+ group='policy_state',
963
+ partition='female',
964
+ time='post',
965
+ covariates=['age', 'education'],
966
+ estimation_method='dr'
967
+ )
968
+ ```
969
+
970
+ **Why use DDD instead of DiD?**
971
+
972
+ DDD allows for violations of parallel trends that are:
973
+ - Group-specific (e.g., economic shocks in treatment states)
974
+ - Partition-specific (e.g., trends affecting women everywhere)
975
+
976
+ As long as these biases are additive, DDD differences them out. The key assumption is that the *differential* trend between eligible and ineligible units would be the same across groups.
977
+
904
978
  ### Event Study Visualization
905
979
 
906
980
  Create publication-ready event study plots:
@@ -1696,6 +1770,60 @@ SunAbraham(
1696
1770
  | `print_summary(alpha)` | Print summary to stdout |
1697
1771
  | `to_dataframe(level)` | Convert to DataFrame ('event_study' or 'cohort') |
1698
1772
 
1773
+ ### TripleDifference
1774
+
1775
+ ```python
1776
+ TripleDifference(
1777
+ estimation_method='dr', # 'dr' (doubly robust), 'reg', or 'ipw'
1778
+ robust=True, # Use HC1 robust standard errors
1779
+ cluster=None, # Column for cluster-robust SEs
1780
+ alpha=0.05, # Significance level for CIs
1781
+ pscore_trim=0.01 # Propensity score trimming threshold
1782
+ )
1783
+ ```
1784
+
1785
+ **fit() Parameters:**
1786
+
1787
+ | Parameter | Type | Description |
1788
+ |-----------|------|-------------|
1789
+ | `data` | DataFrame | Input data |
1790
+ | `outcome` | str | Outcome variable column name |
1791
+ | `group` | str | Group indicator column (0/1): 1=treated group |
1792
+ | `partition` | str | Partition/eligibility indicator column (0/1): 1=eligible |
1793
+ | `time` | str | Time indicator column (0/1): 1=post-treatment |
1794
+ | `covariates` | list | Covariate column names for adjustment |
1795
+
1796
+ ### TripleDifferenceResults
1797
+
1798
+ **Attributes:**
1799
+
1800
+ | Attribute | Description |
1801
+ |-----------|-------------|
1802
+ | `att` | Average Treatment effect on the Treated |
1803
+ | `se` | Standard error of ATT |
1804
+ | `t_stat` | T-statistic |
1805
+ | `p_value` | P-value for H0: ATT = 0 |
1806
+ | `conf_int` | Tuple of (lower, upper) confidence bounds |
1807
+ | `n_obs` | Total number of observations |
1808
+ | `n_treated_eligible` | Obs in treated group & eligible partition |
1809
+ | `n_treated_ineligible` | Obs in treated group & ineligible partition |
1810
+ | `n_control_eligible` | Obs in control group & eligible partition |
1811
+ | `n_control_ineligible` | Obs in control group & ineligible partition |
1812
+ | `estimation_method` | Method used ('dr', 'reg', or 'ipw') |
1813
+ | `group_means` | Dict of cell means for diagnostics |
1814
+ | `pscore_stats` | Propensity score statistics (IPW/DR only) |
1815
+ | `is_significant` | Boolean for significance at alpha |
1816
+ | `significance_stars` | String of significance stars |
1817
+
1818
+ **Methods:**
1819
+
1820
+ | Method | Description |
1821
+ |--------|-------------|
1822
+ | `summary(alpha)` | Get formatted summary string |
1823
+ | `print_summary(alpha)` | Print summary to stdout |
1824
+ | `to_dict()` | Convert to dictionary |
1825
+ | `to_dataframe()` | Convert to pandas DataFrame |
1826
+
1699
1827
  ### HonestDiD
1700
1828
 
1701
1829
  ```python
@@ -2059,6 +2187,18 @@ This library implements methods from the following scholarly works:
2059
2187
 
2060
2188
  - **Arkhangelsky, D., Athey, S., Hirshberg, D. A., Imbens, G. W., & Wager, S. (2021).** "Synthetic Difference-in-Differences." *American Economic Review*, 111(12), 4088-4118. [https://doi.org/10.1257/aer.20190159](https://doi.org/10.1257/aer.20190159)
2061
2189
 
2190
+ ### Triple Difference (DDD)
2191
+
2192
+ - **Ortiz-Villavicencio, M., & Sant'Anna, P. H. C. (2025).** "Better Understanding Triple Differences Estimators." *Working Paper*. [https://arxiv.org/abs/2505.09942](https://arxiv.org/abs/2505.09942)
2193
+
2194
+ This paper shows that common DDD implementations (taking the difference between two DiDs, or applying three-way fixed effects regressions) are generally invalid when identification requires conditioning on covariates. The `TripleDifference` class implements their regression adjustment, inverse probability weighting, and doubly robust estimators.
2195
+
2196
+ - **Gruber, J. (1994).** "The Incidence of Mandated Maternity Benefits." *American Economic Review*, 84(3), 622-641. [https://www.jstor.org/stable/2118071](https://www.jstor.org/stable/2118071)
2197
+
2198
+ Classic paper introducing the Triple Difference design for policy evaluation.
2199
+
2200
+ - **Olden, A., & Møen, J. (2022).** "The Triple Difference Estimator." *The Econometrics Journal*, 25(3), 531-553. [https://doi.org/10.1093/ectj/utac010](https://doi.org/10.1093/ectj/utac010)
2201
+
2062
2202
  ### Parallel Trends and Pre-Trend Testing
2063
2203
 
2064
2204
  - **Roth, J. (2022).** "Pretest with Caution: Event-Study Estimates after Testing for Parallel Trends." *American Economic Review: Insights*, 4(3), 305-322. [https://doi.org/10.1257/aeri.20210236](https://doi.org/10.1257/aeri.20210236)
@@ -71,6 +71,7 @@ Signif. codes: '***' 0.001, '**' 0.01, '*' 0.05, '.' 0.1
71
71
  - **Panel data support**: Two-way fixed effects estimator for panel designs
72
72
  - **Multi-period analysis**: Event-study style DiD with period-specific treatment effects
73
73
  - **Staggered adoption**: Callaway-Sant'Anna (2021) and Sun-Abraham (2021) estimators for heterogeneous treatment timing
74
+ - **Triple Difference (DDD)**: Ortiz-Villavicencio & Sant'Anna (2025) estimators with proper covariate handling
74
75
  - **Synthetic DiD**: Combined DiD with synthetic control for improved robustness
75
76
  - **Event study plots**: Publication-ready visualization of treatment effects
76
77
  - **Parallel trends testing**: Multiple methods including equivalence tests
@@ -93,6 +94,8 @@ We provide Jupyter notebook tutorials in `docs/tutorials/`:
93
94
  | `04_parallel_trends.ipynb` | Testing parallel trends, equivalence tests, placebo tests, diagnostics |
94
95
  | `05_honest_did.ipynb` | Honest DiD sensitivity analysis, bounds, breakdown values, visualization |
95
96
  | `06_power_analysis.ipynb` | Power analysis, MDE, sample size calculations, simulation-based power |
97
+ | `07_pretrends_power.ipynb` | Pre-trends power analysis (Roth 2022), MDV, power curves |
98
+ | `08_triple_diff.ipynb` | Triple Difference (DDD) estimation with proper covariate handling |
96
99
 
97
100
  ## Data Preparation
98
101
 
@@ -866,6 +869,77 @@ print(f"Sun-Abraham ATT: {sa_results.overall_att:.3f}")
866
869
  # If results differ substantially, investigate heterogeneity
867
870
  ```
868
871
 
872
+ ### Triple Difference (DDD)
873
+
874
+ Triple Difference (DDD) is used when treatment requires satisfying two criteria: belonging to a treated **group** AND being in an eligible **partition**. The `TripleDifference` class implements the methodology from Ortiz-Villavicencio & Sant'Anna (2025), which correctly handles covariate adjustment (unlike naive implementations).
875
+
876
+ ```python
877
+ from diff_diff import TripleDifference, triple_difference
878
+
879
+ # Basic usage
880
+ ddd = TripleDifference(estimation_method='dr') # doubly robust (recommended)
881
+ results = ddd.fit(
882
+ data,
883
+ outcome='wages',
884
+ group='policy_state', # 1=state enacted policy, 0=control state
885
+ partition='female', # 1=women (affected by policy), 0=men
886
+ time='post' # 1=post-policy, 0=pre-policy
887
+ )
888
+
889
+ # View results
890
+ results.print_summary()
891
+ print(f"ATT: {results.att:.3f} (SE: {results.se:.3f})")
892
+
893
+ # With covariates (properly incorporated, unlike naive DDD)
894
+ results = ddd.fit(
895
+ data,
896
+ outcome='wages',
897
+ group='policy_state',
898
+ partition='female',
899
+ time='post',
900
+ covariates=['age', 'education', 'experience']
901
+ )
902
+ ```
903
+
904
+ **Estimation methods:**
905
+
906
+ | Method | Description | When to use |
907
+ |--------|-------------|-------------|
908
+ | `"dr"` | Doubly robust | Recommended. Consistent if either outcome or propensity model is correct |
909
+ | `"reg"` | Regression adjustment | Simple outcome regression with full interactions |
910
+ | `"ipw"` | Inverse probability weighting | When propensity score model is well-specified |
911
+
912
+ ```python
913
+ # Compare estimation methods
914
+ for method in ['reg', 'ipw', 'dr']:
915
+ est = TripleDifference(estimation_method=method)
916
+ res = est.fit(data, outcome='y', group='g', partition='p', time='t')
917
+ print(f"{method}: ATT={res.att:.3f} (SE={res.se:.3f})")
918
+ ```
919
+
920
+ **Convenience function:**
921
+
922
+ ```python
923
+ # One-liner estimation
924
+ results = triple_difference(
925
+ data,
926
+ outcome='wages',
927
+ group='policy_state',
928
+ partition='female',
929
+ time='post',
930
+ covariates=['age', 'education'],
931
+ estimation_method='dr'
932
+ )
933
+ ```
934
+
935
+ **Why use DDD instead of DiD?**
936
+
937
+ DDD allows for violations of parallel trends that are:
938
+ - Group-specific (e.g., economic shocks in treatment states)
939
+ - Partition-specific (e.g., trends affecting women everywhere)
940
+
941
+ As long as these biases are additive, DDD differences them out. The key assumption is that the *differential* trend between eligible and ineligible units would be the same across groups.
942
+
869
943
  ### Event Study Visualization
870
944
 
871
945
  Create publication-ready event study plots:
@@ -1661,6 +1735,60 @@ SunAbraham(
1661
1735
  | `print_summary(alpha)` | Print summary to stdout |
1662
1736
  | `to_dataframe(level)` | Convert to DataFrame ('event_study' or 'cohort') |
1663
1737
 
1738
+ ### TripleDifference
1739
+
1740
+ ```python
1741
+ TripleDifference(
1742
+ estimation_method='dr', # 'dr' (doubly robust), 'reg', or 'ipw'
1743
+ robust=True, # Use HC1 robust standard errors
1744
+ cluster=None, # Column for cluster-robust SEs
1745
+ alpha=0.05, # Significance level for CIs
1746
+ pscore_trim=0.01 # Propensity score trimming threshold
1747
+ )
1748
+ ```
1749
+
1750
+ **fit() Parameters:**
1751
+
1752
+ | Parameter | Type | Description |
1753
+ |-----------|------|-------------|
1754
+ | `data` | DataFrame | Input data |
1755
+ | `outcome` | str | Outcome variable column name |
1756
+ | `group` | str | Group indicator column (0/1): 1=treated group |
1757
+ | `partition` | str | Partition/eligibility indicator column (0/1): 1=eligible |
1758
+ | `time` | str | Time indicator column (0/1): 1=post-treatment |
1759
+ | `covariates` | list | Covariate column names for adjustment |
1760
+
1761
+ ### TripleDifferenceResults
1762
+
1763
+ **Attributes:**
1764
+
1765
+ | Attribute | Description |
1766
+ |-----------|-------------|
1767
+ | `att` | Average Treatment effect on the Treated |
1768
+ | `se` | Standard error of ATT |
1769
+ | `t_stat` | T-statistic |
1770
+ | `p_value` | P-value for H0: ATT = 0 |
1771
+ | `conf_int` | Tuple of (lower, upper) confidence bounds |
1772
+ | `n_obs` | Total number of observations |
1773
+ | `n_treated_eligible` | Obs in treated group & eligible partition |
1774
+ | `n_treated_ineligible` | Obs in treated group & ineligible partition |
1775
+ | `n_control_eligible` | Obs in control group & eligible partition |
1776
+ | `n_control_ineligible` | Obs in control group & ineligible partition |
1777
+ | `estimation_method` | Method used ('dr', 'reg', or 'ipw') |
1778
+ | `group_means` | Dict of cell means for diagnostics |
1779
+ | `pscore_stats` | Propensity score statistics (IPW/DR only) |
1780
+ | `is_significant` | Boolean for significance at alpha |
1781
+ | `significance_stars` | String of significance stars |
1782
+
1783
+ **Methods:**
1784
+
1785
+ | Method | Description |
1786
+ |--------|-------------|
1787
+ | `summary(alpha)` | Get formatted summary string |
1788
+ | `print_summary(alpha)` | Print summary to stdout |
1789
+ | `to_dict()` | Convert to dictionary |
1790
+ | `to_dataframe()` | Convert to pandas DataFrame |
1791
+
1664
1792
  ### HonestDiD
1665
1793
 
1666
1794
  ```python
@@ -2024,6 +2152,18 @@ This library implements methods from the following scholarly works:
2024
2152
 
2025
2153
  - **Arkhangelsky, D., Athey, S., Hirshberg, D. A., Imbens, G. W., & Wager, S. (2021).** "Synthetic Difference-in-Differences." *American Economic Review*, 111(12), 4088-4118. [https://doi.org/10.1257/aer.20190159](https://doi.org/10.1257/aer.20190159)
2026
2154
 
2155
+ ### Triple Difference (DDD)
2156
+
2157
+ - **Ortiz-Villavicencio, M., & Sant'Anna, P. H. C. (2025).** "Better Understanding Triple Differences Estimators." *Working Paper*. [https://arxiv.org/abs/2505.09942](https://arxiv.org/abs/2505.09942)
2158
+
2159
+ This paper shows that common DDD implementations (taking the difference between two DiDs, or applying three-way fixed effects regressions) are generally invalid when identification requires conditioning on covariates. The `TripleDifference` class implements their regression adjustment, inverse probability weighting, and doubly robust estimators.
2160
+
2161
+ - **Gruber, J. (1994).** "The Incidence of Mandated Maternity Benefits." *American Economic Review*, 84(3), 622-641. [https://www.jstor.org/stable/2118071](https://www.jstor.org/stable/2118071)
2162
+
2163
+ Classic paper introducing the Triple Difference design for policy evaluation.
2164
+
2165
+ - **Olden, A., & Møen, J. (2022).** "The Triple Difference Estimator." *The Econometrics Journal*, 25(3), 531-553. [https://doi.org/10.1093/ectj/utac010](https://doi.org/10.1093/ectj/utac010)
2166
+
2027
2167
  ### Parallel Trends and Pre-Trend Testing
2028
2168
 
2029
2169
  - **Roth, J. (2022).** "Pretest with Caution: Event-Study Estimates after Testing for Parallel Trends." *American Economic Review: Insights*, 4(3), 305-322. [https://doi.org/10.1257/aeri.20210236](https://doi.org/10.1257/aeri.20210236)
@@ -81,6 +81,11 @@ from diff_diff.sun_abraham import (
81
81
  SunAbraham,
82
82
  SunAbrahamResults,
83
83
  )
84
+ from diff_diff.triple_diff import (
85
+ TripleDifference,
86
+ TripleDifferenceResults,
87
+ triple_difference,
88
+ )
84
89
  from diff_diff.utils import (
85
90
  WildBootstrapResults,
86
91
  check_parallel_trends,
@@ -107,6 +112,7 @@ __all__ = [
107
112
  "SyntheticDiD",
108
113
  "CallawaySantAnna",
109
114
  "SunAbraham",
115
+ "TripleDifference",
110
116
  # Bacon Decomposition
111
117
  "BaconDecomposition",
112
118
  "BaconDecompositionResults",
@@ -123,6 +129,8 @@ __all__ = [
123
129
  "GroupTimeEffect",
124
130
  "SunAbrahamResults",
125
131
  "SABootstrapResults",
132
+ "TripleDifferenceResults",
133
+ "triple_difference",
126
134
  # Visualization
127
135
  "plot_event_study",
128
136
  "plot_group_effects",