Типичное обсуждение легитимности внедрения ML - алгоритмов.
Типичное обсуждение легитимности внедрения ML - алгоритмов.

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

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

Меня зовут Никита Зеленский, я руковожу отделом по работе с данными в Whoosh, разработчике технологических решений и операторе микромобильности. Эту статью мы написали вместе с Иваном Маричевым, дата‑сайнтистом Whoosh. Он же и автор алгоритма, о котором пойдет речь.

Здесь мы расскажем, как мы реализовывали модель прогнозирования спроса на самокаты, с чем сталкивались при прототипировании, какие модели были протестированы, чем наш случай отличается от прогнозирования спроса в каршеринге, спроса для пополнения запасов в дарксторе и т. п. (Самокат, самокаты Whoosh передают привет!)

История получилась про наши подходы и грабли, которые мы в итоге собрали. Чуть‑чуть про технику, чуть‑чуть про бизнес — нескучно и с ветерком (как на самокате).

Whoosh!

Проблематика

Зачем менять устоявшуюся схему, разрабатывать ML‑модель, если можно все сделать в Экселе?

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

Вопрос — почему бы просто не выставлять сильно завышенное количество техники? Представим следующую картину: в среднестатистическом городе Х имеется 350–400 парковок (если не брать в расчет города‑миллионники). По каждой парковке мы собираем статистику: какое количество поездок пользователи на ней начали и закончили. Зная эти цифры, можно было бы оставлять на них количество самокатов, равное скользящему среднему от количества поездок за 7 дней + 20%? Но не все так просто:

  1. Флот << прогноз. Маловероятно, что прогнозируемое таким образом количество техники будет возможно предоставить в рамках флота, доступного в городе. Даже если вы лидер отрасли и у вас большое количество самокатов в локации — это сильно неразумный способ, который замедлит интеграцию в новые регионы и районы.

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

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

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

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

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

EDA

Ключевой этап при создание любой модели — сбор данных, а именно их чистота и репрезентативность, т. е. насколько наши данные корректны и содержат ли всю необходимую информацию (это тот случай, когда принцип GIGO актуален как никогда). Также необходимо быть готовым, что создание ML‑моделей — процесс крайне итеративный, и часто при оценке метрик моделей может потребоваться произвести новую выборку признаков или обогатить исходный датасет новыми данными.

Что мы имеем на входе?

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

Суточная структура временного ряда парковки при агрегации по 3 часа
Суточная структура временного ряда парковки при агрегации по 3 часа
Суточная структура временного ряда парковки при агрегации по 30 минут
Суточная структура временного ряда парковки при агрегации по 30 минут

 

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

Пример “топовой” парковки
Пример “топовой” парковки
Пример “слабо востребованной” парковки
Пример “слабо востребованной” парковки
  1. Пропуски в данных. Наш бизнес имеет определенную сезонную динамику. В большинстве городов мы работаем 9 месяцев: с марта по ноябрь. А анализируя временные ряды, такие пробелы между датами (с декабря по февраль) просто так не выкинешь — их необходимо правильно обрабатывать: подсказывать модели периоды завершения сезона и его начала, что было между этими датами, а также периоды, когда локация встает на кратковременную паузу. В противном случае, мы будем иметь «кривую» линию тренда с завышенным или заниженным показателями.

Также в ходе EDA было определено, что прогнозирование на все 100% парковок для города не имеет бизнес‑смысла, так как 40% «топовых» парковок генерировали 80% всех поездок города.

В качестве тестового города выступает город Сочи в связи с тем, что сезон аренды самокатов в городах южного округа продолжается круглогодично. Тем самым мы, конечно, немного проигнорируем п.3 из списка нюансов выше, но у нас другие цели для MVP:

  • Проверить работоспособность алгоритма (а это проще сделать без разрыва во временных рядах)

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

Выбор модели

С вводными разобрались, теперь приступим к выбору обучающей модели. Как упоминалось ранее, парковок, и, соответственно, рядов для прогнозирования, много — десятки тысяч. Для нас скорость обучения важна не менее (если не более), чем точность самой модели, поэтому при принятии решения какую модель (или модели) выбирать, мы основывались на показателях RMSE и среднему времени, которое мы получаем при прогнозировании данных для n‑парковок. Мы протестировали модели SARIMAX, LightGBM, Prophet и NeuralProphet.

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

  1. SARIMAX — стандартная ARIMA (авторегрессионное интегрированное скользящее среднее) — наиболее популярный метод для однофакторного прогнозирования данных временных рядов. Недостатки ARIMA в том, что при построении прогноза учитываются только данные самого ряда, без внешних факторов‑регрессоров. Так как наши показатели спроса напрямую зависят от множества факторов (погода, праздники, пробки и т. д.), в нашей ситуации алгоритм не будет работать.

SARIMAX же является расширением ARIMA с добавленными алгоритмами обработки сезонности и экзогенных переменных — регрессоров (используемые гиперпараметры — SARIMAX(3, 0, 2)x(2, 1, 1)).

Прогноз SARIMAX
Прогноз SARIMAX

Плюсы:

  • Высокая точность уже «из коробки», учитывая доверительный интервал прогноза;

  • Развёрнутая документация

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

Минусы:

  • долгий подбор гиперпараметров (около 10 минут на парковку).

  1. LightGBM — реализация градиентного бустинга за авторством Microsoft. По опыту примения бустинговых моделей (чаще всего в регрессионных задачах, хотя и в двоичной\множественной классификации алгоритм также хорош), LightGBM — явный фаворит в связи с более высокой (x1.5 — x2) скоростью обучения при практически идентичной точности (разница на уровне погрешности ± 1%) в сравнении с XGBoost, CatBoost, etc.

    Плюсы:

  • Высокая скорость обучения.

  • Большой набор гиперпараметров.

  • Менее ресурсоемко по сравнению с аналогами.

  • Возможность параллельного и GPU-обучения.

Минусы:

  • К сожалению, мы получили переобучение. Даже при автоматизированном подборе гиперпараметров, на тесте так же отсутствует предсказательная способность. Решили не закапываться и поискать возможные альтернативы.

Результаты экспериментов с моделью lightGBM на трейн
Результаты экспериментов с моделью lightGBM на трейн
Результаты экспериментов с моделью lightGBM на тесте
Результаты экспериментов с моделью lightGBM на тесте
  1. Prophet — относительно молодая библиотека прогнозирования от “ЛицоКниги”. Prophet является расширением авторегрессионных моделей, которое  позволяет использовать не только лаговые значения целевой переменной, но и дополнительные признаки (реализовано через ​​применение ряда Фурье к таргету), т.е. позволяет использовать дополнительные переменные — регрессоры. Для нас это было особенно актуально, так как сами лаговые значения таргета не обеспечивают точного прогноза, и требуются дополнительные независимые переменные.

Prophet имеет ряд других полезных функций, например:

  • Высокая точность и скорость обучения “из коробки”.

  • Удобно реализованы базовые функции (в частности, добавления регрессоров).

  • Отслеживание изменений тенденции.

  • Функционал создания пула дат со значениями-аутлаерами (праздниками, спортивными событиями), которые исключались из построения общего тренда + сезонности. 

  • Поддерживается и регулярно обновляется разработчиками.

И пара минусов:

  • По умолчанию нет настроек нормализации временного ряда и сопутствующих регрессоров.

  • Пропуски\аутлаеры в данных лучше обработать вручную.

Результаты экспериментов с моделью Prophet
Результаты экспериментов с моделью Prophet
  1. NeuralProphet ‑ модификация базовой библиотеки Prophet с добавлением нейронного слоя. По сравнению с Prophet бэкэнд переехал со Stan на PyTorch. Идея использовать Prophet, обладающий высокими результатами (особенно после тюнинга) по функциям потери\времени, и при этом добавить однослойную нейронную сеть для теоретического улучшения точности показалась нам крайне интересной, после чего мы построили модель уже на NeuralProphet. API у библиотек практически идентичны, как и почти все ключевые функции, поэтому технически реализовать было несложно.

    Результаты экспериментов с моделью NeuralProphet
    Результаты экспериментов с моделью NeuralProphet

Из плюсов можно выделить:

  • Хороший уровень точности «из коробки»

  • В библиотеку интегрирован слой pyTorch, благодаря которому реализован подбор параметров через градиентный спуск

  • Автоматическая предобработка данных (заполнение пропусков, нормализация и т. д.)

Минусы:

  • Низкая скорость обучения, связанная с профилированием DL‑настроек (количество эпох, learning rate, etc) для каждой парковки в индивидуальности

Что получили на выходе?

Prophet

NeuralProphet

LightGBM

SARIMAX

RMSE

1.3

2.19

13.23

1.43

total_time (min)

5.59

32.20

2.33

58.20

Табл.1 сравнения метрики RMSE и времени выполнения алгоритмов на n‑парковок.

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

Разумеется, как бы хороша библиотека не была, чуда «по умолчанию» не произошло, и прежде чем Prophet начал демонстрировать приемлемые результаты предстояло решить ряд проблем. Например, данные по температуре меньше -1°C модель принимала как NaN и пришлось видоизменять датасет с погодой под этот баг. На старте прототипирования у нас были сложности с прогнозированием пиков, так как к дневной сезонности прибавлялись естественные шумы. Решить эту проблему получилось путем добавлением регрессоров с высокой корреляцией к таргету, в первую очередь, связанные с погодными метриками и пользовательской активностью.

Большие надежды также возлагались на NeuralProphet, так как библиотека позиционируется как «быстрее‑выше‑сильнее Prophet во всем», однако в нашем случае это оказалось не совсем верно. Небольшую прибавку в точности (+3–5%) получалась только путем значительного увеличения количества эпох, как следствие — всего времени обучения в 2 — 2,5 раза.

В случае с топовыми и дефицитными парковками Prophet позволил умеренно‑эффективно прогнозировать данные не только там, где присутствует явная структура (тренд + сезонность), но и там, где спрос не обладает устойчивой структурой.

Результаты работы модели Prophet на “топовой” парковке
Результаты работы модели Prophet на “топовой” парковке

             

Результаты работы модели Prophet на “слабо востребованной” парковке
Результаты работы модели Prophet на “слабо востребованной” парковке

Общая модель ребаланса

Необходимо учитывать, что парковки обладают различной структурой не только в плане спроса («топовые» и «слабо востребованные»), но и в плане ориентированности.

Часть парковок являются кольцевыми, то есть начало поездки и ее окончание — это одна и та же парковка. Как правило, это актуально для парковок возле парков или других крупных точек притяжения. Другая часть парковок являются однонаправленными — с парковки часто стартуют, и редко финишируют (или наоборот). Это обычная картина для парковок с большим количеством близлежащих жилых домов. Что это нам дает? Это значит, что старты на отдельной взятой парковке могут быть распределены нормально, а вот финиши — нет.

Искушенный аналитик спросит — для чего вообще рассчитывать финиши, если они, в отличие от стартов, не аккумулируют прибыль и их нет необходимости как‑либо обеспечивать со стороны ребаланса?

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

  1. Берем последнее историческое наблюдение количества самокатов (scooters_last).

  2. Прогнозируем количество стартов на ближайшие X‑часов (starts_forecast).

  3. Прогнозируем количество финишей на тоже количество X‑часов (finishes_forecast).

Необходимый флот на парковку = scooters_last - starts_forecast + finishes_forecast

Схема ребаланса
Схема ребаланса

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

На выходе мы получаем таблицу такого вида:

Финальная таблица ребаланса
Финальная таблица ребаланса

где:

ds — время, к которому подвезти самокаты,

parking_id — номер парковки,

rebalance — фактическое значение ребаланса (положительное — профицит, отрицательное — дефицит),

class_ — тип парковки, требуется для приоритизации парковок для сервисных центров.

Вывод

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

Разумеется, это далеко не весь список задач, в который у нас внедрен ML: здесь и классификации (в том числе и гео‑классификации по индексу Морана), и регрессионные модели расчета целевых бизнес метрик, и многое другое.

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

Уважайте пешеходов, водите осторожно и до встречи на улицах.

Whoosh!

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


  1. iivvaall
    00.00.0000 00:00
    +2

    А вы только старты рассматриваете? В прошлом сезоне активно пользовался самокатами. Рассматривал их в том числе как альтернативу маршрутки до метро. Езжу после часа пик. Вот не получается стартануть ни утром, и ни вечером. Утром все самокаты у метро, вечером у домов.


    1. avanmw Автор
      00.00.0000 00:00

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


      1. iivvaall
        00.00.0000 00:00
        +1

        От меня у вас нет ни стартов, ни финишей. Ну просто потому, что самокатов в нужное мне время просто нет. Без явного учета доступности, ваша модель это не увидит. Она будет свято верить, что все хорошо, ибо ожидание старта нулевое.


        1. ChristinaPR
          00.00.0000 00:00

          Если что-то идет не так, всегда ждем фидбек в чате приложения — проверим в чем дело и по какой причине система не работает. Нужен только адрес и краткое описание ситуации. Для нас это очень важно ????


  1. SE1LL
    00.00.0000 00:00

    Доброго времени суток!

    Подскажите, пожалуйста, как вы выбрали начальную точку (от которой начали обучение)? Что если в данный период на какой-то парковке изначально не было самокатов (при этом это потенциальная точка старта) и из-за этого старты были 0. Не будет ли в таком случае ошибки при обучении?


    1. avanmw Автор
      00.00.0000 00:00

      Здравствуйте! Да, такая ситуация имела место. На раннем этапе обходили это увеличением прогноза для таких значений, т.е. там, где прогнозировался 0 стартов, все равно подвозится не более 1-2 самоката (актуально для прогноза на ночной и утренний (~ 6:00) период). Как правило, из 10-12 таких "перепрогнозированных" (в превентивный мерах) парковок только на одной в итоге был фактический старт.


  1. lozy_rc
    00.00.0000 00:00
    +1

    Спасибо за то что поделились! Dart не пробовали? Общий API и большое кол-во моделей из коробки + можно оборачивать их API на линейные модели вроде sklearn, есть даже интересности вроде N-BEATS или NLinearModel с возможно обучения на GPU через pytorch lightning. Есть модельки Future-known covariates, например добавить прогноз погоды на неделю, с самокатами будет актуально


    1. avanmw Автор
      00.00.0000 00:00

      Здравствуйте, нет, Dart не тестировали, но посмотрю документацию на возможность совместить с нашими требованиями. По поводу добавления ковариационный переменных - в финальной Prophet-модели независимые переменные погоды (температура и осадки) уже используются при прогнозирование (и все верно - связь между поездками и погодой практически линейная).


  1. Mentalitet
    00.00.0000 00:00

    А вы для каждой парковки строили свою модель деревьев получается? Не пробовали обучить одну модель на много схожих парковок?


    1. avanmw Автор
      00.00.0000 00:00

      Да, для каждой парковки строится своя модель. Обобщенную модель пробовали, но в нашем случае не подошло: часто парковки схожи по типу (допустим, все парковки топовые) и общему количеству стартов, но при этом сильно различаться по суточной\недельной структуре спроса - например, у первой один суточные пик в 19 часов, у второй два пика спроса - в 9 и 20, и модель, обученная на структуре первой парковки будет давать высокую ошибку на второй парковке.