Однажды мы решили посмотреть, какие сезонные интересы есть у пользователей 2ГИС в разных городах. Всплески интереса к цветам, новогодним подаркам и шинам — вполне ожидаемы. Мы решили ими не ограничиваться и пойти дальше, проверив все сферы деятельности во всех 113 городах присутствия.

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

Зачем вообще нужно измерять сезонность?


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

  • Мы начинаем больше понимать о ценностях и интересах наших пользователей в данный момент и в ближайшем будущем.
  • Мы можем «предугадывать» запрос пользователя.
  • Менеджеры по продажам концентрируются на актуальных для пользователей сферах деятельности.

Виды трафика


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

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

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

Гео-трафик возникает в том случае, когда пользователь работает с картой. Например, ищет ближайшие к дому аптеки или СТО.

Все пользовательские запросы и все последующие за ними действия размечаются по трафику. Для поиска сезонностей в анализ взяли дискавери + гео-трафик. Так как они, во-первых, соответствуют проявлению пользовательских интересов, во-вторых, ими можно управлять. Управлять рекавери-трафиком нельзя.

Про тренды


График 1: Вы видите сезонность?
График 1: Вы видите сезонность?

Перед тем, как приступить к поиску сезонности, нужно учесть изменения объёма трафика на разных типах устройств. Мы учитывали, что аудитории WinPhone и ПК-версий непрерывно падают. Тогда как онлайн, Android, iOS — перманентно растут.

Проверка гипотез о наличии тренда


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

Можем проверить гипотезу о том, что все выборочные значения принадлежат к одной генеральной совокупности со средним m. Тогда основная гипотеза имеет вид:
$H_0: m_i=m, i=1,2,...,N$
против конкурирующей гипотезы о наличии тренда
$inline$H_1: ?m_{i+1}?m_i? > 0, i=1,2,...,N?1$inline$
где N — это количество элементов в ряде.

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

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

График 2: Временной ряд (из графика 1) и его тренд
График 2: Временной ряд (из графика 1) и его тренд

Про грабли и открытия


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

  1. Пропуски в данных. В узких сферах деятельности в некоторые даты может не быть данных. Особенно кейс актуален для маленьких городов. Эту особенность нужно учитывать для корректного построения регрессии.
  2. В случае обнаружения точки перегиба — учитывайте её близость к началу или концу ряда. Возможна неправильная интерпретация поведения ряда в краевых условиях. Например, на графике 2 первые 120 точек, казалось бы, указывают на кусочно-линейный рост. Но, на самом деле, это проявила себя сезонность, которую мы увидим позже.
  3. Выбор правильной точки отсчёта. Чтобы получить корректные коэффициенты, нужно использовать ряд, начиная с первой значимой точки, и запоминать координату X этой точки (дату появления данных в ряде). Тренд будет строится в системе координат с 0 в этой точке. Этот кейс актуален для сравнения сфер между собой. Например, в 2ГИС города запускались не одномоментно и, соответственно, начинали отправлять статистику в разное время. То же самое справедливо для появления новых бизнесов, таких как, например, барбершопы.
  4. Пожалуй, самое сложное — это найти компромисс между уровнем детализации и достаточностью объёма данных. Мы остановились на тройке измерений: город, сфера деятельности, платформа пользовательского устройства.

График 3: Ряд без тренда
График 3: Ряд без тренда

Поиск сезонностей


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

  1. Обнаружения самого факта наличия сезонности ряда.
  2. Определения высокого и низкого сезонов — именно это имеет практическую ценность.

Обнаружение корреляций


Готовые функции поиска корреляций есть как в R, так и в Python. Мы использовали корреляцию Пирсона. При работе с векторами пользовательских интересов надо иметь в виду следующее:

  • После вычитания тренда из исходного ряда могут получиться отрицательные значения. Это нормально на данном этапе.
  • Для нашей задачи достаточно проверки корреляции временных рядов в 365 дней. Да, влияние високосного года незначительно и мы его в расчёт не берём.
  • Для поиска сезонности необходимо наличие данных как минимум за два полных периода. В наших расчётах использовались данные за четыре периода.

Ищем корреляцию двух векторов: X: [0; N-365], Y: [366; N]. Где N — длина ряда.

График 4: Обнаружение корреляции
График 4: Обнаружение корреляции

Получаем пользу


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

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

В нашем случае [пока] достаточно временного масштаба продолжительностью в месяц. Для определения уровня 1 использовали медиану помесячного внимания пользователей. Далее вычисляли кратное отклонение от этой медианы.

График 5: Годовая сезонность
График 5: Годовая сезонность

Пора раскрыть тайну, какие данные показывают графики статьи. На этом и всех предыдущих графиках — клики в музеи Санкт-Петербурга. Как видно из последнего графика, музеи популярны в январские праздники, когда много выходных, и летом.

А что если ...


… взять и скормить алгоритму не интересы пользователей, а, например, продажи?

Алгоритм действий такой же:

  1. Ищем тренды. Аудитория городов растёт, и вместе с ней растёт число рекламодателей. Надо вычитать тренд, связанный с ростом популярности 2ГИС как рекламной площадки, для получения отраслевых всплесков и спадов.
  2. Находим корреляции продаж из года в год, а затем высокий и низкий сезоны.

Понадобилось внести ряд коррективов


Реклама в 2ГИС продаётся помесячно, поэтому за масштаб взяли месяц, но пользовательскую сезонность анализировали с точностью до дня. Для обратной совместимости адаптировали алгоритмы, чтобы они работали с произвольными рядами, где по оси X — порядковый номер точки, а по оси Y некое value (на этом уровне семантика value не имеет значения).

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

Так как продажи помесячные, то и точек в рядах у нас существенно меньше. В этом случае корреляцию надо считать в 12 точек вместо 365.

График 6: Сезонность продаж
График 6: Сезонность продаж

В качестве завершающего этапа мы решили наложить сезонность продаж на пользовательскую сезонность. Теперь видно, где мы продаём рекламу позже, чем надо, и отстаём от пользовательского спроса.

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

График 7: Пересечение пользовательской сезонности и сезонности продаж
График 7: Пересечение пользовательской сезонности и сезонности продаж (зеленый — пользовательская, голубой — продажи, красный — совпадение)

На чём делали


Всё выше описанное реализовано в MS SQL Server 2016. Для поиска линейной регрессии и корреляции используется R, который входит в состав сервера, начиная с версии 2016. И поскольку у нас Data Warehouse и аналитика пользовательской статистики уже на SQL Server, оказалось очень удобным использовать R для математических расчётов.

Пример использования R из TSQL:

INSERT INTO #tmp
EXEC sp_execute_external_script
	@language = N'R',
	@script = @R,
	@input_data_1 = N'SELECT DataId, Number, Value FROM #data ORDER BY 1, 2'

Где:

  • переменная R содержит непосредственно R-код;
  • language = N'R' — указывает на то, что скрипт, переданный в переменной R, содержит код на языке R. В SQL Server 2017 помимо R можно использовать language = N'Python'. Тогда, соответственно, в параметр script необходимо передать код на Python.
  • input_data_1 — содержит SQL-запрос, к результатам которого внутри R-кода можно обращаться как к InputDataSet;
  • Результатом выполнения процедуры будет рекордсет OutputDataSet, сформированный как OutputDataSet < — calcAllTrend(data = InputDataSet);
  • Обязательно указать формат результирующего рекордсета: количество и типы столбцов. В данном случае формат OutputDataSet определяется таблицей #tmp, куда происходит запись результатов. Либо можно воспользоваться WITH RESULT SETS для описания результирующего рекордсета.

В нашем случае оказалось, что существенную часть времени выполнения sp_execute_external_script занимает непосредственно обращение к R Services. Сам R-код отрабатывал быстро.

Напомню, мы хотели посчитать тренды и сезонности для всех городов покрытия 2ГИС и всех сфер деятельности. Поэтому решили передавать в InputDataSet не один ряд (Number, Value), а сразу несколько, сгруппированных по DataId. А цикл по DataId организовали внутри R. Тем самым существенно сэкономили на вызове службы R Services.

Факты из жизни


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

Факт №1


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

График 8: Сезонности шин в Краснодаре, Новосибирске и Норильске
График 8: Сезонности шин в Краснодаре, Новосибирске и Норильске

Факт №2


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

График 9: Поиск новогодних подарков в онлайне и мобильной версии 2ГИС
График 9: Поиск новогодних подарков в онлайне и мобильной версии 2ГИС

Факт №3


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

Спойлер-подсказка
Сильно разные города России. Значит, ни погода, ни регион, ни локальные бизнесы, а что-то глобально общее.
3 месяца = квартал. Обратите внимание на апрель…

График 10
График 10

Ответ
Это фонды социального страхования — квартальная отчётность сдается в ФСС раз в три месяца, а апрельский пик объясняется сменой форм отчетности с 1 января каждого года.

Ещё раз о главном


Собираетесь искать корреляции в данных? Не забудьте эти данные подготовить: обработать пропуски, очистить от трендов и выбросов. Имейте в виду, что подготовка займет бОльшую часть времени.

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

P.S.: задача поиска трендов и сезонностей делалась в рамках другой задачи — прогнозирования изменения пользовательского внимания после приобретения рекламы в 2ГИС. Готов рассказать, как мы делали прогноз, если вам будет интересно.

Комментарии (13)


  1. EgorZanuda
    14.06.2018 08:17

    Так не пойму для чего такая статистика нужна? Грамотный товаровед в магазине до грамма знает сколько ему нужно товара закупить в зависимости от сезона.


    1. Shirshakov Автор
      14.06.2018 08:33
      +1

      График №7 показывает, что нет :)
      Обратите внимание, пользователей интересуют бетон, ЖБИ, кровля и ландшафтная архитектура на месяц раньше, чем товароведы в компаниях начинают заниматься продвижением своей продукции.


    1. trogg
      14.06.2018 08:34

      А откуда он это знает? Провел такой же анализ у себя в голове даже не осознавая этого.


  1. Androniy
    14.06.2018 08:32

    Рост общего числа запросов явно не линеен. Может правильней было пронормировать к общему объему трафика в это же время? Обрабатывать относительное число запросов по заданной теме к общему количеству запросов в этот день. Таким образом уйдут периодичности связанные с общей низкой/высокой активностью, и останется исключительно повышенный интерес к конкретной теме…


    1. Shirshakov Автор
      14.06.2018 09:12

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


  1. Cedric
    14.06.2018 10:16

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


    1. Shirshakov Автор
      14.06.2018 17:52

      Расскажите, пожалуйста, почему вы используете ПК-версию? Online-версия всегда под рукой, поисковой движок куда мощнее и данные самые оперативные.


      1. Cedric
        14.06.2018 18:18

        Мой телефон-не позволяет.


        1. uploadfor
          15.06.2018 10:25

          Cedric, надо было не оправдываться за свой телефон, а сразу его к стенке прибивать встречным: «Расскажите, пожалуйста, зачем вы сделали ПК-версию?» :)


  1. jazator
    14.06.2018 15:16

    Может быть продажа больших данных в обозримом будущем это одно из направлений по монетизации сервиса 2ГИС. А пока нет компаний способных это потреблять и переваривать. Кто-то должен появится, кто будет выкупать все эти данные у 2ГИС и других и делать по ним фантастические прогнозы. На данный момент представленные данные могут быть интересны только 2ГИС.
    Рассуждая со своей колокольни (курорт на Алтае) могу представить, допустим, 2ГИС передаёт мне мониторинг запросов по отелям. Что я могу из него почерпнуть, да толком ничего. Высокий и низкий сезон и так хорошо фиксируются, пошли звонки и дело пошло, даже прогноз погоды мне больше скажет по коротким заездам. Если брать тонкие моменты, допустим, пошли запросы по ресторанам, делаем вывод, что поехал клиент с толстыми кошельками, рискнём поднять цены на люксы? Нет. Одного 2ГИС мало, нужен монстр, что питается и другими данными и способен помочь принять мне решение. И это не проблема 2ГИС, они и без этого прекрасный продукт, снискавший благодарности пользователей.
    Могу пожелать им только активнее работать со своими клиентами, у них невероятная основа для развития бизнеса, для новых моделей взаимодействия. 99% потенциальных клиентов получают от 2ГИС бесплатную рекламу, рассуждая — зачем тратиться, если и так всё хорошо. Предложите заправкам размещать цены на платной основе, застройщикам планы квартир, агентствам объекты на карте, развлекаловкам анонсы, таксистам расчёт маршрута, курьерам и доставщикам карты охвата с тарифами и т.п. Только на одном туризме можно поднять миллионы, но опять же рассуждение с моей курортной колокольни.


    1. uploadfor
      15.06.2018 07:16

      А пока нет компаний способных это потреблять и переваривать.

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

      Так что вполне может быть, что компании эти давно уже есть, просто потреблять и переваривать им до сих пор было нечего ;)


      1. jazator
        15.06.2018 08:11

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


    1. InnaSavchkova
      15.06.2018 09:08

      Какой подробный комментарий, спасибо! Согласны, что сейчас не каждому бизнесу полезны данные 2ГИС. И, конечно, согласны, что есть куда развиваться — главное не переборщить с детализацией и не утонуть в сверке, потому что автоматически мало кто отдает информацию, о которой вы написали.

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