Product Management Продуктовая аналитика и принятие решений на данных
0%

Продуктовая аналитика и принятие решений на данных

Продуктовая аналитика и принятие решений на данных

В https://courses.digitable.life/post/product-management/02-metrics/ мы выбирали, какие числа считать. В https://courses.digitable.life/post/product-management/05-mvp-and-experiments/ — как ставить эксперимент, чтобы получить честный ответ. Эта статья про то, что происходит между ними и после них: как из сырых событий получается решение, за которое не стыдно через полгода.

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


1. Зачем это нужно: аналитика как экономика информации

1.1. Решение первично, данные вторичны

Классическая ошибка: «давайте построим дашборд, а потом посмотрим, что интересного». Правильный порядок обратный — от решения к данным:

  1. Какое решение мы принимаем? (запускать / не запускать, повышать цену / нет, куда идёт квартал)
  2. Какие альтернативы рассматриваем?
  3. Что должно быть правдой, чтобы выбрать альтернативу А, а не Б?
  4. Какое наблюдение отличит эти миры друг от друга?
  5. И только теперь — какой запрос/эксперимент даст это наблюдение?

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

1.2. Ценность информации (EVSI) — почему не всё стоит измерять

У любой информации есть цена и есть ценность. Ценность ограничена сверху: информация полезна ровно настолько, насколько она может переключить ваш выбор.

Простая модель. Решение: катить фичу или нет. Если катим и она хорошая — +300 $k, если катим и плохая — −100 $k. Априорная вероятность «хорошая» = 0.6.

# Ожидаемая ценность идеальной информации (EVPI):
# сколько максимум стоит потратить на исследование/эксперимент.
p_good, gain, loss = 0.6, 300_000, -100_000

ev_without_info = max(p_good * gain + (1 - p_good) * loss, 0)  # решаем «вслепую» или не делаем
# С идеальной информацией мы катим только в хорошем мире:
ev_with_perfect_info = p_good * gain + (1 - p_good) * 0

evpi = ev_with_perfect_info - ev_without_info
print(ev_without_info, ev_with_perfect_info, evpi)  # 140000 180000 40000

Вывод: даже идеальное знание здесь стоит не больше 40 $k. Двухмесячное исследование командой из трёх человек — уже дороже, чем весь возможный выигрыш от него. А если бы p_good = 0.95, EVPI ≈ 5k $ — измерять почти бессмысленно, надо просто катить.

Это формальное обоснование двух практических правил:

  • Обратимые решения (two-way doors, по формулировке Джеффа Безоса в письме акционерам Amazon 2015) принимаются быстро и на слабых данных: цена ошибки = стоимость отката.
  • Необратимые (миграция тарифов, смена позиционирования, удаление фичи с контрактными обязательствами) требуют дорогих методов с верхних ступеней лестницы достоверности.

Лестница достоверности причинного вывода

1.3. Четыре уровня аналитических вопросов

Уровень Вопрос Инструменты Типичная ошибка
Дескриптивный Что произошло? дашборды, воронки, когорты принять корреляцию за причину
Диагностический Почему произошло? декомпозиция, сегменты, mix-анализ остановиться на первом «виновнике»
Предиктивный Что будет? прогнозы, churn-модели, LTV доверять прогнозу вне области определения
Прескриптивный Что делать? эксперименты, causal inference, оптимизация оптимизировать метрику вместо ценности

95% продуктовой работы живёт на первых двух уровнях, а ценность решения создаётся на четвёртом. Задача продакта — не застревать на первом.


2. Фундамент: модель данных и tracking plan

Никакая аналитика не спасёт кривой сбор данных. Прежде всего нужна явная модель событий.

2.1. Событийная модель

Базовая единица — событие: кто, что сделал, когда, в каком контексте. Всё остальное (воронки, retention, LTV) — производные агрегаты.

Три детали, которые чаще всего забывают и потом дорого чинят:

  1. occurred_atreceived_at. Мобильный клиент в офлайне отправит событие через три дня. Если считать по received_at, вы «переоткроете» вчерашний день и сломаете исторические отчёты; если только по occurred_at — отчёты за последние дни будут недосчитывать. Практика: считать по occurred_at, но помечать последние N дней как «неполные» и мерить долю опоздавших.
  2. anonymous_iduser_id (identity stitching). Пользователь ходит анонимно, потом регистрируется. Без склейки вы теряете весь путь до регистрации — и воронка активации превращается в фантазию.
  3. schema_version. Свойство price было в рублях, стало в копейках — без версии схемы вы никогда не узнаете, где произошёл сдвиг.

2.2. Tracking plan: контракт между продуктом и данными

Tracking plan — это документ (лучше — YAML в репозитории с CI-валидацией), где для каждого события зафиксированы имя, владелец, свойства и типы.

# tracking/checkout.yaml — версионируется в репозитории, проверяется в CI
- name: checkout_started
  owner: team-payments
  description: "Пользователь открыл экран оплаты. Одно событие на попытку."
  version: 2
  properties:
    cart_value_minor: { type: integer, required: true, unit: "копейки" }
    currency:         { type: string,  required: true, enum: ["RUB", "USD", "EUR"] }
    items_count:      { type: integer, required: true, min: 1 }
    payment_method:   { type: string,  required: false, enum: ["card", "sbp", "wallet"] }
    experiment_ids:   { type: array,   required: false }

- name: checkout_completed
  owner: team-payments
  description: "Платёж подтверждён провайдером. Источник истины — бэкенд, не клиент."
  version: 2
  properties:
    order_id:         { type: string,  required: true }
    cart_value_minor: { type: integer, required: true }
    revenue_net_minor:{ type: integer, required: true, description: "за вычетом комиссии" }

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

  • object_action в прошедшем времени: checkout_started, invite_sent. Не Click Button.
  • Деньги — только в минорных единицах целым числом. Floating point в выручке — источник вечных расхождений с финансами.
  • Критичные для денег события пишутся с бэкенда. Клиентские события теряются на 5–30% (блокировщики, офлайн, краши) и легко подделываются.
  • Одно событие — один смысл. page_viewed со свойством type лучше, чем 40 отдельных событий.

Хороший разбор дисциплины трекинга — в документации Segment Tracking Plan и Amplitude Data Taxonomy.

2.3. Слои данных

Смысл разделения: сырой слой никогда не переписывается, поэтому любую ошибку трансформации можно исправить пересчётом задним числом. Metrics layer (dbt Semantic Layer, Cube, Malloy) существует ради одной цели — чтобы «активный пользователь» означал одно и то же в отчёте маркетинга, в дашборде команды и в анализе эксперимента. Без него компания тратит месяцы на споры о том, чьё число верное.


3. Качество данных: единственная вещь, которую нельзя починить постфактум

3.1. Как ломается трекинг

Симптом Частая причина Как ловить
Метрика упала ровно в полночь на 100% релиз уронил событие / переименовали алерт на объём событий, а не только на метрику
Конверсия выросла в 2 раза за день дедупликация сломалась, ретраи считаются проверка count(distinct event_id) vs count(*)
Резкий рост «пользователей» боты, скрейперы, нагрузочное тестирование фильтр по user-agent, аномально высокая частота
Разошлись с финансами на 3% клиентские платёжные события сверка с биллингом ежедневно
«Дыра» в данных за вчера опоздавшие события доля событий с лагом received_at − occurred_at

3.2. Тесты данных как код

Data quality проверяется автоматически, а не глазами. Минимальный набор в dbt/Great Expectations:

-- tests/assert_event_sanity.sql — падает, если возвращает хотя бы одну строку
with daily as (
    select
        date_trunc('day', occurred_at)               as d,
        name,
        count(*)                                     as events,
        count(distinct event_id)                     as unique_events,
        count(distinct user_id)                      as users,
        avg(extract(epoch from received_at - occurred_at)) as avg_lag_sec
    from {{ ref('stg_events') }}
    where occurred_at >= current_date - interval '30 days'
    group by 1, 2
),
stats as (                        -- ожидаемый уровень: медиана и MAD за 28 дней
    select
        name, d, events, unique_events, avg_lag_sec,
        percentile_cont(0.5) within group (order by events)
            over (partition by name)                 as median_events
    from daily
)
select *
from stats
where events <> unique_events                    -- дубликаты
   or events < median_events * 0.5               -- обвал объёма
   or events > median_events * 2.0               -- всплеск (боты/ретраи)
   or avg_lag_sec > 3600;                        -- аномальная задержка доставки

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


4. Диагностика: почему метрика изменилась

4.1. Ловушка агрегата — парадокс Симпсона

Самый частый источник неверных выводов в продукте. Агрегированная конверсия падает, хотя в каждом сегменте она растёт, потому что изменился состав аудитории.

Парадокс Симпсона: сегменты растут, агрегат падает

Формально: агрегат — это средневзвешенное, p = Σ wᵢ · pᵢ, где wᵢ — доля сегмента. Изменение агрегата раскладывается на эффект ставки (менялись pᵢ) и эффект состава (менялись wᵢ). Академический разбор — у Джудеи Перла в «The Book of Why» и статье Simpson’s Paradox (Stanford Encyclopedia of Philosophy).

4.2. Декомпозиция mix / rate

Каноническое разложение (аналог shift-share анализа):

Δp = Σᵢ w⁰ᵢ · (p¹ᵢ − p⁰ᵢ)        ← rate effect: изменилось качество внутри сегментов
   + Σᵢ p⁰ᵢ · (w¹ᵢ − w⁰ᵢ)        ← mix effect: изменился состав аудитории
   + Σᵢ (w¹ᵢ − w⁰ᵢ)(p¹ᵢ − p⁰ᵢ)  ← interaction: остаток
from dataclasses import dataclass

@dataclass
class Segment:
    name: str
    users_before: int
    conv_before: float   # доля 0..1
    users_after: int
    conv_after: float

def decompose(segments: list[Segment]) -> dict:
    """Разложение изменения агрегированной конверсии на rate / mix / interaction.

    Сложность: O(S) по времени и O(1) по дополнительной памяти, где S — число сегментов.
    Само получение segments из событий — это group by, O(N) при хешировании
    или O(N log N) при сортировке, N — число событий.
    """
    n0 = sum(s.users_before for s in segments)
    n1 = sum(s.users_after for s in segments)

    p0 = sum(s.users_before * s.conv_before for s in segments) / n0
    p1 = sum(s.users_after * s.conv_after for s in segments) / n1

    rate = mix = inter = 0.0
    per_segment = {}
    for s in segments:
        w0, w1 = s.users_before / n0, s.users_after / n1
        dp, dw = s.conv_after - s.conv_before, w1 - w0
        r, m, i = w0 * dp, s.conv_before * dw, dw * dp
        rate += r; mix += m; inter += i
        per_segment[s.name] = {"rate": r, "mix": m, "interaction": i, "total": r + m + i}

    return {
        "p_before": p0, "p_after": p1, "delta": p1 - p0,
        "rate_effect": rate, "mix_effect": mix, "interaction": inter,
        "by_segment": per_segment,
    }

segments = [
    Segment("Новые",  users_before=1000, conv_before=0.04, users_after=4000, conv_after=0.05),
    Segment("Старые", users_before=1000, conv_before=0.20, users_after=1000, conv_after=0.22),
]
r = decompose(segments)
print(f"было {r['p_before']:.1%} → стало {r['p_after']:.1%} (Δ = {r['delta']:+.1%})")
print(f"  качество (rate):  {r['rate_effect']:+.2%}")
print(f"  состав   (mix):   {r['mix_effect']:+.2%}")
print(f"  взаимодействие:   {r['interaction']:+.2%}")
# было 12.0% → стало 8.4% (Δ = -3.6%)
#   качество (rate):  +1.50%
#   состав   (mix):   -4.80%
#   взаимодействие:   -0.30%

Интерпретация: продукт стал лучше (+1.5 п.п.), а падение агрегата на 4.8 п.п. — целиком результат маркетингового решения залить дешёвый трафик. Действие — не «чинить продукт», а обсуждать с маркетингом качество канала и, возможно, менять целевую метрику на посегментную.

Тот же разбор в SQL, если сегментов много и нужен рейтинг вкладов:

with base as (
    select segment,
           sum(case when period = 'before' then users end) as u0,
           sum(case when period = 'before' then conv * users end)
             / nullif(sum(case when period = 'before' then users end), 0) as p0,
           sum(case when period = 'after'  then users end) as u1,
           sum(case when period = 'after'  then conv * users end)
             / nullif(sum(case when period = 'after'  then users end), 0) as p1
    from segment_period_stats
    group by segment
),
tot as (select sum(u0) as n0, sum(u1) as n1 from base)
select b.segment,
       (u0 / t.n0) * (p1 - p0)                          as rate_effect,
       p0 * (u1 / t.n1 - u0 / t.n0)                     as mix_effect,
       (u1 / t.n1 - u0 / t.n0) * (p1 - p0)              as interaction
from base b cross join tot t
order by abs(rate_effect + mix_effect + interaction) desc
limit 20;   -- 20 сегментов с наибольшим вкладом в изменение

4.3. Алгоритм расследования: от «упало» до «понял»

Два узла здесь чаще всего пропускают, и оба дорого стоят.

Проверка на шум. Прежде чем расследовать, посчитайте, насколько метрика вообще колеблется в норме. Дневная конверсия при 5000 визитов и p ≈ 0.12 имеет стандартное отклонение sqrt(p(1−p)/n) ≈ 0.46 п.п., то есть колебания ±1 п.п. день ко дню — обычный вторник, а не повод собирать митинг.

import math

def is_signal(p_hat: float, n: int, p_baseline: float, z: float = 3.0) -> bool:
    """Грубый контроль: отличается ли дневное значение от базового более чем на z сигм.
    Сложность O(1). Для метрик с автокорреляцией лучше STL-декомпозиция или
    доверительный интервал по историческому распределению остатков."""
    se = math.sqrt(p_baseline * (1 - p_baseline) / n)
    return abs(p_hat - p_baseline) > z * se

print(is_signal(0.113, 5000, 0.12))   # False — шум
print(is_signal(0.098, 5000, 0.12))   # True  — сигнал

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


5. Причинность: почему корреляция почти всегда врёт

5.1. Три источника ложного вывода

  • Конфаундер. Пользователи, включившие уведомления, удерживаются лучше — но они изначально более вовлечены. Включение уведомлений не делает их лояльными.
  • Обратная причинность. «Те, кто пользуется поиском, чаще покупают» — возможно, наоборот: те, кто уже решил купить, идут в поиск.
  • Отбор (survivorship / selection bias). Опрос активных пользователей о причинах оттока не покажет причин оттока — ушедшие в выборку не попали.

5.2. Инструменты, когда A/B невозможен

Полный A/B разобран в https://courses.digitable.life/post/product-management/05-mvp-and-experiments/. Здесь — что делать, когда рандомизация недоступна: изменение затрагивает всех (цена, бренд, логистика), эффект «перетекает» между пользователями (маркетплейс, соцсеть), или тест уже прошёл.

Difference-in-Differences (DiD). Есть тестовая и контрольная группы (например, города), изменение выкатили только в тестовой. Считаем изменение «после − до» в обеих и вычитаем:

def did(y_treat_pre, y_treat_post, y_ctrl_pre, y_ctrl_post) -> float:
    """Оценка эффекта методом разность разностей.
    Критическое допущение — parallel trends: без вмешательства обе группы
    менялись бы одинаково. Проверяется на исторических периодах ДО вмешательства.
    Сложность O(1) для точечной оценки; для доверительного интервала —
    кластерный bootstrap O(B·K), B ~ 1000 итераций, K — число кластеров."""
    return (y_treat_post - y_treat_pre) - (y_ctrl_post - y_ctrl_pre)

# Конверсия в тестовых городах 12.0% → 14.5%, в контрольных 11.5% → 12.3%
print(f"{did(0.120, 0.145, 0.115, 0.123):+.2%}")   # +1.70% — чистый эффект

Обязательная проверка: постройте графики обеих групп за 8–12 периодов до вмешательства. Если линии не параллельны — DiD неприменим, оценка будет смещённой.

Switchback. Для маркетплейсов и логистики, где эффект глобальный: включаем и выключаем изменение по расписанию в одном регионе (например, чередование часовыми блоками). Единица рандомизации — интервал времени, а не пользователь. Это устраняет интерференцию, но требует аккуратного учёта carryover-эффектов (первые минуты после переключения обычно выбрасывают). Разбор — в инженерных блогах Doordash и Lyft.

Synthetic control. Строим «синтетический контроль» — взвешенную комбинацию непострадавших регионов, которая максимально повторяет динамику тестового до вмешательства, и сравниваем после. Метод Абади: Abadie, Diamond, Hainmueller, 2010.

CUPED — не про причинность, а про мощность: используем предпериодные данные, чтобы снизить дисперсию метрики и увидеть эффект на меньшей выборке.

import numpy as np

def cuped(y: np.ndarray, x: np.ndarray) -> np.ndarray:
    """CUPED: корректируем метрику y ковариатой x (та же метрика в предпериоде).
    y_adj = y − θ(x − E[x]), где θ = cov(x,y)/var(x).
    Матожидание не смещается, дисперсия падает в (1 − ρ²) раз.
    Сложность O(n) по времени и O(n) по памяти."""
    theta = np.cov(x, y, ddof=1)[0, 1] / np.var(x, ddof=1)
    return y - theta * (x - x.mean())

rng = np.random.default_rng(42)
x = rng.gamma(2.0, 3.0, 200_000)                 # активность в предпериоде
y = 0.8 * x + rng.normal(0, 2.0, 200_000)        # активность в эксперименте
y_adj = cuped(y, x)
print(f"дисперсия: {y.var():.2f}{y_adj.var():.2f}")            # 15.55 → 3.98
print(f"выборка сокращается во столько же раз: {y.var()/y_adj.var():.1f}x")   # 3.9x

Оригинальная работа: Deng, Xu, Kohavi, Walker, «Improving the Sensitivity of Online Controlled Experiments by Utilizing Pre-Experiment Data», WSDM 2013.

Условие корректности: x вычисляется строго до старта эксперимента. Ковариата, затронутая вмешательством, вносит смещение.


6. Статистика ровно в том объёме, который нужен продакту

6.1. Интервал важнее p-value

p < 0.05 говорит только «эффект вряд ли ноль». Решение принимается не по этому, а по величине эффекта и её неопределённости. Всегда смотрите доверительный интервал и сравнивайте его с порогом практической значимости.

Результат CI эффекта Что делать
Значимо, CI = [+0.1%; +0.3%] эффект есть, но мизерный не катить: не окупит поддержку
Незначимо, CI = [−0.2%; +0.2%] эффект точно мал решать по другим критериям (простота, стратегия)
Незначимо, CI = [−5%; +7%] ничего не знаем тест был бессмысленным: не хватило мощности
Значимо, CI = [+2%; +9%] эффект есть и крупный катить

Третья строка — самая частая и самая опасная: «различий не обнаружено» интерпретируют как «различий нет». Это не одно и то же.

import math

def sample_size_per_arm(p: float, mde_rel: float, alpha: float = 0.05, power: float = 0.8) -> int:
    """Размер выборки на вариант для двусторонней проверки долей.
    n ≈ (z_{1−α/2} + z_{1−β})² · (p1(1−p1) + p2(1−p2)) / (p2 − p1)²
    Ключевое: n растёт как 1/MDE² — чтобы поймать вдвое меньший эффект,
    нужно вчетверо больше трафика. Сложность O(1)."""
    z_a, z_b = 1.959964, 0.841621          # для alpha=0.05, power=0.8
    p2 = p * (1 + mde_rel)
    num = (z_a + z_b) ** 2 * (p * (1 - p) + p2 * (1 - p2))
    return math.ceil(num / (p2 - p) ** 2)

for mde in (0.20, 0.10, 0.05, 0.02):
    print(f"MDE {mde:>5.0%}: {sample_size_per_arm(0.05, mde):>10,} пользователей на вариант")
# MDE   20%:      8,155
# MDE   10%:     31,231
# MDE    5%:    122,121
# MDE    2%:    752,700

Практический вывод: продукт с 20k пользователей в месяц физически не может измерить эффект в 2% на конверсии 5%. Не надо делать вид, что может, — надо либо выбирать более чувствительные метрики (ближе к вмешательству), либо применять CUPED, либо принимать решение на качественных данных и осознанно.

6.2. Подглядывание и множественные сравнения

Две ошибки, которые обесценивают половину продуктовых экспериментов:

  • Peeking. Смотреть на тест каждый день и остановиться, когда «стало значимо», раздувает ложноположительные с 5% до 20–30%. Лекарство: фиксировать длительность заранее либо использовать методы, корректные при непрерывной проверке — sequential testing / always-valid inference (Johari, Pekelis, Walsh).
  • Множественные метрики. 20 метрик при α = 0.05 дадут в среднем одну «значимую» случайно: 1 − 0.95²⁰ ≈ 64% вероятность хотя бы одного ложного срабатывания. Лекарство: одна заранее объявленная primary-метрика, остальные — guardrail (проверяются на «не ухудшилось») и exploratory (только для генерации гипотез).

6.3. Guardrail-метрики

Отдельный класс метрик, которые не должны улучшаться — они должны не ломаться: время загрузки, доля ошибок, отток, обращения в поддержку, доля возвратов. Формально проверяются на non-inferiority: «не хуже, чем на X%». Именно guardrails ловят классику вида «конверсия в подписку +8%, отмены в первый месяц +30%».


7. От анализа к решению

7.1. Жизненный цикл решения

Ветка Запись → Проверка → Калибровка — то, что отличает организацию, которая учится, от организации, которая просто много анализирует. Без замыкания петли команда годами повторяет одни и те же ошибки оценки, потому что никто не измеряет качество прогнозов.

7.2. Decision log

Шаблон записи, который занимает 10 минут и экономит месяцы:

id: DEC-2026-041
date: 2026-05-14
decision: "Убрать обязательную регистрацию перед первым заказом"
type: two-way-door           # откат ~ 3 дня работы
owner: "@product-checkout"
context: |
  Воронка теряет 34% на шаге регистрации. Интервью (n=12) показывают недоверие
  к передаче телефона до понимания цены.
alternatives:
  - "Оставить как есть"
  - "Гостевой заказ с post-purchase регистрацией"   # выбрано
  - "Соцавторизация"                                # отклонено: 2 недели интеграции
evidence:
  - "A/B n=180k, конверсия оплаты +6.1% [CI +3.4%; +8.9%]"
  - "Guardrail: доля фрода +0.02 п.п., в пределах допустимого"
  - "Guardrail: повторные заказы за 30 дней −0.4% [CI −1.6%; +0.8%] — не отличимо"
prediction: "За Q3 доля повторных заказов не упадёт более чем на 1 п.п."
review_at: 2026-10-01
outcome: null                # заполняется на review

Поля prediction и review_at обязательны. Именно они превращают решение в проверяемое утверждение, а команду — в калибруемую систему. Родственная практика в инженерии — ADR (Architecture Decision Records); смежная тема разобрана в https://courses.digitable.life/post/architecture-patterns/00-overview/.

7.3. Кто и как принимает решение по данным

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


8. Как это выглядит в проде

8.1. Слои потребления аналитики

Слой Кто пользуется Требование Антипаттерн
Health-дашборд вся команда, ежедневно 5–9 метрик, коридоры, алерты 60 графиков «на всякий случай»
Weekly business review продукт + бизнес метрика → декомпозиция → действие чтение чисел вслух без решений
Self-serve исследование продакты сами metrics layer, документированные витрины очередь в 3 недели к аналитику
Глубокий анализ аналитик причинность, моделирование ad-hoc «посчитай мне цифру»
Платформа экспериментов все автоматический расчёт, guardrails Excel и ручные t-тесты

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

8.2. Дизайн дашборда, по которому принимают решения

  • Одна страница, ≤ 9 чисел. Что не помещается — не смотрят.
  • Каждое число с контекстом: значение, изменение к прошлому периоду, ожидаемый коридор. Число без коридора не позволяет отличить сигнал от шума.
  • Аннотации на графиках: релизы, промо, праздники, инциденты. Без них любой скачок порождает получасовое расследование заново.
  • Сегменты рядом с агрегатом — защита от парадокса Симпсона на уровне интерфейса.
  • У каждого блока есть владелец и вопрос, на который блок отвечает. Нет вопроса — удалить.

Про визуальную часть — Edward Tufte, «The Visual Display of Quantitative Information» и Stephen Few, «Information Dashboard Design».

8.3. Метрика становится целью — и перестаёт быть метрикой

Закон Гудхарта: «Когда мера становится целью, она перестаёт быть хорошей мерой». В продукте это выглядит буднично:

Цель по метрике Как её «достигают» Что ломается
DAU пуши каждый день отписки, удаление приложения
Время в приложении бесконечная лента, замедление навигации удовлетворённость, отток
Число регистраций принудительная регистрация до ценности конверсия в оплату
Тикеты закрыты быстро закрывают без решения повторные обращения, NPS

Защита: (1) каждой цели соответствует guardrail-пара; (2) целевая метрика измеряет полученную ценность, а не активность; (3) метрики привязываются к результату, а не к личным бонусам за конкретное число. Подробнее про подбор такой пары — в https://courses.digitable.life/post/product-management/02-metrics/ и https://courses.digitable.life/post/product-management/07-pricing-and-growth/.


9. Типичные ошибки

  1. Анализ без решения. «Интересный инсайт», после которого никто ничего не делает. Лекарство: начинать с вопроса «какое решение это изменит?».
  2. HARKing (Hypothesizing After the Results are Known). Нарезали данные на 30 сегментов, нашли «значимый» эффект в одном и объявили его гипотезой. Лекарство: заранее зафиксированный план анализа; найденное постфактум — только кандидат на новую проверку.
  3. Смешение корреляции и причины. «Пользователи фичи X удерживаются в 3 раза лучше» — почти всегда отбор, а не эффект фичи.
  4. Средние по несимметричным распределениям. Средний чек при лог-нормальном распределении сдвигают несколько китов. Смотрите медиану, перцентили и trimmed mean.
  5. Игнорирование выживших. Retention считается только по тем, кто дожил; когорты обязательны, иначе вы измеряете состав, а не поведение.
  6. Сравнение неполных периодов. «Этот месяц хуже прошлого» — а прошедших дней в нём 19 против 31, и в нём меньше выходных.
  7. Один тест = одна правда. Эффект в A/B — это оценка на конкретной популяции в конкретное время. Повторяемость проверяется репликацией, а не убеждённостью.
  8. Данные вместо суждения. Данные говорят о прошлом. Стратегические ставки (https://courses.digitable.life/post/product-management/04-strategy-and-roadmap/) по определению не имеют данных — для них есть суждение, дискавери (https://courses.digitable.life/post/product-management/01-discovery-and-research/) и дешёвые обратимые эксперименты.
  9. Дашборд как замена мышлению. Числа показывают, что; понимание почему приходит из разговоров с пользователями и просмотра сессий.

10. Мини-итог

  • Аналитика начинается с решения, а не с данных. Ценность информации ограничена тем, насколько она способна изменить выбор — считайте EVPI до, а не после исследования.
  • Качество сбора (tracking plan, версии схем, occurred_at vs received_at, identity stitching) невозможно починить задним числом. Тесты данных — часть CI.
  • Прежде чем расследовать падение метрики, проверьте, что это не шум и не поломка трекинга. Это отсекает половину «инцидентов».
  • Агрегат врёт: раскладывайте изменение на rate и mix. Парадокс Симпсона — повседневность, а не экзотика.
  • Причинность — лестница: от корреляции через когорты и DiD к switchback и A/B. Поднимайтесь ровно настолько, насколько дорога ошибка.
  • Смотрите доверительный интервал, а не p-value. «Незначимо» ≠ «эффекта нет».
  • Решения записывайте вместе с прогнозом и датой ревью — это единственный способ калибровать команду.

Источники


Что дальше

Это последняя статья трека «Product Management». Собранная картина выглядит так: дискавери (https://courses.digitable.life/post/product-management/01-discovery-and-research/) находит проблему, метрики (https://courses.digitable.life/post/product-management/02-metrics/) делают её измеримой, приоритизация (https://courses.digitable.life/post/product-management/03-prioritization/) и стратегия (https://courses.digitable.life/post/product-management/04-strategy-and-roadmap/) выбирают, куда идти, MVP и эксперименты (https://courses.digitable.life/post/product-management/05-mvp-and-experiments/), требования и UX (https://courses.digitable.life/post/product-management/06-ux-and-requirements/), монетизация (https://courses.digitable.life/post/product-management/07-pricing-and-growth/) превращают выбор в продукт — а аналитика замыкает петлю обратной связи.

Куда идти дальше:

  • https://courses.digitable.life/post/project-management/00-overview/ — как доводить решения до релиза: планирование, риски, работа с командой и стейкхолдерами.
  • https://courses.digitable.life/post/data-engineering/00-overview/ — инженерия того самого слоя данных, на который опирается вся эта статья: пайплайны, хранилища, качество данных.
  • https://courses.digitable.life/post/machine-learning/00-overview/ — когда описательной аналитики мало и нужны предсказательные модели: churn, ранжирование, рекомендации.
  • https://courses.digitable.life/post/architecture-patterns/00-overview/ — как продуктовые решения ложатся на архитектуру системы.
  • https://courses.digitable.life/post/algorithms/00-overview/ и https://courses.digitable.life/post/golang/00-overview/ — если хочется укрепить инженерный фундамент.

Общая карта портала и рекомендуемый порядок изучения — в https://courses.digitable.life/post/roadmap/.

Вернуться к обзору трека

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

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

Доска запросов