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.
Files changed (36) hide show
  1. {diff_diff-2.3.0 → diff_diff-2.3.1}/PKG-INFO +13 -11
  2. {diff_diff-2.3.0 → diff_diff-2.3.1}/README.md +12 -10
  3. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/__init__.py +1 -1
  4. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/_backend.py +20 -0
  5. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/results.py +13 -5
  6. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/synthetic_did.py +246 -126
  7. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/utils.py +393 -32
  8. {diff_diff-2.3.0 → diff_diff-2.3.1}/pyproject.toml +1 -1
  9. {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/Cargo.lock +18 -18
  10. {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/Cargo.toml +1 -1
  11. {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/src/lib.rs +7 -1
  12. diff_diff-2.3.1/rust/src/weights.rs +713 -0
  13. diff_diff-2.3.0/rust/src/weights.rs +0 -220
  14. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/bacon.py +0 -0
  15. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/datasets.py +0 -0
  16. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/diagnostics.py +0 -0
  17. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/estimators.py +0 -0
  18. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/honest_did.py +0 -0
  19. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/imputation.py +0 -0
  20. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/linalg.py +0 -0
  21. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/power.py +0 -0
  22. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/prep.py +0 -0
  23. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/prep_dgp.py +0 -0
  24. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/pretrends.py +0 -0
  25. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/staggered.py +0 -0
  26. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/staggered_aggregation.py +0 -0
  27. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/staggered_bootstrap.py +0 -0
  28. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/staggered_results.py +0 -0
  29. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/sun_abraham.py +0 -0
  30. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/triple_diff.py +0 -0
  31. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/trop.py +0 -0
  32. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/twfe.py +0 -0
  33. {diff_diff-2.3.0 → diff_diff-2.3.1}/diff_diff/visualization.py +0 -0
  34. {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/src/bootstrap.rs +0 -0
  35. {diff_diff-2.3.0 → diff_diff-2.3.1}/rust/src/linalg.rs +0 -0
  36. {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.0
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
- lambda_reg=0.0, # Regularization toward uniform weights (0 = no reg)
1204
- zeta=1.0, # Time weight regularization (higher = more uniform)
1205
- alpha=0.05, # Significance level
1206
- n_bootstrap=200, # Bootstrap iterations for SE (0 = placebo-based)
1207
- seed=None # Random seed for reproducibility
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
- lambda_reg=0.0, # L2 regularization for unit weights
1913
- zeta=1.0, # Regularization for time weights
1914
- alpha=0.05, # Significance level for CIs
1915
- n_bootstrap=200, # Bootstrap iterations for SE
1916
- seed=None # Random seed for reproducibility
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
- lambda_reg=0.0, # Regularization toward uniform weights (0 = no reg)
1167
- zeta=1.0, # Time weight regularization (higher = more uniform)
1168
- alpha=0.05, # Significance level
1169
- n_bootstrap=200, # Bootstrap iterations for SE (0 = placebo-based)
1170
- seed=None # Random seed for reproducibility
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
- lambda_reg=0.0, # L2 regularization for unit weights
1876
- zeta=1.0, # Regularization for time weights
1877
- alpha=0.05, # Significance level for CIs
1878
- n_bootstrap=200, # Bootstrap iterations for SE
1879
- seed=None # Random seed for reproducibility
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
 
@@ -142,7 +142,7 @@ from diff_diff.datasets import (
142
142
  load_mpdta,
143
143
  )
144
144
 
145
- __version__ = "2.3.0"
145
+ __version__ = "2.3.1"
146
146
  __all__ = [
147
147
  # Estimators
148
148
  "DifferenceInDifferences",
@@ -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="bootstrap")
609
- lambda_reg: Optional[float] = field(default=None)
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.lambda_reg is not None:
654
- lines.append(f"{'Regularization (lambda):':<25} {self.lambda_reg:>10.4f}")
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
- "lambda_reg": self.lambda_reg,
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: