diff-diff 2.4.1__tar.gz → 2.4.3__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 (43) hide show
  1. {diff_diff-2.4.1 → diff_diff-2.4.3}/PKG-INFO +4 -4
  2. {diff_diff-2.4.1 → diff_diff-2.4.3}/README.md +3 -3
  3. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/__init__.py +1 -1
  4. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/_backend.py +21 -0
  5. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/imputation.py +13 -16
  6. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/imputation_bootstrap.py +41 -18
  7. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/imputation_results.py +1 -1
  8. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/sun_abraham.py +0 -22
  9. diff_diff-2.4.3/diff_diff/triple_diff.py +1598 -0
  10. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/trop.py +7 -1
  11. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/two_stage.py +63 -10
  12. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/two_stage_bootstrap.py +18 -8
  13. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/two_stage_results.py +1 -1
  14. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/utils.py +0 -98
  15. {diff_diff-2.4.1 → diff_diff-2.4.3}/pyproject.toml +1 -1
  16. {diff_diff-2.4.1 → diff_diff-2.4.3}/rust/Cargo.lock +28 -1
  17. {diff_diff-2.4.1 → diff_diff-2.4.3}/rust/Cargo.toml +11 -3
  18. diff_diff-2.4.3/rust/build.rs +12 -0
  19. {diff_diff-2.4.1 → diff_diff-2.4.3}/rust/src/lib.rs +25 -0
  20. {diff_diff-2.4.1 → diff_diff-2.4.3}/rust/src/weights.rs +410 -45
  21. diff_diff-2.4.1/diff_diff/triple_diff.py +0 -1317
  22. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/bacon.py +0 -0
  23. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/datasets.py +0 -0
  24. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/diagnostics.py +0 -0
  25. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/estimators.py +0 -0
  26. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/honest_did.py +0 -0
  27. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/linalg.py +0 -0
  28. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/power.py +0 -0
  29. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/prep.py +0 -0
  30. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/prep_dgp.py +0 -0
  31. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/pretrends.py +0 -0
  32. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/results.py +0 -0
  33. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/staggered.py +0 -0
  34. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/staggered_aggregation.py +0 -0
  35. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/staggered_bootstrap.py +0 -0
  36. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/staggered_results.py +0 -0
  37. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/synthetic_did.py +0 -0
  38. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/trop_results.py +0 -0
  39. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/twfe.py +0 -0
  40. {diff_diff-2.4.1 → diff_diff-2.4.3}/diff_diff/visualization.py +0 -0
  41. {diff_diff-2.4.1 → diff_diff-2.4.3}/rust/src/bootstrap.rs +0 -0
  42. {diff_diff-2.4.1 → diff_diff-2.4.3}/rust/src/linalg.rs +0 -0
  43. {diff_diff-2.4.1 → diff_diff-2.4.3}/rust/src/trop.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diff-diff
3
- Version: 2.4.1
3
+ Version: 2.4.3
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: Operating System :: OS Independent
@@ -2021,7 +2021,7 @@ TROP(
2021
2021
  max_iter=100, # Max iterations for factor estimation
2022
2022
  tol=1e-6, # Convergence tolerance
2023
2023
  alpha=0.05, # Significance level for CIs
2024
- n_bootstrap=200, # Bootstrap replications
2024
+ n_bootstrap=200, # Bootstrap replications (minimum 2; TROP requires bootstrap for SEs)
2025
2025
  seed=None # Random seed
2026
2026
  )
2027
2027
  ```
@@ -2102,8 +2102,6 @@ SunAbraham(
2102
2102
  | `time` | str | Time period column |
2103
2103
  | `first_treat` | str | Column with first treatment period (0 for never-treated) |
2104
2104
  | `covariates` | list | Covariate column names |
2105
- | `min_pre_periods` | int | Minimum pre-treatment periods to include |
2106
- | `min_post_periods` | int | Minimum post-treatment periods to include |
2107
2105
 
2108
2106
  ### SunAbrahamResults
2109
2107
 
@@ -2143,6 +2141,7 @@ ImputationDiD(
2143
2141
  alpha=0.05, # Significance level for CIs
2144
2142
  cluster=None, # Column for cluster-robust SEs
2145
2143
  n_bootstrap=0, # Bootstrap iterations (0 = analytical)
2144
+ bootstrap_weights='rademacher', # 'rademacher', 'mammen', or 'webb'
2146
2145
  seed=None, # Random seed
2147
2146
  rank_deficient_action='warn', # 'warn', 'error', or 'silent'
2148
2147
  horizon_max=None, # Max event-study horizon
@@ -2197,6 +2196,7 @@ TwoStageDiD(
2197
2196
  alpha=0.05, # Significance level for CIs
2198
2197
  cluster=None, # Column for cluster-robust SEs (defaults to unit)
2199
2198
  n_bootstrap=0, # Bootstrap iterations (0 = analytical GMM SEs)
2199
+ bootstrap_weights='rademacher', # 'rademacher', 'mammen', or 'webb'
2200
2200
  seed=None, # Random seed
2201
2201
  rank_deficient_action='warn', # 'warn', 'error', or 'silent'
2202
2202
  horizon_max=None, # Max event-study horizon
@@ -1983,7 +1983,7 @@ TROP(
1983
1983
  max_iter=100, # Max iterations for factor estimation
1984
1984
  tol=1e-6, # Convergence tolerance
1985
1985
  alpha=0.05, # Significance level for CIs
1986
- n_bootstrap=200, # Bootstrap replications
1986
+ n_bootstrap=200, # Bootstrap replications (minimum 2; TROP requires bootstrap for SEs)
1987
1987
  seed=None # Random seed
1988
1988
  )
1989
1989
  ```
@@ -2064,8 +2064,6 @@ SunAbraham(
2064
2064
  | `time` | str | Time period column |
2065
2065
  | `first_treat` | str | Column with first treatment period (0 for never-treated) |
2066
2066
  | `covariates` | list | Covariate column names |
2067
- | `min_pre_periods` | int | Minimum pre-treatment periods to include |
2068
- | `min_post_periods` | int | Minimum post-treatment periods to include |
2069
2067
 
2070
2068
  ### SunAbrahamResults
2071
2069
 
@@ -2105,6 +2103,7 @@ ImputationDiD(
2105
2103
  alpha=0.05, # Significance level for CIs
2106
2104
  cluster=None, # Column for cluster-robust SEs
2107
2105
  n_bootstrap=0, # Bootstrap iterations (0 = analytical)
2106
+ bootstrap_weights='rademacher', # 'rademacher', 'mammen', or 'webb'
2108
2107
  seed=None, # Random seed
2109
2108
  rank_deficient_action='warn', # 'warn', 'error', or 'silent'
2110
2109
  horizon_max=None, # Max event-study horizon
@@ -2159,6 +2158,7 @@ TwoStageDiD(
2159
2158
  alpha=0.05, # Significance level for CIs
2160
2159
  cluster=None, # Column for cluster-robust SEs (defaults to unit)
2161
2160
  n_bootstrap=0, # Bootstrap iterations (0 = analytical GMM SEs)
2161
+ bootstrap_weights='rademacher', # 'rademacher', 'mammen', or 'webb'
2162
2162
  seed=None, # Random seed
2163
2163
  rank_deficient_action='warn', # 'warn', 'error', or 'silent'
2164
2164
  horizon_max=None, # Max event-study horizon
@@ -148,7 +148,7 @@ from diff_diff.datasets import (
148
148
  load_mpdta,
149
149
  )
150
150
 
151
- __version__ = "2.4.1"
151
+ __version__ = "2.4.3"
152
152
  __all__ = [
153
153
  # Estimators
154
154
  "DifferenceInDifferences",
@@ -35,6 +35,8 @@ try:
35
35
  compute_time_weights as _rust_compute_time_weights,
36
36
  compute_noise_level as _rust_compute_noise_level,
37
37
  sc_weight_fw as _rust_sc_weight_fw,
38
+ # Diagnostics
39
+ rust_backend_info as _rust_backend_info,
38
40
  )
39
41
  _rust_available = True
40
42
  except ImportError:
@@ -56,6 +58,7 @@ except ImportError:
56
58
  _rust_compute_time_weights = None
57
59
  _rust_compute_noise_level = None
58
60
  _rust_sc_weight_fw = None
61
+ _rust_backend_info = None
59
62
 
60
63
  # Determine final backend based on environment variable and availability
61
64
  if _backend_env == 'python':
@@ -78,6 +81,7 @@ if _backend_env == 'python':
78
81
  _rust_compute_time_weights = None
79
82
  _rust_compute_noise_level = None
80
83
  _rust_sc_weight_fw = None
84
+ _rust_backend_info = None
81
85
  elif _backend_env == 'rust':
82
86
  # Force Rust mode - fail if not available
83
87
  if not _rust_available:
@@ -90,8 +94,25 @@ else:
90
94
  # Auto mode - use Rust if available
91
95
  HAS_RUST_BACKEND = _rust_available
92
96
 
97
+
98
+ def rust_backend_info():
99
+ """Return compile-time BLAS feature information for the Rust backend.
100
+
101
+ Returns a dict with keys:
102
+ - 'blas': True if any BLAS backend is linked
103
+ - 'accelerate': True if Apple Accelerate is linked (macOS)
104
+ - 'openblas': True if OpenBLAS is linked (Linux)
105
+
106
+ If the Rust backend is not available, all values are False.
107
+ """
108
+ if _rust_backend_info is not None:
109
+ return _rust_backend_info()
110
+ return {"blas": False, "accelerate": False, "openblas": False}
111
+
112
+
93
113
  __all__ = [
94
114
  'HAS_RUST_BACKEND',
115
+ 'rust_backend_info',
95
116
  '_rust_bootstrap_weights',
96
117
  '_rust_synthetic_weights',
97
118
  '_rust_project_simplex',
@@ -22,7 +22,7 @@ import pandas as pd
22
22
  from scipy import sparse, stats
23
23
  from scipy.sparse.linalg import spsolve
24
24
 
25
- from diff_diff.imputation_bootstrap import ImputationDiDBootstrapMixin
25
+ from diff_diff.imputation_bootstrap import ImputationDiDBootstrapMixin, _compute_target_weights
26
26
  from diff_diff.imputation_results import ImputationBootstrapResults, ImputationDiDResults # noqa: F401 (re-export)
27
27
  from diff_diff.linalg import solve_ols
28
28
  from diff_diff.utils import safe_inference
@@ -63,6 +63,8 @@ class ImputationDiD(ImputationDiDBootstrapMixin):
63
63
  n_bootstrap : int, default=0
64
64
  Number of bootstrap iterations. If 0, uses analytical inference
65
65
  (conservative variance from Theorem 3).
66
+ bootstrap_weights : str, default="rademacher"
67
+ Type of bootstrap weights: "rademacher", "mammen", or "webb".
66
68
  seed : int, optional
67
69
  Random seed for reproducibility.
68
70
  rank_deficient_action : str, default="warn"
@@ -126,6 +128,7 @@ class ImputationDiD(ImputationDiDBootstrapMixin):
126
128
  alpha: float = 0.05,
127
129
  cluster: Optional[str] = None,
128
130
  n_bootstrap: int = 0,
131
+ bootstrap_weights: str = "rademacher",
129
132
  seed: Optional[int] = None,
130
133
  rank_deficient_action: str = "warn",
131
134
  horizon_max: Optional[int] = None,
@@ -136,6 +139,11 @@ class ImputationDiD(ImputationDiDBootstrapMixin):
136
139
  f"rank_deficient_action must be 'warn', 'error', or 'silent', "
137
140
  f"got '{rank_deficient_action}'"
138
141
  )
142
+ if bootstrap_weights not in ("rademacher", "mammen", "webb"):
143
+ raise ValueError(
144
+ f"bootstrap_weights must be 'rademacher', 'mammen', or 'webb', "
145
+ f"got '{bootstrap_weights}'"
146
+ )
139
147
  if aux_partition not in ("cohort_horizon", "cohort", "horizon"):
140
148
  raise ValueError(
141
149
  f"aux_partition must be 'cohort_horizon', 'cohort', or 'horizon', "
@@ -146,6 +154,7 @@ class ImputationDiD(ImputationDiDBootstrapMixin):
146
154
  self.alpha = alpha
147
155
  self.cluster = cluster
148
156
  self.n_bootstrap = n_bootstrap
157
+ self.bootstrap_weights = bootstrap_weights
149
158
  self.seed = seed
150
159
  self.rank_deficient_action = rank_deficient_action
151
160
  self.horizon_max = horizon_max
@@ -1359,15 +1368,7 @@ class ImputationDiD(ImputationDiDBootstrapMixin):
1359
1368
  effect = float(np.mean(valid_tau))
1360
1369
 
1361
1370
  # Compute SE via conservative variance with horizon-specific weights
1362
- weights_h = np.zeros(int(omega_1_mask.sum()))
1363
- # Map h_mask (relative to df_1) to weights array
1364
- h_indices_in_omega1 = np.where(h_mask)[0]
1365
- n_valid = len(valid_tau)
1366
- # Only weight valid (finite) observations
1367
- finite_mask = np.isfinite(tau_hat[h_mask])
1368
- valid_h_indices = h_indices_in_omega1[finite_mask]
1369
- for idx in valid_h_indices:
1370
- weights_h[idx] = 1.0 / n_valid
1371
+ weights_h, n_valid = _compute_target_weights(tau_hat, h_mask)
1371
1372
 
1372
1373
  se = self._compute_conservative_variance(
1373
1374
  df=df,
@@ -1477,12 +1478,7 @@ class ImputationDiD(ImputationDiDBootstrapMixin):
1477
1478
  effect = float(np.mean(valid_tau))
1478
1479
 
1479
1480
  # Compute SE with group-specific weights
1480
- weights_g = np.zeros(int(omega_1_mask.sum()))
1481
- finite_mask = np.isfinite(tau_hat) & g_mask
1482
- g_indices = np.where(finite_mask)[0]
1483
- n_valid = len(valid_tau)
1484
- for idx in g_indices:
1485
- weights_g[idx] = 1.0 / n_valid
1481
+ weights_g, _ = _compute_target_weights(tau_hat, g_mask)
1486
1482
 
1487
1483
  se = self._compute_conservative_variance(
1488
1484
  df=df,
@@ -1664,6 +1660,7 @@ class ImputationDiD(ImputationDiDBootstrapMixin):
1664
1660
  "alpha": self.alpha,
1665
1661
  "cluster": self.cluster,
1666
1662
  "n_bootstrap": self.n_bootstrap,
1663
+ "bootstrap_weights": self.bootstrap_weights,
1667
1664
  "seed": self.seed,
1668
1665
  "rank_deficient_action": self.rank_deficient_action,
1669
1666
  "horizon_max": self.horizon_max,
@@ -19,6 +19,39 @@ __all__ = [
19
19
  ]
20
20
 
21
21
 
22
+ def _compute_target_weights(
23
+ tau_hat: np.ndarray,
24
+ target_mask: np.ndarray,
25
+ ) -> "tuple[np.ndarray, int]":
26
+ """
27
+ Equal weights for finite tau_hat observations within target_mask.
28
+
29
+ Used by both aggregation and bootstrap paths to avoid weight logic
30
+ duplication.
31
+
32
+ Parameters
33
+ ----------
34
+ tau_hat : np.ndarray
35
+ Per-observation treatment effects (may contain NaN).
36
+ target_mask : np.ndarray
37
+ Boolean mask selecting the target subset within tau_hat.
38
+
39
+ Returns
40
+ -------
41
+ weights : np.ndarray
42
+ Weight array (same length as tau_hat). 1/n_valid for finite
43
+ observations in target_mask, 0 elsewhere.
44
+ n_valid : int
45
+ Number of finite observations in the target subset.
46
+ """
47
+ finite_target = np.isfinite(tau_hat) & target_mask
48
+ n_valid = int(finite_target.sum())
49
+ weights = np.zeros(len(tau_hat))
50
+ if n_valid > 0:
51
+ weights[np.where(finite_target)[0]] = 1.0 / n_valid
52
+ return weights, n_valid
53
+
54
+
22
55
  class ImputationDiDBootstrapMixin:
23
56
  """Mixin providing bootstrap inference methods for ImputationDiD."""
24
57
 
@@ -91,7 +124,8 @@ class ImputationDiDBootstrapMixin:
91
124
 
92
125
  For each aggregation target (overall, per-horizon, per-group), computes
93
126
  psi_i = sum_t v_it * epsilon_tilde_it for each cluster. The multiplier
94
- bootstrap then perturbs these psi sums with Rademacher weights.
127
+ bootstrap then perturbs these psi sums with multiplier weights
128
+ (rademacher/mammen/webb; configurable via ``bootstrap_weights``).
95
129
 
96
130
  Computational cost scales with the number of aggregation targets, since
97
131
  each target requires its own v_untreated computation (weight-dependent).
@@ -120,13 +154,10 @@ class ImputationDiDBootstrapMixin:
120
154
  result["overall"] = (overall_psi, cluster_ids)
121
155
 
122
156
  # Event study: per-horizon weights
123
- # NOTE: weight logic duplicated from _aggregate_event_study.
124
- # If weight scheme changes there, update here too.
125
157
  if event_study_effects:
126
158
  result["event_study"] = {}
127
159
  df_1 = df.loc[omega_1_mask]
128
160
  rel_times = df_1["_rel_time"].values
129
- n_omega_1 = int(omega_1_mask.sum())
130
161
 
131
162
  # Balanced cohort mask (same logic as _aggregate_event_study)
132
163
  balanced_mask = None
@@ -150,24 +181,18 @@ class ImputationDiDBootstrapMixin:
150
181
  h_mask = rel_times == h
151
182
  if balanced_mask is not None:
152
183
  h_mask = h_mask & balanced_mask
153
- weights_h = np.zeros(n_omega_1)
154
- finite_h = np.isfinite(tau_hat) & h_mask
155
- n_valid_h = int(finite_h.sum())
184
+ weights_h, n_valid_h = _compute_target_weights(tau_hat, h_mask)
156
185
  if n_valid_h == 0:
157
186
  continue
158
- weights_h[np.where(finite_h)[0]] = 1.0 / n_valid_h
159
187
 
160
188
  psi_h, _ = self._compute_cluster_psi_sums(**common, weights=weights_h)
161
189
  result["event_study"][h] = psi_h
162
190
 
163
191
  # Group effects: per-group weights
164
- # NOTE: weight logic duplicated from _aggregate_group.
165
- # If weight scheme changes there, update here too.
166
192
  if group_effects:
167
193
  result["group"] = {}
168
194
  df_1 = df.loc[omega_1_mask]
169
195
  cohorts = df_1[first_treat].values
170
- n_omega_1 = int(omega_1_mask.sum())
171
196
 
172
197
  for g in group_effects:
173
198
  if group_effects[g].get("n_obs", 0) == 0:
@@ -175,12 +200,9 @@ class ImputationDiDBootstrapMixin:
175
200
  if not np.isfinite(group_effects[g].get("effect", np.nan)):
176
201
  continue
177
202
  g_mask = cohorts == g
178
- weights_g = np.zeros(n_omega_1)
179
- finite_g = np.isfinite(tau_hat) & g_mask
180
- n_valid_g = int(finite_g.sum())
203
+ weights_g, n_valid_g = _compute_target_weights(tau_hat, g_mask)
181
204
  if n_valid_g == 0:
182
205
  continue
183
- weights_g[np.where(finite_g)[0]] = 1.0 / n_valid_g
184
206
 
185
207
  psi_g, _ = self._compute_cluster_psi_sums(**common, weights=weights_g)
186
208
  result["group"][g] = psi_g
@@ -197,7 +219,8 @@ class ImputationDiDBootstrapMixin:
197
219
  """
198
220
  Run multiplier bootstrap on pre-computed influence function sums.
199
221
 
200
- Uses T_b = sum_i w_b_i * psi_i where w_b_i are Rademacher weights
222
+ Uses T_b = sum_i w_b_i * psi_i where w_b_i are multiplier weights
223
+ (rademacher/mammen/webb; configurable via ``bootstrap_weights``)
201
224
  and psi_i are cluster-level influence function sums from Theorem 3.
202
225
  SE = std(T_b, ddof=1).
203
226
  """
@@ -216,7 +239,7 @@ class ImputationDiDBootstrapMixin:
216
239
 
217
240
  # Generate ALL weights upfront: shape (n_bootstrap, n_clusters)
218
241
  all_weights = _generate_bootstrap_weights_batch(
219
- self.n_bootstrap, n_clusters, "rademacher", rng
242
+ self.n_bootstrap, n_clusters, self.bootstrap_weights, rng
220
243
  )
221
244
 
222
245
  # Overall ATT bootstrap draws
@@ -295,7 +318,7 @@ class ImputationDiDBootstrapMixin:
295
318
 
296
319
  return ImputationBootstrapResults(
297
320
  n_bootstrap=self.n_bootstrap,
298
- weight_type="rademacher",
321
+ weight_type=self.bootstrap_weights,
299
322
  alpha=self.alpha,
300
323
  overall_att_se=overall_se,
301
324
  overall_att_ci=overall_ci,
@@ -33,7 +33,7 @@ class ImputationBootstrapResults:
33
33
  n_bootstrap : int
34
34
  Number of bootstrap iterations.
35
35
  weight_type : str
36
- Type of bootstrap weights (currently "rademacher" only).
36
+ Type of bootstrap weights: "rademacher", "mammen", or "webb".
37
37
  alpha : float
38
38
  Significance level used for confidence intervals.
39
39
  overall_att_se : float
@@ -433,8 +433,6 @@ class SunAbraham:
433
433
  time: str,
434
434
  first_treat: str,
435
435
  covariates: Optional[List[str]] = None,
436
- min_pre_periods: int = 1,
437
- min_post_periods: int = 1,
438
436
  ) -> SunAbrahamResults:
439
437
  """
440
438
  Fit the Sun-Abraham estimator using saturated regression.
@@ -454,10 +452,6 @@ class SunAbraham:
454
452
  Use 0 (or np.inf) for never-treated units.
455
453
  covariates : list, optional
456
454
  List of covariate column names to include in regression.
457
- min_pre_periods : int, default=1
458
- **Deprecated**: Accepted but ignored. Will be removed in a future version.
459
- min_post_periods : int, default=1
460
- **Deprecated**: Accepted but ignored. Will be removed in a future version.
461
455
 
462
456
  Returns
463
457
  -------
@@ -469,22 +463,6 @@ class SunAbraham:
469
463
  ValueError
470
464
  If required columns are missing or data validation fails.
471
465
  """
472
- # Deprecation warnings for unimplemented parameters
473
- if min_pre_periods != 1:
474
- warnings.warn(
475
- "min_pre_periods is not yet implemented and will be ignored. "
476
- "This parameter will be removed in a future version.",
477
- FutureWarning,
478
- stacklevel=2,
479
- )
480
- if min_post_periods != 1:
481
- warnings.warn(
482
- "min_post_periods is not yet implemented and will be ignored. "
483
- "This parameter will be removed in a future version.",
484
- FutureWarning,
485
- stacklevel=2,
486
- )
487
-
488
466
  # Validate inputs
489
467
  required_cols = [outcome, unit, time, first_treat]
490
468
  if covariates: