diff-diff 2.4.0__tar.gz → 2.4.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.4.0 → diff_diff-2.4.1}/PKG-INFO +1 -1
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/__init__.py +1 -1
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/diagnostics.py +4 -10
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/estimators.py +5 -19
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/imputation.py +18 -739
- diff_diff-2.4.1/diff_diff/imputation_bootstrap.py +310 -0
- diff_diff-2.4.1/diff_diff/imputation_results.py +426 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/linalg.py +6 -6
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/staggered.py +16 -30
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/staggered_aggregation.py +3 -10
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/sun_abraham.py +7 -12
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/synthetic_did.py +8 -19
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/triple_diff.py +6 -11
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/trop.py +12 -325
- diff_diff-2.4.1/diff_diff/trop_results.py +322 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/two_stage.py +23 -834
- diff_diff-2.4.1/diff_diff/two_stage_bootstrap.py +449 -0
- diff_diff-2.4.1/diff_diff/two_stage_results.py +379 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/utils.py +2 -3
- {diff_diff-2.4.0 → diff_diff-2.4.1}/pyproject.toml +1 -1
- {diff_diff-2.4.0 → diff_diff-2.4.1}/rust/Cargo.lock +1 -1
- {diff_diff-2.4.0 → diff_diff-2.4.1}/rust/Cargo.toml +1 -1
- {diff_diff-2.4.0 → diff_diff-2.4.1}/README.md +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/_backend.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/bacon.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/datasets.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/honest_did.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/power.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/prep.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/prep_dgp.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/pretrends.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/results.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/staggered_bootstrap.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/staggered_results.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/twfe.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/diff_diff/visualization.py +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/rust/src/bootstrap.rs +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/rust/src/lib.rs +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/rust/src/linalg.rs +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/rust/src/trop.rs +0 -0
- {diff_diff-2.4.0 → diff_diff-2.4.1}/rust/src/weights.rs +0 -0
|
@@ -19,7 +19,7 @@ import pandas as pd
|
|
|
19
19
|
|
|
20
20
|
from diff_diff.estimators import DifferenceInDifferences
|
|
21
21
|
from diff_diff.results import _get_significance_stars
|
|
22
|
-
from diff_diff.utils import
|
|
22
|
+
from diff_diff.utils import safe_inference
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
@dataclass
|
|
@@ -661,7 +661,7 @@ def permutation_test(
|
|
|
661
661
|
ci_lower = np.percentile(valid_effects, alpha / 2 * 100)
|
|
662
662
|
ci_upper = np.percentile(valid_effects, (1 - alpha / 2) * 100)
|
|
663
663
|
|
|
664
|
-
#
|
|
664
|
+
# NOTE: Not using safe_inference — p_value is permutation-based, CI is percentile-based.
|
|
665
665
|
t_stat = original_att / se if np.isfinite(se) and se > 0 else np.nan
|
|
666
666
|
|
|
667
667
|
return PlaceboTestResults(
|
|
@@ -782,15 +782,9 @@ def leave_one_out_test(
|
|
|
782
782
|
|
|
783
783
|
# Statistics of LOO distribution
|
|
784
784
|
mean_effect = np.mean(valid_effects)
|
|
785
|
-
se = np.std(valid_effects, ddof=1) if len(valid_effects) > 1 else
|
|
786
|
-
t_stat = mean_effect / se if np.isfinite(se) and se > 0 else np.nan
|
|
787
|
-
|
|
788
|
-
# Use t-distribution for p-value
|
|
785
|
+
se = np.std(valid_effects, ddof=1) if len(valid_effects) > 1 else np.nan
|
|
789
786
|
df = len(valid_effects) - 1 if len(valid_effects) > 1 else 1
|
|
790
|
-
p_value =
|
|
791
|
-
|
|
792
|
-
# CI
|
|
793
|
-
conf_int = compute_confidence_interval(mean_effect, se, alpha, df=df) if np.isfinite(se) and se > 0 else (np.nan, np.nan)
|
|
787
|
+
t_stat, p_value, conf_int = safe_inference(mean_effect, se, alpha=alpha, df=df)
|
|
794
788
|
|
|
795
789
|
return PlaceboTestResults(
|
|
796
790
|
test_type="leave_one_out",
|
|
@@ -27,9 +27,8 @@ from diff_diff.linalg import (
|
|
|
27
27
|
from diff_diff.results import DiDResults, MultiPeriodDiDResults, PeriodEffect
|
|
28
28
|
from diff_diff.utils import (
|
|
29
29
|
WildBootstrapResults,
|
|
30
|
-
compute_confidence_interval,
|
|
31
|
-
compute_p_value,
|
|
32
30
|
demean_by_group,
|
|
31
|
+
safe_inference,
|
|
33
32
|
validate_binary,
|
|
34
33
|
wild_bootstrap_se,
|
|
35
34
|
)
|
|
@@ -1034,14 +1033,7 @@ class MultiPeriodDiD(DifferenceInDifferences):
|
|
|
1034
1033
|
idx = interaction_indices[period]
|
|
1035
1034
|
effect = coefficients[idx]
|
|
1036
1035
|
se = np.sqrt(vcov[idx, idx])
|
|
1037
|
-
|
|
1038
|
-
t_stat = effect / se
|
|
1039
|
-
p_value = compute_p_value(t_stat, df=df)
|
|
1040
|
-
conf_int = compute_confidence_interval(effect, se, self.alpha, df=df)
|
|
1041
|
-
else:
|
|
1042
|
-
t_stat = np.nan
|
|
1043
|
-
p_value = np.nan
|
|
1044
|
-
conf_int = (np.nan, np.nan)
|
|
1036
|
+
t_stat, p_value, conf_int = safe_inference(effect, se, alpha=self.alpha, df=df)
|
|
1045
1037
|
|
|
1046
1038
|
period_effects[period] = PeriodEffect(
|
|
1047
1039
|
period=period,
|
|
@@ -1085,15 +1077,9 @@ class MultiPeriodDiD(DifferenceInDifferences):
|
|
|
1085
1077
|
avg_conf_int = (np.nan, np.nan)
|
|
1086
1078
|
else:
|
|
1087
1079
|
avg_se = float(np.sqrt(avg_var))
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
avg_conf_int = compute_confidence_interval(avg_att, avg_se, self.alpha, df=df)
|
|
1092
|
-
else:
|
|
1093
|
-
# Zero SE (degenerate case)
|
|
1094
|
-
avg_t_stat = np.nan
|
|
1095
|
-
avg_p_value = np.nan
|
|
1096
|
-
avg_conf_int = (np.nan, np.nan)
|
|
1080
|
+
avg_t_stat, avg_p_value, avg_conf_int = safe_inference(
|
|
1081
|
+
avg_att, avg_se, alpha=self.alpha, df=df
|
|
1082
|
+
)
|
|
1097
1083
|
|
|
1098
1084
|
# Count observations
|
|
1099
1085
|
n_treated = int(np.sum(d))
|