Post Analysis Toolkit
post_analysis_toolkit - локальная библиотека для пост-анализа промо, rollout-ов и других квази-экспериментальных задач, где нужен воспроизводимый causal / quasi-causal пайплайн.
Пакет закрывает типовой цикл:
- подготовили панель или временной ряд;
- проверили предпосылки метода;
- посчитали эффект;
- проверили устойчивость результата;
- получили табличные результаты и готовые графики.
Документация в этом файле ориентирована на пользователя пакета.
Что умеет пакет
- классический
Difference-in-Differences - регрессионный
DiD DiDсHC1robust SE или cluster-robust SEDiDсTWFEDiDс лог-трансформацией outcomeDiDс относительной индексацией outcomeSynthetic ControlCausal ImpactInterrupted Time SeriesTriple DifferenceRegression Discontinuity DesignPropensity Score MatchingDoubly Robust / AIPWEvent Studyс эффектами по временным бинам- проверки предпосылок по каждому методу
- базовые проверки устойчивости
- встроенные
matplotlib-графики
MDE и чувствительность
Для всех MDE по умолчанию используются alpha=0.05, power=0.80 и
двусторонний тест. Если метрика и дизайн допускают аналитическую оценку,
базовый ориентир — t-test/формула через корректную стандартную ошибку.
MDE относится к конкретному estimand и спецификации. В рабочем результате нужно отдельно показывать абсолютный MDE в единицах метрики, относительный MDE относительно явно указанного baseline и cumulative MDE за весь post-period.
Режим mde_mode="auto" используется по умолчанию: если у метода есть корректная
стандартная ошибка, выбирается аналитический расчет, иначе — параметрическая
симуляция. mde_mode="parametric" принудительно включает быструю параметрическую
симуляцию.
mde_mode="resampling" включает полноценные симуляции с генерацией данных и
повторным запуском оценивателя. Быстрый proxy доступен только явно как
mde_mode="proxy". Для симуляций число повторов будет задаваться параметром
n_simulations: 500 для отладки, 2000 для рабочего
расчета и 5000+ для финального отчета. Вместе с ним нужно сохранять
random_state и power curve.
Параметрическая симуляция: для каждого кандидатного эффекта пакет
генерирует оценки по схеме delta + Normal(0, uncertainty_scale). Для
регрессионных и observational-методов uncertainty_scale — SE. Для Event Study
это SE конкретного коэффициента конкретного временного бина, поэтому MDE
считается отдельно для каждого бина. Для
Synthetic Control/Causal Impact/ITS — pre-fit или validation RMSE,
нормированный на размер post-period.
В режиме resampling пакет создает псевдоданные: берет fitted/counterfactual
значения без эффекта, добавляет ресэмплированные центрированные остатки и
кандидатный эффект, а затем повторно запускает весь поддержанный оцениватель.
Для Synthetic Control заново подбираются веса, для PSM заново строится matching,
для Causal Impact заново обучается state-space модель, а для ITS заново
оценивается регрессия. Такой режим заметно медленнее и требует явно задать
разумное n_simulations и, при необходимости, mde_effect_grid.
Power curve можно посмотреть в
result.details["mde_power_curve"].
После вызова любой fit_* MDE читается так:
result.summary[["mde_absolute", "mde_relative", "mde_cumulative", "mde_mode_resolved"]]
result.details["mde_power_curve"]
Пример полноценного resampling-MDE для поддержанного метода:
result = fit_synthetic_control(
panel_df,
outcome_col="outcome",
unit_col="unit",
time_col="sale_date",
treated_unit="treated_city",
intervention_time="2026-02-01",
mde_mode="resampling",
n_simulations=200,
mde_effect_grid=[0, 2, 4, 6],
random_state=42,
)
result.summary[["mde_mode_resolved", "mde_absolute"]]
В этой версии для каждого кандидата эффекта создаются псевдоданные и заново
вызывается Synthetic Control. Поэтому resampling значительно медленнее
параметрического режима. Для нестандартного оценивателя можно передать
mde_simulator, который возвращает массив повторных оценок эффекта.
Параметры mde_mode, alpha, power, alternative, n_simulations,
random_state, mde_effect_grid и mde_simulator добавлены в функции оценки эффекта. Вызов с
mde_mode="proxy" дополнительно заполняет proxy_mde_*; при analytic-,
parametric- или resampling-режиме эти legacy-поля остаются пустыми.
8. PSM
Используй, когда:
- treatment бинарный
- есть наблюдаемые ковариаты, через которые можно объяснять селекцию в treatment
- хочется построить matched control на основе propensity score
В текущей версии пакет реализует ATT через nearest-neighbor matching по propensity score.
9. Doubly Robust
Используй, когда:
- treatment бинарный
- есть набор ковариат
- хочется оценку, устойчивую к ошибке в одной из двух моделей: propensity model или outcome model
В текущей версии это AIPW / doubly robust ATE.
Что пакет не делает
- не строит данные из сырых таблиц
- не проверяет бизнес-смысл метрик за тебя
- не знает, был ли contamination доноров
- не умеет автоматически находить “правильный” метод
- не снимает необходимость ручной интерпретации
То есть пакет отвечает за оценивание и diagnostics, а не за бизнес-контекст и data engineering.
Быстрый старт
Установка
В ноутбуке или Python-скрипте:
%pip install post-analysis-toolkit
Чтобы библиотека была доступна во всех ноутбуках персонального Databricks-кластера,
один раз добавьте PyPI-библиотеку
post-analysis-toolkit в разделе Libraries его настроек.
Базовый импорт
from post_analysis_toolkit import (
check_did_assumptions,
check_doubly_robust_assumptions,
fit_did_regression,
fit_event_study,
fit_doubly_robust,
fit_synthetic_control,
fit_causal_impact,
fit_its,
fit_psm,
fit_rdd,
fit_triple_difference,
)
Как начать, если видишь пакет впервые
Практически всегда работа с пакетом выглядит так:
- Подготовь данные в одном из поддерживаемых форматов:
панель
unit x time, один временной ряд или observational dataset. - Выбери метод под свой дизайн.
- Сначала запусти
check_*_assumptions(...). - Потом запусти
fit_* (...). - Если метод выглядит применимым, запусти
run_*_robustness(...). - Посмотри
summary,detailsиfigures.
Минимальный шаблон:
diag = check_did_assumptions(...)
display(diag.checks)
result = fit_did_regression(...)
display(result.summary)
robust = run_did_robustness(...)
display(robust.summary)
Особенно важно:
- подробное описание параметров теперь находится прямо внутри описания каждой функции, а не в отдельном общем словаре;
- если видишь аргумент вида
*_options, это почти всегда значит “перебор нескольких спецификаций”, а не “одна настройка модели”.
Как читать result-объекты
Почти все функции возвращают один из двух dataclass-объектов:
DiagnosticResult: результат проверки предпосылокMethodResult: результат расчета эффекта или robustness-check
Обычно внутри есть:
summary: компактная итоговая таблицаdetails: более подробные таблицы, например коэффициенты, веса, placebo-результатыfigures: готовыеmatplotlib-графикиmetadata: технические объекты, конфиги, fit-результаты библиотек
Базовые структуры данных
Panel data
Для DiD, Synthetic Control, Causal Impact ожидается длинная панель, обычно такого вида:
import pandas as pd
panel_df = pd.DataFrame(
{
"sale_date": [...],
"unit": [...], # город / пиццерия / страна / магазин
"metric": [...], # outcome
"treated_flag": [...], # 1 для treated, 0 для control
"post_flag": [...], # 1 после старта промо, 0 до
}
)
Минимальные требования:
time_colдолжен парситься в датуoutcome_colдолжен быть числовымtreated_colиpost_colдолжны кодироваться как0/1- для
Synthetic ControlиCausal Impactдолжен существоватьunit_col
Time series data
Для ITS нужен один временной ряд:
ts_df = pd.DataFrame(
{
"sale_date": [...],
"metric": [...],
}
)
Дополнительно можно передавать внешние фичи:
ts_df["weather_temp"] = ...
ts_df["holiday_flag"] = ...
Observational data
Для PSM и Doubly Robust нужен наблюдательный датасет с бинарным treatment:
obs_df = pd.DataFrame(
{
"user_id": [...],
"treatment_flag": [...], # 0/1
"outcome": [...],
"x1": [...],
"x2": [...],
"x3": [...],
}
)
Минимальные требования:
treatment_colбинарный0/1outcome_colчисловой- covariates должны быть числовыми или заранее закодированными
RDD data
Для RDD нужен срез наблюдений с running variable:
rdd_df = pd.DataFrame(
{
"running": [...], # расстояние до порога или исходная шкала
"outcome": [...],
"x1": [...], # optional covariates
}
)
Минимальные требования:
running_colчисловой- известен
cutoff - по обе стороны cutoff есть наблюдения
Triple Difference data
Для Triple Difference нужна панель с третьим бинарным измерением:
ddd_df = pd.DataFrame(
{
"sale_date": [...],
"unit": [...],
"treated_flag": [...],
"post_flag": [...],
"subgroup_flag": [...], # 1 = affected subgroup, 0 = internal control subgroup
"outcome": [...],
}
)
Полностью готовые минимальные примеры
Ниже четыре примера, которые можно буквально скопировать в ноутбук и запустить как первый smoke-test пакета.
1. End-to-end пример: DiD
import pandas as pd
from post_analysis_toolkit import (
check_did_assumptions,
fit_did_regression,
run_did_robustness,
)
did_df = pd.DataFrame(
{
"sale_date": pd.date_range("2026-02-01", periods=12, freq="D").tolist() * 2,
"unit": ["Batumi"] * 12 + ["Tbilisi"] * 12,
"metric": [
10, 11, 10, 12, 11, 10, 15, 16, 15, 17, 16, 15,
9, 10, 9, 11, 10, 9, 10, 11, 10, 12, 11, 10,
],
"treated_flag": [1] * 12 + [0] * 12,
}
)
did_df["post_flag"] = (did_df["sale_date"] >= pd.Timestamp("2026-02-07")).astype(int)
did_diag = check_did_assumptions(
did_df,
outcome_col="metric",
time_col="sale_date",
treated_col="treated_flag",
post_col="post_flag",
intervention_time="2026-02-07",
unit_col="unit",
cluster_col="unit",
)
print(did_diag.checks)
did_result = fit_did_regression(
did_df,
outcome_col="metric",
time_col="sale_date",
treated_col="treated_flag",
post_col="post_flag",
unit_col="unit",
cluster_col="unit",
twfe=True,
)
print(did_result.summary)
did_robust = run_did_robustness(
did_df,
outcome_col="metric",
time_col="sale_date",
treated_col="treated_flag",
post_col="post_flag",
intervention_time="2026-02-07",
unit_col="unit",
cluster_col="unit",
)
print(did_robust.summary)
2. End-to-end пример: Synthetic Control
import pandas as pd
from post_analysis_toolkit import (
check_synthetic_control_assumptions,
fit_synthetic_control,
run_synthetic_control_robustness,
)
dates = pd.date_range("2026-02-01", periods=14, freq="D")
sc_df = pd.DataFrame(
{
"sale_date": list(dates) * 3,
"unit": ["Batumi"] * 14 + ["Tbilisi"] * 14 + ["Kutaisi"] * 14,
"metric": (
[100, 101, 99, 100, 102, 101, 100, 110, 111, 109, 112, 111, 110, 109]
+ [98, 99, 97, 98, 100, 99, 98, 99, 100, 98, 101, 100, 99, 98]
+ [102, 103, 101, 102, 104, 103, 102, 103, 104, 102, 105, 104, 103, 102]
),
}
)
sc_diag = check_synthetic_control_assumptions(
sc_df,
outcome_col="metric",
unit_col="unit",
time_col="sale_date",
treated_unit="Batumi",
intervention_time="2026-02-08",
)
print(sc_diag.checks)
sc_result = fit_synthetic_control(
sc_df,
outcome_col="metric",
unit_col="unit",
time_col="sale_date",
treated_unit="Batumi",
intervention_time="2026-02-08",
)
print(sc_result.summary)
sc_robust = run_synthetic_control_robustness(
sc_df,
outcome_col="metric",
unit_col="unit",
time_col="sale_date",
treated_unit="Batumi",
intervention_time="2026-02-08",
)
print(sc_robust.summary)
3. End-to-end пример: ITS
import pandas as pd
from post_analysis_toolkit import (
check_its_assumptions,
fit_its,
run_its_robustness,
)
its_df = pd.DataFrame(
{
"sale_date": pd.date_range("2026-01-01", periods=20, freq="D"),
"metric": [
100, 102, 101, 103, 102, 101, 100, 102, 101, 103,
108, 110, 109, 111, 110, 109, 108, 110, 109, 111,
],
}
)
its_diag = check_its_assumptions(
its_df,
outcome_col="metric",
time_col="sale_date",
intervention_time="2026-01-11",
)
print(its_diag.checks)
its_result = fit_its(
its_df,
outcome_col="metric",
time_col="sale_date",
intervention_time="2026-01-11",
)
print(its_result.summary)
its_robust = run_its_robustness(
its_df,
outcome_col="metric",
time_col="sale_date",
intervention_time="2026-01-11",
)
print(its_robust.summary)
4. End-to-end пример: PSM
import pandas as pd
from post_analysis_toolkit import (
check_psm_assumptions,
fit_psm,
run_psm_robustness,
)
psm_df = pd.DataFrame(
{
"user_id": list(range(1, 13)),
"treatment_flag": [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
"outcome": [12, 11, 13, 12, 14, 13, 9, 8, 10, 9, 11, 10],
"x1": [30, 32, 31, 29, 33, 34, 30, 31, 29, 28, 32, 33],
"x2": [5, 6, 5, 4, 6, 7, 5, 5, 4, 4, 6, 6],
"x3": [100, 110, 105, 98, 115, 120, 99, 108, 101, 97, 112, 118],
}
)
psm_diag = check_psm_assumptions(
psm_df,
outcome_col="outcome",
treatment_col="treatment_flag",
covariate_cols=["x1", "x2", "x3"],
caliper=0.2,
)
print(psm_diag.checks)
psm_result = fit_psm(
psm_df,
outcome_col="outcome",
treatment_col="treatment_flag",
covariate_cols=["x1", "x2", "x3"],
caliper=0.2,
)
print(psm_result.summary)
psm_robust = run_psm_robustness(
psm_df,
outcome_col="outcome",
treatment_col="treatment_flag",
covariate_cols=["x1", "x2", "x3"],
caliper_options=(None, 0.1, 0.2),
neighbor_options=(1, 2),
)
print(psm_robust.summary)
Что возвращают функции
У пакета два основных result-объекта:
MethodResultDiagnosticResult
Оба описаны в contracts.py
MethodResult
Поля:
method- имя методаsummary- главный итоговыйDataFramedetails- словарь с дополнительными таблицамиfigures- словарьmatplotlib-фигурmetadata- служебные объекты, fit-модели, выбранные доноры и т.д.
DiagnosticResult
Поля:
method- имя диагностикиchecks- таблица проверок предпосылокdetails- вспомогательные таблицыfigures- диагностические графикиmetadata- служебная информация
Как обычно с этим работать
diag = check_did_assumptions(...)
display(diag.checks)
result = fit_did_regression(...)
display(result.summary)
display(result.details["coefficients"])
fig = result.figures["actual_vs_counterfactual"]
display(fig)
Рекомендуемый workflow
Для любого метода лучше идти одинаково:
- Проверить, что метрика и grain корректны.
- Проверить предпосылки через
check_*_assumptions. - Посчитать основной эффект через
fit_*. - Прогнать
run_*_robustness. - Уже после этого писать вывод.
Минимальный шаблон:
diag = check_did_assumptions(...)
display(diag.checks)
result = fit_did_regression(...)
display(result.summary)
robust = run_did_robustness(...)
display(robust.summary)
DiD: пример
Формат данных для функции
Пример для unit x day:
| sale_date | unit | metric | treated_flag | post_flag |
|---|---|---|---|---|
| 2026-02-10 | Batumi | 0.084 | 1 | 0 |
| 2026-02-10 | Tbilisi | 0.121 | 0 | 0 |
| 2026-02-11 | Batumi | 0.079 | 1 | 0 |
| 2026-02-25 | Batumi | 0.116 | 1 | 1 |
| 2026-02-25 | Tbilisi | 0.118 | 0 | 1 |
Обязательные колонки:
sale_dateunitmetrictreated_flagpost_flag
Опционально:
- ковариаты
- веса
- колонка для кластеризации ошибок
1. Проверка предпосылок
from post_analysis_toolkit import check_did_assumptions
did_diag = check_did_assumptions(
df=panel_df,
outcome_col="metric",
time_col="sale_date",
treated_col="treated_flag",
post_col="post_flag",
intervention_time="2026-02-25",
unit_col="unit",
cluster_col="unit",
event_bin_size=7,
)
Что смотреть:
- строку
Корреляция treated/control на предпериоде - строку
Разница наклонов тренда на предпериоде - строку
p-value разницы наклонов на предпериоде - строку
p-value joint-теста лидов в event study - графики
pretrend_triptychиevent_study
2. Оценка эффекта
from post_analysis_toolkit import fit_did_regression
did_result = fit_did_regression(
df=panel_df,
outcome_col="metric",
time_col="sale_date",
treated_col="treated_flag",
post_col="post_flag",
unit_col="unit",
cluster_col="unit",
twfe=True,
log_transform=False,
relative=False,
)
Главные поля в summary:
effect_absolute,effect_relative,effect_cumulativep_valueeffect_cimde_absolute,mde_relative,mde_cumulative,mde_mode_resolveddetails["mde_power_curve"]
Для DiD режим auto по умолчанию считает MDE аналитически через SE interaction-
оценки. Параметрический режим можно включить через mde_mode="parametric", а
полноценный повторный запуск регрессии — через mde_mode="resampling". При
кластеризации ориентируйся также на stderr_type.
3. Robustness
from post_analysis_toolkit import run_did_robustness
did_robust = run_did_robustness(
df=panel_df,
outcome_col="metric",
time_col="sale_date",
treated_col="treated_flag",
post_col="post_flag",
unit_col="unit",
cluster_col="unit",
)
Это прогоняет набор спецификаций:
- с
TWFEи без - с логами и без
- с относительной индексацией и без
Synthetic Control: пример
Формат данных для функции
Пример для unit x day с одним treated unit и несколькими донорами:
| sale_date | unit | metric |
|---|---|---|
| 2026-02-10 | Batumi | 0.084 |
| 2026-02-10 | Tbilisi | 0.121 |
| 2026-02-10 | Kutaisi | 0.097 |
| 2026-02-11 | Batumi | 0.079 |
| 2026-02-11 | Tbilisi | 0.120 |
Обязательные колонки:
sale_dateunitmetric
Что важно:
- одна строка на один
unitв одну дату - donor units не должны быть затронуты treatment
- metric должна быть сопоставима между unit-ами
from post_analysis_toolkit import (
check_synthetic_control_assumptions,
fit_synthetic_control,
run_synthetic_control_robustness,
)
synth_diag = check_synthetic_control_assumptions(
df=panel_df,
outcome_col="metric",
unit_col="unit",
time_col="sale_date",
treated_unit="Batumi",
intervention_time="2026-02-25",
donor_units=["Tbilisi", "Kutaisi"],
)
synth_result = fit_synthetic_control(
df=panel_df,
outcome_col="metric",
unit_col="unit",
time_col="sale_date",
treated_unit="Batumi",
intervention_time="2026-02-25",
donor_units=["Tbilisi", "Kutaisi"],
)
synth_robust = run_synthetic_control_robustness(
df=panel_df,
outcome_col="metric",
unit_col="unit",
time_col="sale_date",
treated_unit="Batumi",
intervention_time="2026-02-25",
donor_units=["Tbilisi", "Kutaisi"],
)
Что смотреть:
donor_countpre_rmsepre_r2pre_corravg_post_effectavg_post_relative_effect- таблицу весов
details["weights"]
Проверки устойчивости:
- placebo по каждому донору
- leave-one-out по донорам
Causal Impact: пример
Формат данных для функции
Формат на вход такой же, как у Synthetic Control.
Пример:
| sale_date | unit | metric |
|---|---|---|
| 2026-02-10 | Batumi | 0.084 |
| 2026-02-10 | Tbilisi | 0.121 |
| 2026-02-10 | Kutaisi | 0.097 |
| 2026-02-11 | Batumi | 0.079 |
| 2026-02-11 | Tbilisi | 0.120 |
Обязательные колонки:
sale_dateunitmetric
Что важно:
- treated unit один
- pre-period должен быть достаточно длинным
- после выравнивания treated и donor рядов не должно быть пропусков
from post_analysis_toolkit import (
check_causal_impact_assumptions,
fit_causal_impact,
run_causal_impact_robustness,
)
ci_diag = check_causal_impact_assumptions(
df=panel_df,
outcome_col="metric",
unit_col="unit",
time_col="sale_date",
treated_unit="Batumi",
intervention_time="2026-02-25",
donor_units=["Tbilisi", "Kutaisi"],
)
ci_result = fit_causal_impact(
df=panel_df,
outcome_col="metric",
unit_col="unit",
time_col="sale_date",
treated_unit="Batumi",
intervention_time="2026-02-25",
donor_units=["Tbilisi", "Kutaisi"],
)
ci_robust = run_causal_impact_robustness(
df=panel_df,
outcome_col="metric",
unit_col="unit",
time_col="sale_date",
treated_unit="Batumi",
intervention_time="2026-02-25",
donor_units=["Tbilisi", "Kutaisi"],
)
Что смотреть:
- строку
R2 на валидации - строку
RMSE на валидации average_abs_effectaverage_rel_effecteffect_absolute,effect_relative,effect_cumulativeeffect_absolute_ci,effect_relative_ciposterior_tail_areamde_absolute,mde_relative,mde_cumulative,mde_mode_resolveddetails["mde_power_curve"]
Для Causal Impact simulation-режим много раз получает случайную оценку с масштабом, равным RMSE на валидации. Это еще не повторный запуск state-space pipeline для каждого pseudo-dataset; такой callback остается отдельным расширением.
Проверки устойчивости:
- placebo по более ранним датам
- leave-one-out по донорам
ITS: пример
Формат данных для функции
Базовый пример для одного временного ряда:
| sale_date | metric |
|---|---|
| 2026-01-01 | 125.0 |
| 2026-01-02 | 118.0 |
| 2026-01-03 | 133.0 |
| 2026-02-25 | 149.0 |
| 2026-02-26 | 152.0 |
Если есть дополнительные регрессоры:
| sale_date | metric | weather_temp | holiday_flag |
|---|---|---|---|
| 2026-01-01 | 125.0 | 8.3 | 1 |
| 2026-01-02 | 118.0 | 7.9 | 0 |
| 2026-02-25 | 149.0 | 10.4 | 0 |
Обязательные колонки:
sale_datemetric
Что важно:
- одна строка на одну дату
- доп. фичи должны быть на том же дневном grain
- ряд должен быть числовым и упорядочиваемым по времени
from post_analysis_toolkit import (
build_standard_its_features,
check_its_assumptions,
fit_its,
run_its_robustness,
)
its_diag = check_its_assumptions(
df=ts_df,
outcome_col="metric",
time_col="sale_date",
intervention_time="2026-02-25",
)
its_result = fit_its(
df=ts_df,
outcome_col="metric",
time_col="sale_date",
intervention_time="2026-02-25",
)
its_robust = run_its_robustness(
df=ts_df,
outcome_col="metric",
time_col="sale_date",
intervention_time="2026-02-25",
)
По умолчанию ITS использует:
time_indexpost_flagtime_after_intervention- day-of-week dummies
month_start_flagmonth_end_flag
Можно добавить дополнительные фичи:
its_result = fit_its(
df=ts_df,
outcome_col="metric",
time_col="sale_date",
intervention_time="2026-02-25",
extra_feature_cols=["weather_temp", "holiday_flag"],
)
Что смотреть:
avg_abs_effectavg_rel_effecteffect_absolute,effect_relative,effect_cumulative- строку
R2 на валидации - строку
RMSE на валидации - строку
Средний rolling R2 на валидации mde_absolute,mde_relative,mde_cumulative,mde_mode_resolveddetails["mde_power_curve"]
Для ITS simulation-режим много раз получает случайную оценку с масштабом, равным RMSE на валидации. Он относится к выбранному агрегированному постпериодному estimand и не является отдельным MDE для level и slope.
Проверки устойчивости:
- разные длины pre-window
- placebo intervention dates
- разные feature sets
Стандартные проверки предпосылок
Во всех checks-таблицах пакет теперь возвращает русские колонки:
проверказначениеориентир
Для DiD
- визуальная параллельность трендов
- pre-period correlation
- slope gap на pre-period
- joint pre-trend test через event study
- отсутствие параллельных изменений
Для Synthetic Control
- достаточно доноров
- хороший pre-fit
- отсутствие contamination доноров
- reasonable donor weights
Для Causal Impact
- достаточно длинный pre-period
- нормальное predictive quality на pre-period
- отсутствие пропусков после выравнивания
- отсутствие contamination контрольных рядов
Для ITS
- достаточно длинный pre-period
- нет сильных дырок в датах
- модель более-менее объясняет pre-period
- residual diagnostics не выглядят катастрофически
- нет явных concurrent changes
Интерпретация результатов
Пакет возвращает числа, но не ставит автоматический ярлык “causal effect proven”.
Практически удобно мыслить так:
- если assumptions слабые, а эффект красивый - не переоценивай вывод
- если assumptions хорошие, но
MDEогромный - отсутствие значимости мало что значит - если robustness разваливается - основной результат надо считать хрупким
- если control-конструкция сомнительна - лучше честный descriptive / benchmark framing
Типичные ошибки
1. Неправильный grain
Например:
- treated на уровне города
- а outcome собран на уровне товара x день без аккуратной агрегации
Сначала выровняй unit анализа.
2. Плохой pre-period
Если pre-period слишком короткий, то:
ITSбудет слабымCausal Impactбудет плохо предсказыватьSynthetic Controlбудет переобучаться
3. Перепутан post_flag
Проверь, что:
- до даты intervention
post_flag = 0 - начиная с даты intervention
post_flag = 1
4. Causal-язык без проверок
Нельзя говорить “акция вызвала рост”, если:
- assumptions не прошли
- donor pool слабый
- robustness разваливается
Рекомендации по использованию в пост-анализах
- Для продаж с нормальным donor pool начинай с
Synthetic ControlилиCausal Impact - Для benchmark-сравнения treated vs control держи
DiD - Если контроль надежно собрать не удалось, переходи к
ITS - Если даже
ITSслабый, оставляй descriptive analysis
Где смотреть готовые примеры
- демо-скрипт: run_post_analysis_toolkit_demo.py
- демо-скрипт: demo.py
- smoke-тесты: test_smoke.py
- Batumi notebook v2: batumi_sales_effect_validation_notebook_v2.ipynb
Публичный API
Пакет экспортирует:
compute_classic_didfit_did_regressionfit_event_studycheck_did_assumptionsrun_did_robustnessfit_triple_differencecheck_triple_difference_assumptionsrun_triple_difference_robustnessfit_rddcheck_rdd_assumptionsrun_rdd_robustnessfit_psmcheck_psm_assumptionsrun_psm_robustnessfit_doubly_robustcheck_doubly_robust_assumptionsrun_doubly_robust_robustnessfit_synthetic_controlcheck_synthetic_control_assumptionsrun_synthetic_control_robustnessfit_causal_impactcheck_causal_impact_assumptionsrun_causal_impact_robustnessbuild_standard_its_featuresfit_itscheck_its_assumptionsrun_its_robustness
Ограничения текущей версии
Synthetic Controlздесь реализован в облегченной форме, без сложного набора pre-treatment predictorsCausal Impactзависит от сторонней библиотеки и требует аккуратного окруженияMDEпо умолчанию выбирает аналитический расчет при наличии SE, а для методов без аналитической формы использует параметрическую симуляцию; режимresamplingпереобучает поддержанный расчет на каждом повторе- contamination и concurrent changes проверяются вручную, а не автоматически
Версия
Текущая версия пакета: 1.0.5
Metadata
Release files for post-analysis-toolkit 1.0.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| post_analysis_toolkit-1.0.5.tar.gz | 125.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| post_analysis_toolkit-1.0.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 238.6 kB
Release files / post_analysis_toolkit-1.0.5.tar.gz
| Download URL | post_analysis_toolkit-1.0.5.tar.gz |
|---|---|
| Size | 125.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
03d9db5f8703de73ceef72d170dc8778e32b9c6bca094a91bc8f111ca40116a1
|
|
BLAKE2b-256 checksum How to use checksums |
d51dd2a2c676bdedb984a93d7bf834c45a6623d8993cf0614f59ef70da657cdc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 19, 2026.
Transparency logRelease files / post_analysis_toolkit-1.0.5-py3-none-any.whl
| Download URL | post_analysis_toolkit-1.0.5-py3-none-any.whl |
|---|---|
| Size | 113.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3d50bbc20a755abf019572eca949d967386ddc864a63ced62d7a8a58d53854a5
|
|
BLAKE2b-256 checksum How to use checksums |
0d694174a0cb65d8c1ed6d6095cdbe77f710f983dd5b2352353d953a63544b84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 19, 2026.
Transparency log