Observed since 21 Oct, 10:22 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Abnormal Impact Differential (AID) analysis with ANOVA significance testing for year-over-year event impact measurement.
Abnormal Impact Differential (AID) — a difference-in-differences style tool for measuring how much a metric deviated from its normal year-over-year pattern during a specific event window, with a two-way ANOVA significance test included.
pip install aid-analysis
Given daily (or other tidy) time-series data for one or more numeric metrics, AID asks:
"How much did my metric change from Period 1 to Period 2 this year, compared to how much it normally changes from Period 1 to Period 2 in a baseline year?"
The answer is a single number in percentage points (the AID), plus a p-value from a two-way ANOVA testing whether that difference is statistically significant.
$$\text{AID} = 100 \times \left[\left(\frac{\mu_{\text{current}, P_2}}{\mu_{\text{current}, P_1}} - 1\right) - \left(\frac{\mu_{\text{baseline}, P_2}}{\mu_{\text{baseline}, P_1}} - 1\right)\right]$$
A negative AID means the metric performed worse in the current year than prior-year seasonality would predict; positive means better.
from aid_analysis import run_analysis, PeriodConfig
cfg = PeriodConfig(
current_year=2026,
baseline_year=2025,
period_1=("01-29", "02-28"), # "before" window, inclusive
period_2=("03-01", "03-31"), # "after" window, inclusive
)
# Single metric
summary = run_analysis("data.csv", metrics="Revenue", config=cfg)
# Multiple metrics
summary = run_analysis(
"data.csv",
metrics=["Transactions", "Count of Users", "Revenue"],
config=cfg,
)
Your CSV just needs a date column and one or more numeric columns.
A tidy CSV (or pandas.DataFrame) with:
date column (any parseable date format — you can change the column name via PeriodConfig(date_col="..."))"Count of Users")Example:
date,Transactions,Revenue
2025-01-29,142,8930.50
2025-01-30,156,9420.00
...
2026-03-31,98,6110.25
Three things:
aid_summary.csv by default) with one row per metric.run_analysis() for further work.Example summary:
| metric | mean_2026_period_1 | mean_2026_period_2 | mean_2025_period_1 | mean_2025_period_2 | change_2026_pct | change_2025_pct | aid_pp | anova_interaction_pvalue |
|---|---|---|---|---|---|---|---|---|
| Revenue | 8,430.50 | 6,120.75 | 8,200.10 | 8,350.40 | -27.39 | 1.83 | -29.22 | 0.00023 |
For more control over intermediate steps:
from aid_analysis import AbnormalImpactAnalyzer, PeriodConfig
cfg = PeriodConfig(
current_year=2026,
baseline_year=2025,
period_1=("01-29", "02-28"),
period_2=("03-01", "03-31"),
)
analyzer = AbnormalImpactAnalyzer("data.csv", config=cfg)
analyzer.run(metrics=["Revenue", "Transactions"])
analyzer.print_report()
# Access individual results
revenue_result = analyzer.results["Revenue"]
print(revenue_result.delta_pp) # the AID value
print(revenue_result.anova_table) # full ANOVA table
print(revenue_result.anova_interaction_pvalue)
# Get the summary as a DataFrame
df = analyzer.summary_frame()
# Or export to CSV
analyzer.export("my_summary.csv")
| AID value | p-value | Meaning |
|---|---|---|
| Large negative | < 0.05 | Real, significant underperformance vs the seasonal baseline |
| Large negative | ≥ 0.05 | Looks like a drop, but could be random noise |
| Large positive | < 0.05 | Real, significant outperformance vs the seasonal baseline |
| Large positive | ≥ 0.05 | Looks like an uplift, but could be random noise |
| Near zero | any | No abnormal impact vs the prior-year pattern |
MIT
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.0 | 19 Apr 2026 | 6 |
This describes our collected data; it is not a security assessment.
Observed since 21 Oct, 10:22 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:f4c481da7cbfae64f5e841a69ae10b9b40edaed9a71417c8615fdf46e62b39d1