Переходы между уроками и учебный маршрут
Отношение продолжений к открытиям показало, как часто активируется ссылка, но не объяснило дальнейший путь. Человек мог открыть назначение, закрыть вкладку или продолжить через каталог. Для вопроса о маршруте нужно рассматривать порядок связанных действий. Суммы по отдельным статьям этого порядка не сохраняют.
Используем вымышленный journey.csv. В нём четыре условных сеанса s1–s4 и поле sequence, которое задаёт порядок. Эти идентификаторы придуманы для ручного объяснения. Они не получены из аккаунтов и не являются предложением отправлять собственные постоянные ID посетителей в аналитическую платформу.
Что считать входом
Наш учебный маршрут reading-demo имеет порядок Markdown → XML. Он знакомит с разными видами статьи, а не изображает реальный опубликованный курс ProfessorWeb. Для первой проверки определим вход как сеанс, в котором первое известное действие — lesson_open документа markdown. Это узкое правило нужно записать до подсчёта.
В s1 сначала открывается Markdown, затем активируется продолжение, затем открывается XML. В s2 после открытия Markdown активируется исходник, продолжения нет. В s3 порядок обратный: XML, затем Markdown. В s4 известны открытие Markdown и активация продолжения, но открытия XML в таблице нет.
| Сеанс | Известная последовательность | Вход по нашему правилу |
|---|---|---|
| s1 | markdown → next → xml | Да |
| s2 | markdown → download | Да |
| s3 | xml → markdown | Нет |
| s4 | markdown → next | Да |
Если правилом входа сделать любое открытие Markdown, набор изменится и включит s3. Это допустимая другая задача, например исследование всех обращений к материалу. Но она не равна анализу начала заданного маршрута. Поэтому изменение правила меняет знаменатель и требует нового описания результата.
Активация и прибытие
Из трёх выбранных входов два содержат lesson_next из Markdown в XML. Отношение равно 2/3. Только в одном наблюдается последующее открытие XML, поэтому подтверждённое нашей таблицей прибытие — 1/3 входов. Если знаменателем взять две активации, отношение известных прибытий будет 1/2. Это три разных вопроса, а не три варианта одного процента.
Отсутствие открытия в s4 не доказывает отказ человека от продолжения. Возможны сетевой сбой, блокировка измерения назначения или неполный экспорт. Урок о пропусках объяснил эту границу. Здесь мы сохраняем состояние «прибытие не наблюдалось» вместо психологического вывода «читатель потерял интерес».
Само прибытие тоже не равно освоению главы. Оно подтверждает соответствующее событие документа, если договор и доставка исправны. Для учебного результата нужны задания, проверка ответа или содержательная обратная связь с собственной моделью. Не стоит переименовывать воронку открытий в процент прошедших обучение только ради более сильной формулировки.
В нашей таблице нет времени задержки: sequence задаёт лишь относительный порядок. Поэтому нельзя считать скорость прохождения или допустимый интервал между действиями. Для настоящего исследования потребуются временные поля и выбранное окно. Даже появление timestamp не отменит вопроса о том, какое время оно обозначает — действие, получение или обработку.
Разбор последовательности
Ниже полный journey-report.py для условного файла в data/journey.csv. Он использует правило входа и ищет открытие XML после известной активации. Скрипт ничего не загружает из сервисов. Результат относится только к этим придуманным последовательностям.
import csv
from collections import defaultdict
from pathlib import Path
groups = defaultdict(list)
path = Path(__file__).parent / "data" / "journey.csv"
with path.open(encoding="utf-8", newline="") as source:
for row in csv.DictReader(source):
if row["data_kind"] != "fictional":
raise ValueError("This example expects fictional rows")
row["sequence"] = int(row["sequence"])
groups[row["session_id"]].append(row)
starts = clicks = arrivals = 0
for rows in groups.values():
rows.sort(key=lambda row: row["sequence"])
if len({row["sequence"] for row in rows}) != len(rows):
raise ValueError("Duplicate sequence")
first = rows[0]
if (first["event_name"], first["article_id"]) != ("lesson_open", "markdown"):
continue
starts += 1
next_rows = [row for row in rows if
row["event_name"] == "lesson_next" and
row["article_id"] == "markdown" and
row["target_article_id"] == "xml"]
if not next_rows:
continue
clicks += 1
next_position = next_rows[0]["sequence"]
if any(row["sequence"] > next_position and
row["event_name"] == "lesson_open" and
row["article_id"] == "xml" for row in rows):
arrivals += 1
print("starts", starts, "clicks", clicks, "arrivals", arrivals)
Ожидаемый вывод — три входа, две известные активации и одно наблюдаемое прибытие. Код не связывает людей между устройствами и не восстанавливает потерянную историю. Он показывает, как определение превращается в условие отбора. При изменении входного правила соответствующий фрагмент меняется вместе с объяснением.
Разные способы продолжить
Посетитель может перейти к XML через оглавление, закладку или поиск. Тогда открытия будут связаны с маршрутом по содержанию, но события кнопки next не возникнет. Для вопроса «открываются ли следующие главы вообще» нужно учитывать другие пути. Для вопроса «используют ли эту кнопку» наш более узкий набор подходит лучше.
Не пытайтесь искусственно заставить каждого посетителя пройти одну кнопку ради красивой воронки. Каталог и прямые ссылки нужны читателю. В большой библиотеке человек часто ищет один конкретный ответ и начинает с середины серии. Такой вход не является ошибкой навигации и не должен исчезать из отчёта только потому, что не соответствует линейной схеме.
Аналитическая платформа предлагает свои инструменты последовательностей и воронок. Их настройки задают порядок, допустимость других действий и область пользователя или сеанса. Перед переносом нашего правила прочитайте актуальное описание инструмента. В частности, GA4 исследование воронки имеет собственные условия открытого и закрытого входа. Исследование воронки GA4.
Договор событий предоставляет ID текущей и целевой статьи, но сам по себе не создаёт полную последовательность платформы. Сохраните настройки исследования и выбранный источник. Если сервис не позволяет получить нужную детализацию, не заменяйте её вымышленным списком реальных людей. Можно сузить вопрос до доступного агрегата и отметить ограничение.
Редакционный вывод
После наблюдения s4 стоит проверить доступность назначения и доставку его события в собственном контрольном сценарии. После s2 можно исследовать, объясняет ли статья следующий шаг и нужен ли он читателю. Это разные действия, потому что последовательности показывают разные участки неопределённости. Само наличие узкого места ещё не назначает его причину.
Маршрут должен иметь версию. Если редактор вставил новую главу между Markdown и XML, прежние и новые переходы относятся к разным последовательностям. Постоянные ID сохраняются, но course_version меняется. В отчёте мы сначала сравниваем соответствующие версии либо явно описываем новую задачу; объединение без заметки скроет изменение условий.
Теперь у нас есть точное определение входа, различие активации и прибытия и маленькая последовательность для проверки логики. Следующий урок рассмотрит группы материалов: линейный маршрут полезен для курса, но нельзя переносить один показатель на справочники, рецепты и большие главы с разными задачами.