Предиктивная аналитика

Описание прогнозной модели

Прогнозные модели и скрипты размещены на сервере izb-ally-nodered02 (IP: 10.1.241.244).

Скрипты написаны на Python с использованием библиотеки ENTA

python3.10 main.py --help
Usage: main.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  copy      copy time_series from one DB to another
  fit       Fits model with collected lines from DB
  forecast  Makes forecast for the next 7 days and saves it to DB
  test      Evaluates forecast metrics
  view      Prints one segment used for forecast

Наилучшие результаты при прогнозировании показала модель CatBoost.

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

Данные для обучения поступают из различных источников, а результаты прогнозов сохраняются в гипертаблицу time_series.

Для обучения используются погодные данные, которые ежедневно загружаются с сайта rp5.ru в таблицы weather и weather_stations. Загрузка осуществляется с помощью скрипта rp5_weather, который настраивается через файл static/cities.txt. Этот файл содержит список метеостанций по всей стране.

В таблице weather также хранятся исторические данные о погоде, начиная с 2005 года.

Кроме исторических данных, для прогнозирования требуется актуальный прогноз погоды. Он ежедневно загружается с сайта api.met.no через Node-RED в таблицу weather.

Также в прогнозе используется данные табель календаря из таблицы calendar и календарь Православных Христианских праздников.

Также при построении прогноза учитываются данные производственного календаря из таблицы calendar и календаря православных праздников.

Попытка включить мусульманские праздники в расчёт прогноза не улучшила точность.

Прогноз может строиться на заданное количество дней вперёд и с различной степенью дискретизации.

Работа с данными для прогнозов

Мы получаем исходные данные из базы данных MS SQL с помощью SQL-запросов.


Получение данных о заказах

Для получения данных о заказах составляется отчет по заказам с фильтрацией по дате заказа и наличию даты поставки.

Источником получения данных служит таблица Report.[report_zakaz_tbl]

Запрос извлекает данные о заказах из таблицы отчетов за указанный период времени. Запрос фокусируется на заказах, где дата заказа находится в заданном диапазоне, и дата поставки не является NULL. Дополнительно вычисляется поле с датой поставки, увеличенной на 15 минут.

Текст запроса

Ниже представлен запрос для получения информации о заказах:

SELECT 
    id_order as id, 
    ShopNo as shopno, 
    order_type, 
    gettype, 
    date_order, 
    date_supply, 
    date_supply_untill, 
    date_posted, 
    date_collect_start, 
    date_collected, 
    date_delivery_start, 
    date_delivered, 
    sum_paid, 
    sum_paid_coupon, 
    count_pos, 
    latitude, 
    longitude, 
    client_type, 
    order_weight, 
    delivery_hottime, 
    collecting_await_dur, 
    collecting_dur, 
    delivery_await_dur, 
    delivery_dur, 
    completed_agg, 
    distance, 
    DATEADD(Minute, 15, date_supply) as date_supply_vv 
FROM Report.[report_zakaz_tbl] rzt (NOLOCK) 
WHERE date_order BETWEEN '{{payload.from}}' AND '{{payload.to}}' 
AND date_supply IS NOT NULL
Поля запроса

Запрос возвращает 27 полей. Ниже приведена таблица с описаниями:

Поле SELECT Исходное поле Тип данных
id id_order INT
shopno ShopNo INT
order_type order_type TinyInt
gettype gettype TinyInt
date_order date_order DateTime
date_supply date_supply DateTime
date_supply_untill date_supply_untill DateTime
date_posted date_posted DateTime
date_collect_start date_collect_start DateTime
date_collected date_collected DateTime
date_delivery_start date_delivery_start DateTime
date_delivered date_delivered DateTime
sum_paid sum_paid FLOAT
sum_paid_coupon sum_paid_coupon FLOAT
count_pos count_pos SmallInt
latitude latitude Decimal(19,16)
longitude longitude Decimal(19,16)
client_type client_type NVarChar(100) COLLATE Cyrillic_General_CI_AS
order_weight order_weight Decimal(15,3)
delivery_hottime delivery_hottime DateTime
collecting_await_dur collecting_await_dur INT
collecting_dur collecting_dur INT
delivery_await_dur delivery_await_dur INT
delivery_dur delivery_dur INT
completed_agg completed_agg INT
distance distance Real
date_supply_vv date_supply (вычисляемое)
Фильтры запроса

В запросе присутствуют 2 фильтра:

Вычисляемые поля

В запросе есть вычисляемое поле:


Получение данных о геозонах

Для получения данных о геозонах составляется отчет по зонам с фильтрацией по магазинам.

Источником получения данных служит таблицы [GeoReports].[Analytics].[EffectiveZonesOnlineServices] и [Geo].[geo].[tt]

Запрос объединяет данные из двух таблиц для получения информации о зонах, услугах и временных интервалах.

Текст запроса

Ниже представлен запрос для получения информации о заказах:

SELECT 
    tt.N AS id_tt, 
    id_online_service, 
    id_poly, 
    date_add, 
    geo, 
    payway, 
    time_start, 
    time_end 
FROM [GeoReports].[Analytics].[EffectiveZonesOnlineServices] (NOLOCK) z
JOIN [Geo].[geo].[tt] tt ON tt.id_TT = z.id_tt
WHERE tt.name_TT LIKE '%ДС[_]%
Поля запроса

Запрос возвращает 8 полей. Ниже приведена таблица с описаниями:

Поле SELECT Исходное поле Тип данных
id_tt tt.N

id_online_service

id_online_service


id_poly

id_poly


date_add

date_add


geo

geo


payway

payway


time_start

time_start


time_end

time_end

 
Фильтры запроса

В запросе присутствуют 2 фильтра:


Таблицы хранения полученных данных

Исходные данные, используемые для построения прогноза, размещены в следующих таблицах:

Кроме того, на базе этих таблиц создаются материализованные представления:

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

vv_orders_ts
Поле  Тип данных
id int4
shopno int4
order_type int4
gettype int4
date_order timestamp
date_supply timestamp
date_supply_untill timestamp
date_posted timestamp
date_collect_start timestamp
date_collected timestamp
date_delivery_start timestamp
date_delivered timestamp
sum_paid float8
sum_paid_coupon float8
count_pos int2
latitude numeric(19, 16)
longitude numeric(19, 16)
client_type varchar(100)
order_weight numeric(15, 3)
delivery_hottime timestamp
collecting_await_dur int4
collecting_dur int4
delivery_await_dur int4
delivery_dur int4
completed_agg int4
distance float4
date_supply_vv timestamp
details jsonb
tt_id int4
geohash varchar(20)
test_vv_points
Поле  Тип данных Описание
geohash varchar(20) Геохэш области
tt_id numeric ИД иорговой точки
coeff int4

Вероятность того, что заказ в данной области попадет в данную ТТ. Определяется на основе статистики заказов за предыдущие 3 дня

 

weather
Поле  Тип данных Описание
weather_station_id int4 ИД погодной станции
date timestamp Время
temperature numeric(3, 1)

Температура

humidity int4

Влажность

wind_speed int4

Скорость ветра

weather_stations
Поле  Тип данных Описание
id serial4 ИД погодной станции
active bool Признак активности
calendar
Поле  Тип данных Описание
id serial4 ИД
date date Дата
type int4 Тип (2 - суббота, 3 - воскресенье, 4 - предпраздничный день, 5 - праздник)
vv_orders_ts_hash_hourly

Для составления представления формируется запрос который формирует представление для хранения агрегированных данных о количестве заказов, сгруппированных по геохешу и часовым интервалам. Исключаются заказы с типом получения gettype = 6. Представление обновляется автоматически.

Источником получения данных служит таблица vv_orders_ts.

Текст запроса:

CREATE MATERIALIZED VIEW vv_orders_ts_hash_hourly 
WITH (timescaledb.continuous) AS 
SELECT 
    geohash, 
    time_bucket('1 hour', ts.date_supply_vv) AS bucket, 
    COUNT(*) AS cnt 
FROM vv_orders_ts ts 
WHERE ts.gettype != 6 
GROUP BY geohash, bucket;

Поля запроса:

Поле Тип данных Описание
geohash varchar(20)
bucket timestamp  
cnt int8
vv_lines_ts_hash_hourly

Для составления представления формируется запрос который формирует представление для хранения агрегированных данных о суммарном количестве позиций (строк) в заказах, сгруппированных по геохешу и часовым интервалам.

Источником получения данных служит таблица vv_orders_ts.

Текст запроса:

CREATE MATERIALIZED VIEW vv_lines_ts_hash_hourly 
WITH (timescaledb.continuous) AS 
SELECT 
    geohash, 
    time_bucket('1 hour', ts.date_supply_vv) AS bucket, 
    SUM(ts.count_pos) AS cnt 
FROM vv_orders_ts ts 
GROUP BY geohash, bucket;

Поля запроса:

Поле Тип данных Описание
geohash varchar(20)
bucket timestamp  
cnt int8  


Хранение результатов обработки исходных данных

Данные для прогнозов, сами прогнозы и результаты их анализа хранятся во временных рядах в таблице time_series:

Поле Тип данных Описание
id bigserial
tstamp timestamptz  
type int4 Описывает тип данных
restaurant_id int4
user_id int4
value float8 Значение прогноза
details jsonb  

Тип прогноза, для которого сформирован результат обработки, определяется значением поля type. Возможные числовые значения поля и их интерпретация приведены ниже. Сформированный прогноз по часам помещается в таблицу под типами 4-7

type Описание Подразделение Тип Источник
1 Данные по доставке Последняя миля Исходные данные Репликатор
2 Данные по сборке Последняя миля Исходные данные Репликатор
4 Прогноз доставка Последняя миля Прогноз Python
5 Прогноз сборка Последняя миля Прогноз Python
6 Прогноз по геозонам доставка Последняя миля Прогноз Python
7 Прогноз по геозонам сборка Последняя миля Прогноз Python
51 Оценка трудоемкости розница Розница Исходные данные Node-RED
52 Прогноз суммарной трудоемкости Розница Розница Прогноз Python
53 Прогноз трудоемкости кассиров Розница Розница Прогноз Python
55 Факт суммарной выработки Розница Розница Аналитика pgAgent
56 Факт выработки кассиров Розница Розница Аналитика pgAgent
154 Курьеры факт Последняя миля Аналитика Node-RED
155 Курьеры план Последняя миля Аналитика Node-RED
156 Курьеры прогноз Последняя миля Аналитика Node-RED
157 Заказы план Последняя миля Аналитика Node-RED


Запросы для составления прогнозов

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

 


Зональный прогноз доставки

Для зонального прогноза доставки извлекаются и агрегируются данные рассчитываемые как сумма количества заказов (cnt), умноженного на коэффициент из геоточки (coeff), сгруппированных по идентификатору торговой точки (tt_id) и часовому интервалу (bucket).

Ниже представлен запрос который делает все это и объединяет данные о заказах с географическими точками для анализа по сегментам (торговым точкам или зонам) в заданном диапазоне дат:

SELECT 
    h.bucket AS timestamp, 
    vp.tt_id AS segment, 
    SUM(cnt * coeff) AS target 
FROM vv_orders_ts_hash_hourly h 
JOIN test_vv_points vp ON vp.geohash = h.geohash 
WHERE bucket BETWEEN '{from_date}' AND '{to_date}' 
GROUP BY vp.tt_id, h.bucket;

Запрос берет значения из:

Запрос формирует следующие поля:

Поле в SELECT Исходное поле Описание
timestamp h.bucket Временной интервал, начало часа для агрегации данных о заказах.
segment vp.tt_id Идентификатор торговой точки, к которой привязан geohash.
target (Вычисляемое) Сумма (cnt * coeff), где cnt — количество заказов, coeff — коэффициент из геоточки.

 


Зональный прогноз сборки

Для зонального прогноза сборки извлекаются и агрегируются данные рассчитываемые как сумма количества строк в заказах (cnt), умноженного на коэффициент (coeff), сгруппированных по идентификатору торговой точки (tt_id) и часовому интервалу (bucket).

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

SELECT 
    h.bucket AS timestamp, 
    vp.tt_id AS segment, 
    SUM(cnt * coeff) AS target 
FROM vv_lines_ts_hash_hourly h 
JOIN test_vv_points vp ON vp.geohash = h.geohash 
WHERE bucket BETWEEN '{from_date}' AND '{to_date}' 
GROUP BY vp.tt_id, h.bucket;

Запрос берет значения из:

Запрос формирует следующие поля:

Поле в SELECT Исходное поле Описание
timestamp h.bucket Временной интервал, начало часа для агрегации данных о заказах.
segment vp.tt_id Идентификатор торговой точки, к которой привязан geohash.
target (Вычисляемое) Сумма (cnt * coeff), где cnt — количество строк в заказах, coeff — коэффициент из геоточки.

 


Данные о погоде

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

Ниже представлен запрос данных о погоде с дополнением последними значениями на конечную дату.

WITH t AS (
    SELECT 
        w.weather_station_id AS station_id, 
        w.date, 
        w.temperature, 
        w.humidity, 
        w.wind_speed, 
        ROW_NUMBER() OVER (PARTITION BY w.weather_station_id ORDER BY w.date DESC) AS rn 
    FROM weather w 
    JOIN weather_stations st ON st.id = w.weather_station_id 
    WHERE st.active AND date BETWEEN '{from_date}' AND '{to_date}'
)
SELECT 
    station_id, 
    date, 
    temperature, 
    humidity, 
    wind_speed 
FROM t 
UNION 
SELECT 
    station_id, 
    '{to_date}', 
    temperature, 
    humidity, 
    wind_speed 
FROM t 
WHERE t.rn = 1 
ORDER BY station_id, date;

Запрос берет значения из:

Запрос формирует следующие поля:

Поле в SELECT Исходное поле Описание
station_id w.weather_station_id Идентификатор погодной станции.
date w.date Дата измерения погоды.
temperature w.temperature Температура
humidity w.humidity Влажность воздуха
wind_speed w.wind_speed Скорость ветра

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

37 - (37 - temperature) / (0.68 - 0.0014 * humidity] + 1 / (1.76 + 1.4 * pow(wind_speed, 0.75))) - 0.29 * temperature * (1 - humidity / 100)

В этой формуле:

 


Календарные данные

В прогнозах используются данные производственного календаря из таблицы и календарь Православных Христианских праздников.

Ниже представлен запрос календарных данных:

SELECT 
    date, 
    type AS holiday 
FROM calendar 
WHERE date BETWEEN '{from_date}' AND '{to_date}' 
ORDER BY date;

Запрос берет значения из:

Запрос формирует следующие поля:

Поле в SELECT Исходное поле Описание
date date

Дата календарного события

holiday

type

Тип события

Данные о православных праздниках хранятся в файле: calendar.csv

Логика прогнозов

Прогноз для последней мили:

Прогнозы по сборке и доставке строятся с шагом 1 час и охватывают период в 14 дней вперёд.

Обычный прогноз.

Основан на данных о сборке и доставке, где каждый заказ привязан к ТТ.

Данные загружаются в БД Ally из БД MS SQL через Node-RED.

Зональный прогноз.

Основан на данных о сборке и доставке, где каждый заказ привязан к ТТ, и на статистике распределения адресов по зонам той или иной ТТ.

На основе геозон ТТ формируются сводные буферы, по которым рассчитываются вероятности выполнения заказов конкретной ТТ, исходя из статистики за последние 7 дней.

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


Прогноз для розницы

Прогноз по трудоёмкости строится с шагом 1 день и охватывает 21 день вперёд.

Основан на оценке трудоёмкости, которая загружается во временной ряд 51 через Node-RED.


Расчёт требуемого количества сборщиков

Прогноз трудоёмкости сборщиков автоматически пересчитывается в требуемое количество сборщиков. Расчёт выполняется по следующему алгоритму:

  1. Оценка скорости сборки сотрудников
    Для каждого сотрудника рассчитывается средняя скорость сборки на основе фактических данных за последний месяц. Скорость выражается в количестве строк, которые сотрудник собирает в час.
  2. Расчёт плановой производительности
    Для каждого часа прогнозируемого периода рассчитывается ожидаемое количество собранных строк на основе списка запланированных сборщиков и их индивидуальной скорости работы.
  3. Сравнение с прогнозом
    Вычисляется разность между прогнозируемым количеством строк на сборку и плановой производительностью сборщиков.
  4. Корректировка численности
    Разность преобразуется в дополнительное или избыточное количество сотрудников. Для этого используется средняя скорость сборки по всем сборщикам на данной торговой точке.
  5. Вывод итогового количества
    Полученное число используется для формирования рекомендаций: сколько сотрудников необходимо добавить или убрать из смены в конкретный час.

Для подсчета скорости сборки заказов используется подход средней скорости сборки которая рассчитывается как количество собранных строк в течение одного часа (строки / час).


Расчет требуемого количества курьеров

Прогноз по требуемому количеству курьеров можно описать формулой:

Где:

t — Конкретный час, о котором идёт речь

Dt — Сколько заказов на доставку ожидается в этот час

Nt — Сколько людей уже поставили смену на этот час

Средняя скорость работы i-го человека, записавшегося в смену

Средняя скорость по всем курьерам на точке

Rt — Сколько работников нужно вывести в итоге в этот час