Все материалы
Продуктовая аналитикагайдсредний

Почему метрика обманывает: состав, календарь, база и декомпозиция

Как честно посчитанная метрика приводит к неверному выводу: парадокс Симпсона, регрессия к среднему, сезонность, аномалии и декомпозиция роста по вкладам сегментов.

КПКейсПрактика2 августа 2026 г.23 мин
Содержание статьи

В недельном отчёте конверсия выросла с 13% до 32%. Запрос написан правильно, знаменатель тот же, дубли проверены, данные свежие. А внутри обоих каналов, из которых собран этот показатель, конверсия упала: 10% → 9% и 40% → 35%. Обе цифры верны одновременно, и решение «увеличить бюджет, раз работает» закрепит ухудшение. Это не курьёз и не ошибка в SQL: агрегат смешивает размер сегмента с его качеством, и вес пересилил ставку. Дальше — пять механизмов, из-за которых корректно посчитанное число ведёт к неверному выводу, и порядок проверок, который ловит их до того, как изменение объяснят поведением пользователей.

Коротко

Почти любое изменение метрики допускает четыре объяснения. Три из них не имеют отношения к продукту, и проверяются они быстрее, чем четвёртое.

  • Состав: изменились веса сегментов, а не поведение внутри них — парадокс Симпсона.
  • База: предыдущая точка была экстремальной, и возврат к норме произошёл бы сам — регрессия к среднему.
  • Календарь: сравниваются разные дни недели, месяцы разной длины или несезонные периоды.
  • Данные: алерт сработал на опоздавшей загрузке, а не на продукте.
  • И только после этих четырёх — гипотеза о том, что пользователи стали вести себя иначе.
  • Декомпозиция на множители превращает «метрика выросла» в набор проверяемых вкладов и закрывает все предыдущие ловушки сразу.

У одного роста есть четыре объяснения, и продукт — последнее в очереди

Агрегированное число — это результат арифметики над множеством строк. Оно меняется, когда меняется хотя бы одно из трёх: какие строки попали в расчёт, с чем именно ты сравниваешь текущую точку, и что происходило внутри строк. Первые два пункта не про продукт вообще, но выглядят они точно так же, как третий: цифра в отчёте просто становится другой.

Порядок проверок стоит выбирать по их стоимости. Пересчёт на фиксированных весах — это один запрос. Сравнение с тем же днём недели — фильтр в дашборде. Проверка свежести источника — минута. А доказательство того, что изменилось поведение, требует контрольной группы и недель ожидания. Если начать с самого дорогого объяснения, дешёвые остаются непроверенными, и в отчёт уезжает кейс успеха, который держится на изменении микса трафика.

Неприятная деталь: эти механизмы складываются. Маркетинг увеличил долю сильного канала (состав), это совпало с началом учебного сезона (календарь), а на прошлой неделе был провальный день после инцидента (база). Каждый из трёх эффектов даёт по несколько процентных пунктов, и вместе они рисуют убедительный рост, в котором от релиза нет ничего.

Симптом и первый подозреваемый
Что видно в отчётеПервая проверкаМеханизм
общий рост, сегменты падаютпересчёт на фиксированных весахпарадокс Симпсона
улучшение после провалаholdout с тем же правилом отборарегрессия к среднему
рост к прошлой неделесравнение с тем же днём неделисезонность
резкий скачок внизfreshness и полнота текущего дняпроблема данных
рост без объясненияразложение на множителинужна декомпозиция

Конверсия выросла с 13% до 32%, хотя в каждом канале она упала

Разберём тот случай из вступления по строкам. В июне канал A привёл 900 пользователей с конверсией 10%, канал B — 100 пользователей с конверсией 40%. Всего 90 + 40 = 130 конверсий на 1 000 пользователей, то есть 13%. В июле закупка перевернулась: A дал 100 пользователей, B — 900. Конверсия внутри каждого канала просела: A до 9%, B до 35%. Считаем: 9 + 315 = 324 конверсии на 1 000, то есть 32,4%.

Общая конверсия выросла в два с половиной раза, пока оба её источника ухудшились. Причина в том, что отношение сумм не равно среднему отношений: вес канала задаётся его знаменателем. Доля дорогого сильного канала B выросла с 10% до 90% трафика, и этот сдвиг веса пересилил падение ставок внутри обоих каналов.

Тот же механизм переворачивает вывод в A/B-тесте, и там он опаснее, потому что эксперимент принято считать защитой от подобных искажений. Вариант выигрывает и на mobile, и на desktop: 2% → 6% и 12% → 18%. Но в контроль попало 3 000 мобильных и 7 000 десктопных пользователей, а в тест — 9 000 мобильных и 1 000 десктопных. Конверсия контроля: (60 + 840) / 10 000 = 9,0%. Конверсия теста: (540 + 180) / 10 000 = 7,2%. Итоговый uplift минус 1,8 п.п. при плюс 4 и плюс 6 п.п. в сегментах.

В эксперименте такой перекос — это не парадокс, а сломанная рандомизация: сильный и слабый сегменты распределены по вариантам неравномерно. Поэтому SRM-проверку делают не только на общем размере групп, но и в разрезе ключевых сегментов. Совпадение суммарных 10 000 против 10 000 ничего не гарантирует.

Почему нельзя усреднять проценты
rate_total = Σ conversions / Σ users ≠ average(rate_segment)

Вес сегмента в общей метрике равен его знаменателю. Среднее по сегментам даёт другое число и отвечает на другой вопрос.

Та же картина в числителях и знаменателях
ГруппаИюньИюльЧто изменилось
Канал A90 / 900 = 10%9 / 100 = 9%ставка вниз, вес вниз
Канал B40 / 100 = 40%315 / 900 = 35%ставка вниз, вес вверх
Всего130 / 1000 = 13%324 / 1000 = 32,4%микс маскирует падение
На весах июня13%11,6%сопоставимое сравнение
Один набор данных, два противоположных ответа

Факт: 13% → 32,4%. На весах июня (90% A, 10% B) тот же июль даёт 0,09 × 0,9 + 0,35 × 0,1 = 11,6%. Сегментные ставки упали обе, поэтому сопоставимое сравнение показывает падение, а не рост.

Июнь, %Июль, %
Признак, по которому это видно за минуту

Положи рядом две колонки: метрику по сегментам и размер сегмента. Если знак изменения метрики и знак изменения доли расходятся хотя бы у одного крупного сегмента, общий агрегат уже нельзя читать как характеристику качества.

Фиксированный микс: один запрос, который отделяет состав от поведения

Пересчёт на фиксированных весах работает так: ставки берём из текущего периода, а доли сегментов — из опорного. Получается ответ на вопрос «какой была бы метрика, если бы состав трафика не менялся». Разница между фактом и этим числом и есть вклад микса.

Опорный период приходится выбирать, и выбор меняет число. На весах июня июль даёт 11,6% против июньских 13%. На весах июля июнь дал бы 0,10 × 0,1 + 0,40 × 0,9 = 37% против фактических 32,4% в июле. Оба сценария показывают падение, и это как раз тот случай, когда вывод устойчив: знак не зависит от выбора весов. Если бы знаки разошлись, в отчёт пошли бы оба числа с пояснением, какой вопрос закрывает каждое.

Поэтому перед расчётом полезно назвать вслух, про какую популяцию спрашиваешь. «Что мы получаем сейчас» — это факт с текущим миксом, им считают выручку и планируют мощности. «Стали ли каналы хуже» — это фиксированный микс. «Что даст изменение продукта» — это уже эффект внутри сегмента, и на него агрегат не отвечает вовсе.

Факт и фиксированный микс в одном результате
with seg as (
  select
    period,
    channel,
    count(*)                              as users,
    count(*) filter (where converted)     as conversions
  from visits
  where period in ('2026-06', '2026-07')
  group by period, channel
),
base_weights as (
  -- веса опорного периода: фиксируем состав трафика
  select channel, users::numeric / sum(users) over () as weight
  from seg
  where period = '2026-06'
)
select
  s.period,
  sum(s.conversions)::numeric / sum(s.users)                     as rate_fact,
  sum(w.weight * s.conversions::numeric / s.users)               as rate_fixed_mix
from seg s
join base_weights w using (channel)
group by s.period
order by s.period;
  • Ключевые разрезы выбирай до того, как увидел расхождение: канал, платформа, страна, тариф, новизна пользователя.
  • Сегменты с маленьким знаменателем объединяй в «прочее», иначе шум в них будет выглядеть как эффект.
  • В эксперименте проверяй баланс сегментов, а не только суммарный размер групп.
  • Если в отчёте остаётся одно число, рядом должна стоять строка «вклад микса» с её знаком.

Плохой день сменяется хорошим сам, и баннер тут не при чём

Второй механизм срабатывает, когда решение принимают после экстремального значения. Во вторник конверсия упала с обычных 7,8% до 4,1%. В среду включили новый баннер, и дальше пошло 6,0%, 7,1%, 7,6%. Кажется, баннер вернул метрику. На самом деле вернулась сама метрика: экстремальная точка содержала много случайного шума, а следующее измерение того же процесса естественно оказывается ближе к его среднему.

Регрессия к среднему — это не сила, которая тянет показатель к норме. Это следствие двух решений: наблюдение выбрано по экстремальному значению, а оценивают его на новом измерении. Чем больше доля шума относительно устойчивого сигнала, тем сильнее иллюзия. На метрике с размахом ±0,3 п.п. эффект почти не заметен, на конверсии маленького сегмента он даёт те самые три с половиной пункта «роста».

Тот же сценарий встречается вне дашбордов. Поддержка обзвонила клиентов с самым долгим временем ответа — через неделю время сократилось. Ретаргетинг догнал пользователей, которые только что положили товар в корзину, — конверсия оказалась высокой. Магазины с упавшими продажами получили программу поддержки — продажи подросли. В каждом случае часть улучшения случилась бы без вмешательства, потому что отбор шёл по значению, которое само по себе было необычным.

Возврат к норме происходит и там, где ничего не делали

Обе группы отобраны по одному правилу — провал во вторник. Вмешательство получила только первая. К четвёртому дню разрыв между ними 0,1 п.п., а «рост» внутри каждой группы — около 3,5 п.п.

Баннер включили, %Holdout, %

Правило отбора и окно оценки должны быть разными вещами

Защита здесь не статистическая, а процедурная: отбор и оценка разводятся во времени и в данных. Зафиксируй baseline до отбора — каким был показатель у этих объектов раньше, а не в тот день, когда они попали в список. Выбери окно оценки, которое не пересекается с окном отбора. И оставь holdout: часть объектов, прошедших тот же фильтр, но не получивших вмешательства.

Holdout решает задачу, с которой не справляется сравнение «до и после»: он движется к среднему точно так же, как обработанная группа. Поэтому ответом становится не изменение внутри группы, а разница между группами. В примере выше это 0,1 п.п. вместо 3,5 п.п. — и дальше вопрос уже не «помог ли баннер», а «хватает ли нам мощности, чтобы отличить 0,1 п.п. от нуля».

Отдельно: реагировать на инцидент нужно. Никто не просит ждать контрольную группу, когда сломан checkout. Разделяются не действия, а выводы: срочное исправление остаётся срочным исправлением, а доказательством влияния оно становится только при наличии baseline, контроля и независимого окна. Если команда регулярно вмешивается после плохих дней, стоит один раз посчитать, как ведут себя такие дни сами по себе — и дальше сравнивать с этим числом, а не с нулём.

Четыре вопроса к «эффекту после плохого дня»
ВопросЧто смотретьСигнал, что это регрессия
Как выбрали объектыправило отбораотобраны по самому outcome
Что в holdoutпараллельная динамикатам такое же улучшение
Сколько держится эффектнесколько окон подрядвозврат к baseline за день-два
Что изменилось в продуктерелизы и логиобъяснение только ручное

38 против 27: половина «падения» — это просто воскресенье

Третий механизм — календарь. Типичная недельная форма DAU в B2C-продукте: 42, 39, 38, 40, 41 тысячи в рабочие дни и 30, 27 в выходные. Сравнение среды с воскресеньем даёт минус 29%, сравнение воскресенья с понедельником — плюс 56%. Оба числа посчитаны верно и не значат ничего: они описывают день недели, а не продукт.

Тренд, сезонность и шум — три разные части ряда. Тренд — устойчивое движение уровня. Сезонность — повторяемый паттерн с известным периодом: день недели, месяц, квартал, учебный год. Шум — остаток, который выбранная модель не объясняет. Разовое событие вроде релиза или аварии сезонностью не является, даже если совпало дважды: для сезонности нужен механизм, который объясняет, почему паттерн повторяется.

Календарь ломает и годовые сравнения. Недельная активность выросла на 18% после email-кампании, но кампания попала на начало учебного сезона, когда аудитория возвращается сама. Более аккуратный разбор выглядел так: плюс 9% к той же неделе прошлого года, из которых 6 п.п. объясняются возвратом учебной аудитории, а устойчивый тренд — около 3%. Локальный рост на iOS после релиза остался гипотезой до следующей когорты.

Месяцы разной длины — отдельная ловушка, потому что её не видно. В феврале 28 дней, в марте 31: это плюс 10,7% объёма при полностью неизменном поведении. Любое месячное сравнение абсолютных величин требует нормализации на число дней или на число рабочих дней, если метрика про B2B.

Недельный профиль DAU и его сглаженный уровень

Среднее за семь дней — 36,7 тыс. Сглаживание показывает уровень, но стирает форму: по линии rolling-7 не видно, что воскресенье ниже среды на 29%.

DAU, тыс.Среднее за 7 дней, тыс.

Четыре сравнения одного ряда отвечают на четыре разных вопроса

Вместо спора о «правильном» способе сравнения проще держать рядом все четыре и помнить, что каждый ловит. День к предыдущему дню реагирует мгновенно и путается в дне недели. Неделя к неделе снимает дневную сезонность, но ломается на празднике внутри окна. Скользящее среднее за семь дней показывает уровень и с задержкой примерно в три дня прячет инцидент. Год к году ловит сезонно похожий период, но за год меняется состав базы — и тогда к календарной ловушке добавляется ловушка состава из третьего раздела.

Сглаживание полезно и опасно одновременно. Оно убирает дневную пилу, но размазывает провал: падение на 40% в один день на rolling-7 выглядит как аккуратная ступенька минус 6%. Поэтому в дашборде держат обе линии — raw и сглаженную, — а аннотации релизов и акций рисуют прямо на графике. Зритель должен видеть, откуда взялась точка и с каким периодом её сравнивают.

Последний день почти всегда неполный. Если его не отрезать или не подписать, каждое утро метрика будет «падать» — и команда постепенно научится не верить графику. Для рядов с задержкой загрузки работает простое правило: показывать только зрелые окна, а незрелый хвост рисовать другим цветом.

Что ловит каждое сравнение
СравнениеОтвечает на вопросГде ошибается
День к днючто случилось вчерадень недели и неполный день
WoW по тому же днюменяется ли недельный уровеньпраздник внутри окна
Rolling 7где находится уровеньпрячет и запаздывает
YoY (сдвиг 364 дня)сезонно похожий периодза год сменился состав базы
pythonЧетыре сравнения в одном DataFrame
daily = events.set_index('date').resample('D')['user_id'].nunique().to_frame('dau')

daily['dod'] = daily['dau'].pct_change()                       # день к предыдущему
daily['wow'] = daily['dau'] / daily['dau'].shift(7) - 1        # тот же день недели
daily['rolling_7'] = daily['dau'].rolling(7, min_periods=7).mean()
daily['yoy'] = daily['dau'] / daily['dau'].shift(364) - 1      # 364, чтобы совпал день недели

# незрелый хвост не сравниваем
daily = daily.loc[: daily.index.max() - pd.Timedelta(days=1)]

Падение на 28% оказалось опозданием загрузки на два часа

Четвёртый механизм живёт на стыке аналитики и данных. В 10:00 дашборд показал минус 28% к обычному уровню DAU. Проверка заняла пять минут: ingestion отставал на два часа, сырые события продолжали поступать, продукт работал. Продуктового инцидента не было, но тревожный красный прямоугольник в отчёте был.

Аномалия — это наблюдение, заметно отличающееся от ожидаемого по выбранной модели baseline. Значит, первое решение — не порог, а baseline. Скользящая медиана устойчивее среднего к выбросам. Медиана по тем же дням недели сразу снимает сезонность из предыдущего раздела. Прогноз с явной сезонной составляющей точнее, но требует ухода. z-score разумен на более-менее симметричном распределении, IQR спокойнее переносит тяжёлые хвосты; на счётчиках с правой асимметрией оба работают лучше после логарифмирования.

Второе решение — минимальный объём. Без него правило будет срабатывать на сегментах из сорока пользователей, где разница в шесть конверсий даёт минус 30% и ничего не означает. Порог по объёму обрезает эти сегменты до того, как они попадут в алерт, и заодно снимает добрую половину ложных срабатываний.

Третье — признание того, что после сильного релиза уровень может честно измениться. z-score, считающий baseline по последним 28 дням, будет неделю объявлять аномалией новую норму. Либо окно пересчитывают после подтверждённого сдвига уровня, либо правило знает про даты релизов.

Отклонение от baseline по дням

Обычный разброс ±4%. Точка минус 24% выходит за него, но это ещё не вывод: она одинаково совместима с инцидентом продукта, опоздавшей загрузкой и праздником.

Отклонение от baseline, %
pythonBaseline, который уже знает про день недели
s = orders.set_index('date')['orders'].asfreq('D').to_frame('value')
s['dow'] = s.index.dayofweek

# медиана четырёх предыдущих таких же дней недели
s['baseline'] = (
    s.groupby('dow')['value']
     .transform(lambda x: x.shift(1).rolling(4, min_periods=3).median())
)
s['delta_pct'] = s['value'] / s['baseline'] - 1

# порог по объёму отсекает шум маленьких дней
alerts = s[(s['delta_pct'].abs() > 0.15) & (s['baseline'] >= 200)]

Алерт без диагностики превращается в шум через две недели

Детектирование и диагностика — разные задачи, и смешивать их в одном сигнале дорого. Детектирование отмечает отклонение. Диагностика собирает контекст: свежесть источника, полнота текущего дня, доля NULL в ключевых полях, дубли, деплои за сутки, поведение соседних метрик и разбивка по платформам и версиям. Результатом проверки должен быть статус, а не обсуждение: подтверждённый инцидент, проблема данных, ожидаемая сезонность или «пока непонятно» с назначенным владельцем и сроком.

Мониторинг полезно разделить на слои, потому что у них разные владельцы и разная скорость реакции. Freshness отвечает на вопрос «данные пришли вовремя». Completeness — «события и поля на месте». Бизнес-слой — «метрика отклонилась от ожидаемой». Когда эти сигналы слиты в один, продуктовая команда получает алерт о конверсии, причина которого лежит в пайплайне, и тратит час на поиск того, чего не случилось.

Чувствительность настраивается не на глаз, а бэктестом. Прогони правило по истории за полгода, посчитай число срабатываний и долю тех, которые оказались ничем. Двадцать алертов в неделю означают, что их перестанут читать к концу месяца. Отдельно проверь, ловит ли мониторинг искусственную задержку данных: подвинь загрузку на три часа и посмотри, сработает ли freshness-сигнал раньше бизнес-метрики.

Слои мониторинга и их владельцы
СлойСигналВладелец
Freshnessданные пришли вовремяdata platform
Completenessполнота событий и полейanalytics engineering
Businessметрика вне ожидаемого диапазонаproduct / operations
Diagnosisлокализация и статусдежурная команда
Что должно быть в карточке правила

Ссылка на дашборд, владелец реакции, источник данных, baseline и порог, минимальный объём, список диагностических разрезов и критерий закрытия. Без критерия закрытия алерт живёт в чате неделями и тихо обесценивает все остальные.

Разложи метрику на множители, и спорить станет не о чем

Три предыдущие ловушки объединяет одно: итоговое число не показывает, из чего оно собрано. Декомпозиция возвращает эту информацию. Многие продуктовые метрики — произведение или отношение компонентов: revenue = payers × orders_per_payer × AOV, GMV = orders × average order value, DAU = новые + вернувшиеся + удержанные. Разложение не доказывает причину, зато показывает арифметический путь от прошлой точки к текущей.

Выручка выросла на 9,0%. Смотрим множители: плательщиков стало на 7% больше, заказов на плательщика — на 5% больше, средний чек упал на 3%. Проверяем: 1,07 × 1,05 × 0,97 = 1,0898. Сходится. Теперь у разговора есть структура: рост дали база плательщиков и частота покупок, а чек работает против. Предложение «поднять цены» перестаёт быть первой гипотезой, потому что видно, что чек и так уже снизился — вероятно, из-за скидочного микса или сдвига в сторону дешёвых категорий.

Сверка суммы компонентов с исходной метрикой — не формальность, а основной контроль. Если произведение множителей не даёт фактическое изменение, значит компоненты посчитаны на разных grain, в разных окнах или с разными фильтрами. Ошибка в зерне расчёта важнее любого красивого графика: waterfall, который не сходится, объясняет не метрику, а собственную сборку.

Порядок множителей влияет на величину вкладов, и это нормальное свойство метода, а не баг. Перестановка шагов перераспределяет взаимодействие между компонентами. Поэтому порядок фиксируют один раз и пишут рядом с отчётом; для аккуратного разделения вкладов в долгоживущих отчётах используют логарифмические веса, где сумма вкладов не зависит от порядка.

Где рост может родиться
revenue = payers × orders_per_payer × AOV

Произведение множителей обязано равняться фактическому изменению выручки. Не равняется — проблема в grain или в окне, а не в интерпретации.

Из чего сложились +9,0% выручки

Индекс: 100 → 107 (плательщики +7%) → 112,35 (частота +5%) → 108,98 (чек −3%). Последний столбец — итог, а не отдельный шаг.

Индекс выручки
Множители и проверка сходимости
with m as (
  select
    date_trunc('month', paid_at)                      as month,
    count(distinct user_id)                           as payers,
    count(*)::numeric / count(distinct user_id)       as orders_per_payer,
    sum(amount)::numeric / count(*)                   as aov,
    sum(amount)                                       as revenue
  from orders
  where paid_at >= date '2026-05-01' and paid_at < date '2026-07-01'
  group by 1
)
select
  month,
  revenue / lag(revenue) over (order by month)                    as k_revenue,
  payers::numeric / lag(payers) over (order by month)             as k_payers,
  orders_per_payer / lag(orders_per_payer) over (order by month)  as k_freq,
  aov / lag(aov) over (order by month)                            as k_aov,
  -- обязано быть равно k_revenue
  payers::numeric / lag(payers) over (order by month)
    * orders_per_payer / lag(orders_per_payer) over (order by month)
    * aov / lag(aov) over (order by month)                        as k_check
from m
order by month;

ARPU вырос на 7,8%, но дорогих покупателей не стало больше

Для отношений разложение выглядит иначе, и тут легче всего ошибиться. ARPU — это произведение доли плательщиков и средней выручки на плательщика. Было 10% × 5 000 ₽ = 500 ₽. Стало 11% × 4 900 ₽ = 539 ₽, то есть плюс 7,8%. Проверка: 1,10 × 0,98 = 1,078.

Вывод из этих двух множителей противоположен тому, который обычно делают из роста ARPU. Платить начали чаще — доля плательщиков выросла на целый процентный пункт, это десятая часть от исходного уровня. А средний плательщик стал платить меньше. Значит, в платящую базу пришли новые люди с меньшими чеками, и следующие вопросы не про цену, а про удержание этих плательщиков и про маржу в их заказах. Если они не вернутся во второй месяц, рост ARPU окажется разовым.

Работать декомпозиция должна сверху вниз и по одной ветке за раз: выбрал компонент с наибольшим вкладом — разрезай именно его. Разрезать всё сразу по десяти измерениям значит почти гарантированно найти красивую случайную историю в маленьком сегменте. И каждую ветку нужно помечать зрелостью: когорта последнего месяца ещё не дожила до второй покупки, поэтому её частота заведомо ниже, причём по арифметике, а не по поведению.

Порядок спуска по уровням
УровеньКомпонентСледующий вопрос
1активные пользователиизменился трафик или его микс?
2доля плательщиковкто именно начал платить?
3частота покупоквернулись старые плательщики или пришли новые?
4средний чек и маржачто со скидками и составом корзины?
  • Один grain и одно окно для всех компонентов — иначе сверка не сойдётся.
  • Арифметический вклад не равен причинному эффекту: waterfall сужает список гипотез, а проверяет их эксперимент.
  • Средние по сегментам нельзя складывать без весов — это возвращает нас к первому разделу.
  • Зрелость когорты подписывается рядом с каждой веткой.

Порядок проверок: состав, календарь, база, и только потом продукт

Собирая всё вместе, получаем маршрут из пяти шагов, который занимает меньше часа и закрывает большинство ложных выводов. Сначала свежесть и полнота данных: неполный день и опоздавшая загрузка объясняют самые драматичные скачки. Потом календарь: сравни с тем же днём недели и с сезонно похожим периодом. Потом состав: пересчитай на фиксированных весах ключевых сегментов. Потом база: посмотри, не была ли предыдущая точка экстремальной и не отбирали ли объекты по самому показателю. И только после этого раскладывай изменение на множители и формулируй гипотезу о поведении.

Порядок не случаен: каждый следующий шаг дороже предыдущего, а первые четыре умеют полностью снимать вопрос. Если после пересчёта на фиксированных весах рост исчез, дальше идти некуда — у тебя изменение закупки, а не продукта. Экономия получается заметной: вместо двухнедельного эксперимента, который должен подтвердить несуществующий эффект, один запрос на пятнадцать минут.

У маршрута есть побочная польза. Он превращает обсуждение «мне кажется, это цена» в последовательность проверок, у каждой из которых есть ответ в данных. На встрече это меняет сам характер разговора: спорить о гипотезах становится не нужно, потому что видно, какие из них уже отсеяны арифметикой.

Маршрут проверки изменения метрики
ШагЧто делаешьВывод, если проверка срабатывает
1. Данныеfreshness, полнота дня, дубли, NULLэто не метрика, это пайплайн
2. Календарьтот же день недели, YoY, нормализация по днямизменение объясняет календарь
3. Составпересчёт на фиксированных весахизменился микс, а не поведение
4. Базаholdout, baseline до отбораэто возврат к среднему
5. Разложениемножители и сверкапонятно, какой компонент проверять экспериментом

Как записать вывод, чтобы его не прочитали как доказательство

Формулировка решает не меньше, чем расчёт. Одно и то же наблюдение можно записать так, что команда пойдёт увеличивать бюджет, и так, что она пойдёт проверять закупку. Рабочая схема — три части: что видно в данных, что мешает сделать более сильный вывод, какой следующий шаг это меняет.

Про микс: «Общая конверсия выросла с 13% до 32,4% за счёт роста доли канала B с 10% до 90% трафика. Внутри A показатель упал с 10% до 9%, внутри B — с 40% до 35%. На весах июня июль даёт 11,6%, то есть качество обоих каналов ухудшилось. Рост агрегата не является подтверждением того, что закупка стала лучше».

Про регрессию: «После включения баннера конверсия вернулась с 4,1% к 7,6%. В holdout с тем же правилом отбора она вернулась к 7,5%. Добавочный эффект не подтверждён; оставляем баннер как гипотезу и запускаем его с контрольной группой на полном трафике».

Про аномалию: «Заказы на 19% ниже сезонного baseline. Сырые события и платёжный провайдер в норме, падение локализовано в Android 6.4 после вчерашнего релиза. Статус — подтверждённый продуктовый инцидент, владелец mobile team, следующее обновление в 14:00».

Общее у трёх примеров то, что в каждом названа проверка, которая уже пройдена, и граница, за которую вывод не распространяется. Такая запись живёт дольше цифры: через месяц по ней видно, на каком основании было принято решение, и это снимает половину повторных разборов.

Практика на своих данных

Возьми метрику, которая заметно изменилась за последний месяц, и прогони её через четыре проверки, ничего не меняя в продукте. Первая: пересчитай показатель на весах прошлого периода по двум-трём ключевым разрезам и запиши разницу с фактом отдельной строкой «вклад микса». Вторая: сравни тот же период с тем же днём недели и с прошлым годом, нормализовав на число дней. Третья: проверь, не была ли предыдущая точка экстремальной, и если да — посмотри, как вели себя похожие экстремальные точки раньше без вмешательства.

Четвёртая проверка — разложение. Напиши формулу метрики на бумаге, посчитай множители за оба периода и убедись, что их произведение равно фактическому изменению. Если не сходится, останавливайся здесь: расхождение в сверке означает ошибку в зерне или в знаменателе, и до её исправления остальные выводы не имеют значения.

В конце сравни два вывода: тот, который сделала бы команда по исходной цифре, и тот, который получился после четырёх проверок. Если они расходятся — а они расходятся чаще, чем ожидаешь, — у тебя есть конкретный повод добавить в регулярный отчёт строку вклада микса и подпись периода сравнения. Это дешевле любого разбора постфактум.

Итог и куда дальше

Метрика не обманывает сама — она отвечает ровно на тот вопрос, который задан её формулой, и молчит обо всём остальном. Обманывает чтение: из арифметики агрегата делают вывод о поведении пользователей, пропуская состав, календарь и базу. Поэтому надёжность приходит не от более точного расчёта, а от порядка проверок, в котором дешёвые объяснения отсекаются первыми.

Декомпозиция стоит в конце не потому, что она сложнее, а потому что она закрывает все предыдущие ловушки разом: микс виден как изменение веса компонента, календарь — как сдвиг окна, экстремальная база — как аномальное значение множителя. Когда разложение сошлось, у команды остаётся один честный вопрос вместо пяти догадок: какой именно компонент мы проверяем экспериментом.

Продолжить чтение
Вся библиотека