imageКаждый день поступает все больше заказов, и их нужно как-то распределять по исполнителям. Вроде ничего сложного: пришёл заказ – отдай его клинеру. Но не всё так просто, как кажется. У наших клинеров нет фиксированного графика работы, они могут работать, когда захотят, отказываться практически от любых заказов (и это клинеры, увы, делают довольно часто). Поэтому распределение заказов – одна из самых сложных задач, над которой мы работаем.

ОСНОВНЫЕ ПРОБЛЕМЫ


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

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

Такие заказы мы называем “горящие”. Их бывает достаточно много, и надеяться на то, что клинеры разберут их в приложении не стоит. Поэтому мы распределяем их вручную. Сотрудники колл-центра обзванивают клинеров и предлагают им заказы. Это трудоемкий процесс, требующий времени и ресурсов.

В день распределяется от 50 заказов вручную, в сезон случается и вовсе адище – может быть и 300. Это занимает много времени и ресурсов.

Другая проблема – невыполненные заказы. Каждый день мы не выполняем примерно 2% заказов потому, что не можем или не успеваем найти на них клинеров. Если мы их не выполняем, дарим клиенту бесплатную уборку. Каждый день мы дарим около 20 бесплатных уборок, а в сезон эта цифра может достигать 200-300.

Как мы решаем эти проблемы?

1. Клинерское приложение

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

image

Эти ленты различаются для разных сегментов клинеров. Например, клинеры-новички никогда не увидят заказы наших постоянных клиентов. Эту видимость мы регулируем матрицей. Числа означают, за какое время клинер видит заказ в приложении.

image

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

2. Автоназначение

Вместе со стремительным ростом заказов, растет и число “плохих” заказов. “Плохие” – это те, которые в конечном итоге не состоятся или будут отменены. Нам нужно было что-то с этим делать, и поэтому мы решили немного хайпануть и заюзать ML, чтобы предсказать такие заказы.

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

Взяли готовые библиотеки

import numpy as np
import pandas as pd
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

Загрузили фичи

features = pd.read_csv('train/train.csv', header = 0)
X = features.drop(['cancel'], axis=1)
y = features.cancel

Разделили выборку на обучающую и тестовую

X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=1234)

Обучили градиентным бустингом

gb_clf = GradientBoostingClassifier(learning_rate=0.2, n_estimators=70, max_depth=3, verbose=False, random_state=241)
gb_clf.fit(X_train, y_train)

Проверили на тестовой выборке

y_true = y_test
y_pred = final_gb_clf.predict_proba(X_test)[:,1]
roc_auc=roc_auc_score(y_true, y_pred)

roc-auc: 0.881929812245

Сделали прогноз

features = pd.read_csv('predict_features.csv', header = 0, index_col='order_id')
y_predict = gb_clf.predict_proba(features)[:,1]
print(y_pred)

Получили неплохую roc-auc = 0.88. И закинули в продакшн.

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

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

image

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

Запилили им расписание. Но, как в итоге оказалось, клинеры в принципе его не соблюдают. А заставлять их – противоречит нашим устоям.

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

Алгоритм

Ищем заказы, которые нужно распределить, вычищаем из них “плохие” c помощью полученной оценки вероятности отмены. Подбираем потом на каждый заказ клинеров. Сначала тех, которых хочет видеть клиент – избранных – и назначаем их на заказ. Если все они заняты, то подбираем других клинеров, которые уже были у клиента, но просто не были никак оценены. Если и они заняты, просто ищем ближайшего свободного клинера.

Результаты

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

Выводы

Не бойтесь использовать ML в своих задачах — сделать простую модель не составляет труда. На написание моделей у нас ушло всего пару дней работы одного аналитика. Зато теперь мы можем использовать её в наших бизнес-процессах.

Задавайте вопросы в комментариях, будем рады на них ответить.

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


  1. lair
    28.04.2018 15:37

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

    Это когда у вас данные под руками есть.


  1. WildZero
    28.04.2018 15:55

    Если мы их не выполняем, дарим клиенту бесплатную уборку

    2 подряд регулярные уборки, на которые не нашлось клинера — 500 бонусных рублей. Что-то здесь не сходится.


  1. dolphin4ik
    28.04.2018 18:44

    А какое количество параметров учитывалось для обучения? на вскидку на ум приходят время заказа и стоимость. Но этого явно маловато…


    1. rstrekalov Автор
      28.04.2018 19:01

      Например
      информация о клиенте:
      cколько до этого отменял уборок, сколько до этого выполнилось уборок, подписчик или нет, сколько времени прошло с последнего заказа
      информация про заказ:
      Стоимость, доп. услуги, когда был создан заказ(за сколько времени до начала), была ли скидка, были ли переносы заказы, как был создан заказ (через веб/приложение/кц)


  1. diswest
    28.04.2018 18:52
    +1

    Попробуйте LightGBM или XGBoost, если еще не пробовали. Они тот же самый градиентный бустинг обычно быстрее и точнее делают после тюнинга. За полдня можно сделать. Количество кода не сильно изменится.


    1. rstrekalov Автор
      28.04.2018 19:02

      Обязательно попробуем. Спасибо)


    1. griganton
      28.04.2018 23:17

      В свою очередь, порекомендую попробовать отечественную разработку — Catboost, в последнее время он стал очень хорош.


  1. lumaxy
    29.04.2018 05:35

    А можно поподробнее, как запускается уже обученная модель на новых заказах? Хотелось бы побольше технических деталей вот этой части: «И закинули в продакшн. Теперь каждое утро нам в базу данных падает оценка вероятности отмены заказа»


  1. AmberSP
    29.04.2018 13:21

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


    А что выступает в качестве признаков в этих моделях? Особенно интересна модель про клинеров.


    1. Stas911
      30.04.2018 19:28

      Интересно, какие неочевидные связи они выяснили — типа: «клинеры 30+ чаще канселяют заказы по вторникам»