Лучше бы доверились картам таро, чем такому гео-эксперименту

Гео-тесты обычно случаются не от хорошей жизни…Когда фича раскатывается на уровне города или региона (новая логистика в доставке, рекламная кампания на ТВ, изменение цен на маркетплейсе для конкретного рынка), обычный AB на уровне юзера невозможен в принципе, потому что юзеры внутри одного города получают тритмент скопом и разбить их нельзя. Ну вот ты собираешь панель город x период, запускаешь diff-in-diff, получаешь p меньше 0.05, отчитываешься команде про значимый рост на 3%, но… после полного запуска эффект куда-то испаряется, и ты привычно скидываешь всю вину на novelty effect, сезонность или ретроградный меркурий. Это сработает раз, ну два, но если чаще, то к такому аналитику могут возникнуть вопросики. Давайте разбираться, как такое чинить

И кто поможет разобраться

Как обычно — умные люди: на прошлой неделе на выложили статью Айзека Гербера из Meta, которая объясняет, что дело часто не в косячном дизайне теста, а в стандартных ошибках, которые ты считаешь по дефолту. Если ты применяешь современные DiD оценщики к панели, где наблюдения собраны кластерами (юзеры внутри городов, заказы внутри ресторанов, водители внутри хабов), а стандартные ошибки считаешь как HC1 или HC3, то ты неявно предполагаешь iid (значение одного наблюдения ничего не говорит про другое) между юзерами, которого там нет и в помине. Гербер прогоняет 66 тысяч симуляций и показывает, что покрытие 95-процентного доверительного интервала падает до 34% при базовом дизайне опроса и ниже 11% при информативной выборке, и это означает что в двух третях случаев твой CI вообще не накрывает истинный эффект

Я воспроизвёл этот сюжет на синтетическом geo-эксперименте, и картина вышла даже драматичнее. При 40 городах по 200 юзеров покрытие HC1 составляет 9.6%, при 1000 юзеров на город падает до 4.4%, а кластерные SE по city_id держат стабильные 92-95%, то есть с ростом размера выборки внутри кластера ситуация не улучшается, а ухудшается, потому что HC1 видит больше независимых наблюдений и становится ещё увереннее в неправильном ответе. Увеличение числа городов тоже не лечит, лечит только переход на кластерную дисперсию

Как как, говоришь, лечить?

В statsmodels это одна строка, cov_type=‘cluster’ с указанием city_id как групп, в linearmodels аналогично, в R это vcovCL или пакет sandwich. Точечная оценка не меняется, меняется только SE, и она вырастает в моих симуляциях в 13 раз при средних настройках и в 30 раз при тысяче юзеров на город. Иногда «значимый» результат после правильного учёта кластеров перестаёт быть значимым, и это значит, что таро было бы дешевле