Перейти к содержанию

Воронка с подтверждённым результатом

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

Продолжение использует conversion-lab и вымышленную запись на обновления курса. Материалы markdown и xml сохраняют учебные ID. Новые события и сессии специально подготовлены для расчёта; они не являются экспортом настоящего ProfessorWeb или предложением передавать собственные session_id внешнему счётчику.

Результат и знаменатель

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

Знаменателем станут шесть учебных сессий, которым показано предложение. Это не все открытия библиотеки и не все люди. Одна реальная личность может иметь несколько посещений; наши искусственные session_id только позволяют объяснить порядок на маленьком известном наборе.

Заранее зададим окно: следующий этап должен произойти в течение 30 минут после показа внутри одной учебной сессии. Это выбранный договор примера. Для настоящего подтверждения подписки могут понадобиться более длинный срок и другая связь событий. Тогда изменится метод, а не только подпись таблицы.

Четыре этапа

Воронка состоит из offer_view, form_start, form_submit и subscription_confirmed. Сначала посетитель видит предложение, затем начинает форму, отправляет её и получает подтверждённый результат.

Этап Что наблюдаем Чего он не доказывает
offer_view Предложение показано Посетитель внимательно его прочитал
form_start Началось взаимодействие Данные корректны
form_submit Отправлена попытка Сервер принял запись
subscription_confirmed Подтверждение связано с записью Человек будет читать каждую рассылку

В маленьком снимке шесть сессий проходят первый этап, четыре — второй, три — третий, две — последний. У каждой события имеют относительные секунды. Скачайте архив conversion-lab: он содержит исходные данные, программы расчёта и README. После распаковки используйте файлы из папки conversion-lab.

Эти числа выбраны для объяснения и не изображают реальную эффективность подписки. Важен способ получения: этапы относятся к одному набору и заданному порядку.

Упорядоченный расчёт

Ниже полный алгоритм funnel.py для массива events.json. Каждая запись содержит event_id, session_id, document_id, event и second. Дубликаты ID с разным содержанием считаются ошибкой данных.

import json
from collections import defaultdict
from pathlib import Path

STAGES = ["offer_view", "form_start", "form_submit", "subscription_confirmed"]

def funnel(events, window=1800):
    unique = {}
    for event in events:
        previous = unique.get(event["event_id"])
        if previous is not None and previous != event:
            raise ValueError("Конфликт event_id")
        unique[event["event_id"]] = event
    grouped = defaultdict(list)
    for event in unique.values():
        grouped[event["session_id"]].append(event)
    counts = [0] * len(STAGES)
    for rows in grouped.values():
        rows.sort(key=lambda row: (row["second"], row["event_id"]))
        stage = 0
        started = None
        document = None
        for row in rows:
            if row["event"] != STAGES[stage]:
                continue
            if stage == 0:
                started = row["second"]
                document = row["document_id"]
            elif row["document_id"] != document or row["second"] > started + window:
                continue
            counts[stage] += 1
            stage += 1
            if stage == len(STAGES):
                break
    return counts

if __name__ == "__main__":
    data = json.loads(Path(__file__).with_name("events.json").read_text())
    print(dict(zip(STAGES, funnel(data))))

Ожидаются количества 6, 4, 3 и 2. Сортировка относится к секундам внутри вымышленной сессии. Для реального экспорта потребуются известная временная зона и правила событий с одинаковой отметкой.

Один этап считается не более одного раза. Повторный submit не увеличивает число успешно прошедших сессий. Это отличается от отчёта по количеству событий, изученного раньше.

Доли и разрыв

Общая доля результата равна 2/6, около 33,3%. Переход от начала к отправке — 3/4, то есть 75%. Переход от отправки к подтверждению — 2/3. Эти числа отвечают на разные вопросы.

Если сравнить 2 подтверждения с 4 началами, получим 50%, но это не общая конверсия показанного предложения. Подпись знаменателя должна находиться рядом с показателем. Удобное число без определения легко вводит в заблуждение.

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

Порядок и связь

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

События разных документов также не соединяются после выбранного первого показа. Посетитель мог начать предложение на Markdown и закончить на XML; наш договор такую последовательность не считает. Для другой модели понадобится связь предложения или заявки, а не случайное объединение всех событий сессии.

Алгоритм закрепляет первый подходящий показ и не ищет заново лучший последующий маршрут. Это известное упрощение. Оно помогает избежать скрытого подбора удобной последовательности и должно сохраняться при сравнении периодов.

Наблюдение изменений

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

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

Неполное наблюдение

Если источник не прислал offer_view, позднее подтверждение не создаёт подходящую единицу автоматически. Такая строка может быть полезна для диагностики доставки, но она не устанавливает отсутствующий знаменатель. Нельзя «исправлять» конверсию добавлением выдуманного начала.

Аналогично единая session_id должна иметь известную область. Повтор номера в другом снимке или на другом стенде не соединяет людей. В наших данных это искусственные короткие обозначения; contexts.json отделяет их от form-v1.

Относительные секунды уже имеют числовой тип в подготовленном JSON. Для настоящего экспорта понадобится проверить тип, пропуски, часы источника и правила задержки. Алгоритм воронки не заменяет очистку данных, которую рассматривала основная серия.

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

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

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