diff-diff 2.3.0__tar.gz → 2.3.1__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.
- {diff_diff-2.3.0 → diff_diff-2.3.1}/PKG-INFO +13 -11
- {diff_diff-2.3.0 → diff_diff-2.3.1}/README.md +12 -10
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/__init__.py +1 -1
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/_backend.py +20 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/results.py +13 -5
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/synthetic_did.py +246 -126
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/utils.py +393 -32
- {diff_diff-2.3.0 → diff_diff-2.3.1}/pyproject.toml +1 -1
- {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/Cargo.lock +18 -18
- {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/Cargo.toml +1 -1
- {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/src/lib.rs +7 -1
- diff_diff-2.3.1/rust/src/weights.rs +713 -0
- diff_diff-2.3.0/rust/src/weights.rs +0 -220
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/bacon.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/datasets.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/diagnostics.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/estimators.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/honest_did.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/imputation.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/linalg.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/power.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/prep.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/prep_dgp.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/pretrends.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/staggered.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/staggered_aggregation.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/staggered_bootstrap.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/staggered_results.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/sun_abraham.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/triple_diff.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/trop.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/twfe.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/visualization.py +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/src/bootstrap.rs +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/src/linalg.rs +0 -0
- {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/src/trop.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: diff-diff
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.1
|
|
4
4
|
Classifier: Development Status :: 5 - Production/Stable
|
|
5
5
|
Classifier: Intended Audience :: Science/Research
|
|
6
6
|
Classifier: Operating System :: OS Independent
|
|
@@ -1200,11 +1200,12 @@ Use Synthetic DiD instead of standard DiD when:
|
|
|
1200
1200
|
|
|
1201
1201
|
```python
|
|
1202
1202
|
SyntheticDiD(
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
alpha=0.05,
|
|
1206
|
-
|
|
1207
|
-
|
|
1203
|
+
zeta_omega=None, # Unit weight regularization (None = auto-computed from data)
|
|
1204
|
+
zeta_lambda=None, # Time weight regularization (None = auto-computed from data)
|
|
1205
|
+
alpha=0.05, # Significance level
|
|
1206
|
+
variance_method="placebo", # "placebo" (default, matches R) or "bootstrap"
|
|
1207
|
+
n_bootstrap=200, # Replications for SE estimation
|
|
1208
|
+
seed=None # Random seed for reproducibility
|
|
1208
1209
|
)
|
|
1209
1210
|
```
|
|
1210
1211
|
|
|
@@ -1909,11 +1910,12 @@ MultiPeriodDiD(
|
|
|
1909
1910
|
|
|
1910
1911
|
```python
|
|
1911
1912
|
SyntheticDiD(
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
alpha=0.05,
|
|
1915
|
-
|
|
1916
|
-
|
|
1913
|
+
zeta_omega=None, # Unit weight regularization (None = auto from data)
|
|
1914
|
+
zeta_lambda=None, # Time weight regularization (None = auto from data)
|
|
1915
|
+
alpha=0.05, # Significance level for CIs
|
|
1916
|
+
variance_method="placebo", # "placebo" (R default) or "bootstrap"
|
|
1917
|
+
n_bootstrap=200, # Replications for SE estimation
|
|
1918
|
+
seed=None # Random seed for reproducibility
|
|
1917
1919
|
)
|
|
1918
1920
|
```
|
|
1919
1921
|
|
|
@@ -1163,11 +1163,12 @@ Use Synthetic DiD instead of standard DiD when:
|
|
|
1163
1163
|
|
|
1164
1164
|
```python
|
|
1165
1165
|
SyntheticDiD(
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
alpha=0.05,
|
|
1169
|
-
|
|
1170
|
-
|
|
1166
|
+
zeta_omega=None, # Unit weight regularization (None = auto-computed from data)
|
|
1167
|
+
zeta_lambda=None, # Time weight regularization (None = auto-computed from data)
|
|
1168
|
+
alpha=0.05, # Significance level
|
|
1169
|
+
variance_method="placebo", # "placebo" (default, matches R) or "bootstrap"
|
|
1170
|
+
n_bootstrap=200, # Replications for SE estimation
|
|
1171
|
+
seed=None # Random seed for reproducibility
|
|
1171
1172
|
)
|
|
1172
1173
|
```
|
|
1173
1174
|
|
|
@@ -1872,11 +1873,12 @@ MultiPeriodDiD(
|
|
|
1872
1873
|
|
|
1873
1874
|
```python
|
|
1874
1875
|
SyntheticDiD(
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
alpha=0.05,
|
|
1878
|
-
|
|
1879
|
-
|
|
1876
|
+
zeta_omega=None, # Unit weight regularization (None = auto from data)
|
|
1877
|
+
zeta_lambda=None, # Time weight regularization (None = auto from data)
|
|
1878
|
+
alpha=0.05, # Significance level for CIs
|
|
1879
|
+
variance_method="placebo", # "placebo" (R default) or "bootstrap"
|
|
1880
|
+
n_bootstrap=200, # Replications for SE estimation
|
|
1881
|
+
seed=None # Random seed for reproducibility
|
|
1880
1882
|
)
|
|
1881
1883
|
```
|
|
1882
1884
|
|
|
@@ -30,6 +30,11 @@ try:
|
|
|
30
30
|
# TROP estimator acceleration (joint method)
|
|
31
31
|
loocv_grid_search_joint as _rust_loocv_grid_search_joint,
|
|
32
32
|
bootstrap_trop_variance_joint as _rust_bootstrap_trop_variance_joint,
|
|
33
|
+
# SDID weights (Frank-Wolfe matching R's synthdid)
|
|
34
|
+
compute_sdid_unit_weights as _rust_sdid_unit_weights,
|
|
35
|
+
compute_time_weights as _rust_compute_time_weights,
|
|
36
|
+
compute_noise_level as _rust_compute_noise_level,
|
|
37
|
+
sc_weight_fw as _rust_sc_weight_fw,
|
|
33
38
|
)
|
|
34
39
|
_rust_available = True
|
|
35
40
|
except ImportError:
|
|
@@ -46,6 +51,11 @@ except ImportError:
|
|
|
46
51
|
# TROP estimator acceleration (joint method)
|
|
47
52
|
_rust_loocv_grid_search_joint = None
|
|
48
53
|
_rust_bootstrap_trop_variance_joint = None
|
|
54
|
+
# SDID weights (Frank-Wolfe matching R's synthdid)
|
|
55
|
+
_rust_sdid_unit_weights = None
|
|
56
|
+
_rust_compute_time_weights = None
|
|
57
|
+
_rust_compute_noise_level = None
|
|
58
|
+
_rust_sc_weight_fw = None
|
|
49
59
|
|
|
50
60
|
# Determine final backend based on environment variable and availability
|
|
51
61
|
if _backend_env == 'python':
|
|
@@ -63,6 +73,11 @@ if _backend_env == 'python':
|
|
|
63
73
|
# TROP estimator acceleration (joint method)
|
|
64
74
|
_rust_loocv_grid_search_joint = None
|
|
65
75
|
_rust_bootstrap_trop_variance_joint = None
|
|
76
|
+
# SDID weights (Frank-Wolfe matching R's synthdid)
|
|
77
|
+
_rust_sdid_unit_weights = None
|
|
78
|
+
_rust_compute_time_weights = None
|
|
79
|
+
_rust_compute_noise_level = None
|
|
80
|
+
_rust_sc_weight_fw = None
|
|
66
81
|
elif _backend_env == 'rust':
|
|
67
82
|
# Force Rust mode - fail if not available
|
|
68
83
|
if not _rust_available:
|
|
@@ -89,4 +104,9 @@ __all__ = [
|
|
|
89
104
|
# TROP estimator acceleration (joint method)
|
|
90
105
|
'_rust_loocv_grid_search_joint',
|
|
91
106
|
'_rust_bootstrap_trop_variance_joint',
|
|
107
|
+
# SDID weights (Frank-Wolfe matching R's synthdid)
|
|
108
|
+
'_rust_sdid_unit_weights',
|
|
109
|
+
'_rust_compute_time_weights',
|
|
110
|
+
'_rust_compute_noise_level',
|
|
111
|
+
'_rust_sc_weight_fw',
|
|
92
112
|
]
|
|
@@ -605,8 +605,10 @@ class SyntheticDiDResults:
|
|
|
605
605
|
pre_periods: List[Any]
|
|
606
606
|
post_periods: List[Any]
|
|
607
607
|
alpha: float = 0.05
|
|
608
|
-
variance_method: str = field(default="
|
|
609
|
-
|
|
608
|
+
variance_method: str = field(default="placebo")
|
|
609
|
+
noise_level: Optional[float] = field(default=None)
|
|
610
|
+
zeta_omega: Optional[float] = field(default=None)
|
|
611
|
+
zeta_lambda: Optional[float] = field(default=None)
|
|
610
612
|
pre_treatment_fit: Optional[float] = field(default=None)
|
|
611
613
|
placebo_effects: Optional[np.ndarray] = field(default=None)
|
|
612
614
|
n_bootstrap: Optional[int] = field(default=None)
|
|
@@ -650,8 +652,12 @@ class SyntheticDiDResults:
|
|
|
650
652
|
f"{'Post-treatment periods:':<25} {len(self.post_periods):>10}",
|
|
651
653
|
]
|
|
652
654
|
|
|
653
|
-
if self.
|
|
654
|
-
lines.append(f"{'
|
|
655
|
+
if self.zeta_omega is not None:
|
|
656
|
+
lines.append(f"{'Zeta (unit weights):':<25} {self.zeta_omega:>10.4f}")
|
|
657
|
+
if self.zeta_lambda is not None:
|
|
658
|
+
lines.append(f"{'Zeta (time weights):':<25} {self.zeta_lambda:>10.6f}")
|
|
659
|
+
if self.noise_level is not None:
|
|
660
|
+
lines.append(f"{'Noise level:':<25} {self.noise_level:>10.4f}")
|
|
655
661
|
|
|
656
662
|
if self.pre_treatment_fit is not None:
|
|
657
663
|
lines.append(f"{'Pre-treatment fit (RMSE):':<25} {self.pre_treatment_fit:>10.4f}")
|
|
@@ -731,7 +737,9 @@ class SyntheticDiDResults:
|
|
|
731
737
|
"n_pre_periods": len(self.pre_periods),
|
|
732
738
|
"n_post_periods": len(self.post_periods),
|
|
733
739
|
"variance_method": self.variance_method,
|
|
734
|
-
"
|
|
740
|
+
"noise_level": self.noise_level,
|
|
741
|
+
"zeta_omega": self.zeta_omega,
|
|
742
|
+
"zeta_lambda": self.zeta_lambda,
|
|
735
743
|
"pre_treatment_fit": self.pre_treatment_fit,
|
|
736
744
|
}
|
|
737
745
|
if self.n_bootstrap is not None:
|