Тип Syntetos Boylan Croston (SBC), аккуратный прогноз, структура спроса

Анализ временных рядов - широко используемый метод в бизнесе для получения полезной информации, такой как прогнозирование спроса, определение сезонных продуктов, категоризация моделей спроса и другие характеристики. Здесь мы сосредоточимся на прогнозировании временных рядов (с использованием статистической модели / машинного обучения / модели глубокого обучения для прогнозирования будущих значений) & категоризация моделей спроса (категоризация продуктов по количеству и времени).

В этом блоге я собираюсь объяснить, как мы можем подогнать несколько (1000+) моделей временных рядов, используя статистические (классические модели), модели машинного обучения и глубокого обучения, проектирование функций временных рядов и структуру спроса. категоризация. Эта серия будет состоять из следующих 5 частей:

Часть 1: Очистка данных и категоризация спроса.

Часть 2: Подгоните статистические модели временных рядов (ARIMA, ETS, CROSTON и т. Д.) С использованием пакета R fpp3 (аккуратное прогнозирование).

Часть 3: Разработка функций временных рядов с использованием пакета timetk R.

Часть 4. Подходите Модели машинного обучения (XGBoost, Random Forest и т. д.) & Настройка гиперпараметров с использованием пакетов R.

Часть 5: Подгонка моделей углубленного изучения (NBeats и DeepAR) и настройка гиперпараметров с использованием пакетов R.

Давайте начнем!

PS: это не ЕДИНСТВЕННЫЙ метод решения этой проблемы. Однако это один из способов решить эту проблему.

Данные

Я использую данные с хакатона Прогнозирование спроса на продукты питания в AnalyticsVidhya. Цель этого хакатона - спрогнозировать количество заказов для каждой комбинации еды / центра для службы доставки еды. У нас есть в общей сложности 3 548 комбинаций приема пищи / центра (т. Е. 77 центров и 51 прием пищи), что означает, что модели временного ряда 3548 необходимо будет подогнать. Этот метод в деловой среде также известен как масштабируемое прогнозирование.

Давайте импортируем библиотеки.

pacman::p_load(tidyverse, magrittr) # data wrangling packages
pacman::p_load(lubridate, tsintermittent, fpp3, modeltime, timetk, modeltime.gluonts, tidymodels, modeltime.ensemble, modeltime.resample) # time series model packages
pacman::p_load(foreach, future) # parallel functions
pacman::p_load(viridis, plotly) # visualizations packages
theme_set(hrbrthemes::theme_ipsum()) # set default themes

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

meal_demand_tbl <- read.csv(unz("data/raw/train_GzS76OK.zip", "train.csv")) # reading train data
new_tbl <- read.csv("data/raw/test_QoiMO9B.csv") # the data need to forecast
skimr::skim(meal_demand_tbl %>% 
              # remove id
              select(-id) %>% 
              # make center & meal id factors
              mutate(center_id = factor(center_id),
                     meal_id = factor(meal_id))) # summary of data

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

На этом этапе были выполнены этапы предварительной обработки данных. Затем эти данные были преобразованы в данные временных рядов (то есть в объект tsibble: это особый тип данных, который обрабатывает модели временных рядов в пакете fpp3).

Приведенная выше сводка показывает, что в 77 центрах продается 51 вид еды, что составляет в общей сложности 3 548 данных временных рядов, каждый из которых состоит из 145 недель. Здесь нам нужно будет спрогнозировать количество заказов (num_orders) для каждой комбинации блюд / центр. Более того, посмотрев на столбец complete_rate, мы можем увидеть, что в переменных нет пропущенных значений.

Столбец week состоит из чисел от 1 до 145, поэтому нам нужно будет заменить его на даты. Также удалим комбинации (прием пищи / центр), которые не требовали прогнозирования.

date_list <- tibble(id = seq(1, 155, 1),
                    week_date = seq(from = as.Date("2016-01-02"), by = "week", length.out = 155))
master_data_tbl <- meal_demand_tbl %>%
  left_join(date_list, by = c("week" = "id")) %>% # joining the date
  inner_join(distinct(new_tbl, meal_id, center_id), by = c("meal_id", "center_id")) %>% # remove combos that did not want to forecast
  select(week_date, num_orders, everything(), -c(week, id))

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

Например, следующие данные временного ряда (таблица 1) показывают, что после 4-й недели отсутствуют данные вплоть до 7-й недели. В таблице 2 показаны завершенные данные с новыми записями за те недостающие недели (т.е. недели 5 и 6).

Затем emailer_for_promotion & homepage_featured переменные преобразуются в коэффициент.

master_data_tbl <- master_data_tbl %>%
  as_tsibble(key = c(meal_id, center_id), index = week_date) %>%
  ## num_urders missing value imputation ----
  fill_gaps(num_orders = 0, .full = end()) %>% # make it complete by max week dates
  ## X variables missing value imputation ----
  group_by_key() %>%
  fill_(fill_cols = c("emailer_for_promotion", "homepage_featured", "base_price", "checkout_price")) %>% # filling other variables
  ungroup() %>%
  ## change variables to factor ----
  mutate(emailer_for_promotion = factor(emailer_for_promotion), 
         homepage_featured = factor(homepage_featured))

Аналогичная операция проводится с файломsubmission.

## New Table (Submission file) data wrangling ----
new_tbl <- new_tbl %>%
  left_join(date_list, by = c("week" = "id")) %>% # joining the date
  full_join(new_data(master_data_tbl, n = 10), by = c("center_id", "meal_id", "week_date")) %>%
  as_tsibble(key = c(meal_id, center_id), index = week_date) %>%
  group_by_key() %>%
  fill_(fill_cols = c("emailer_for_promotion", "homepage_featured", "base_price", "checkout_price")) %>% # filling other variables
  ungroup() %>%
  # change variables to factor
  mutate(emailer_for_promotion = factor(emailer_for_promotion), 
         homepage_featured = factor(homepage_featured))

Визуализация пищевых данных временного ряда

График 1. Количество заказов по центрам

master_data_tbl %>%
  # Randomly Pick 4 Centres
  distinct(center_id) %>% 
  sample_n(4) %>% 
  
  # Joining the transaction data
  left_join(master_data_tbl) %>% 
  group_by(week_date, center_id) %>% # aggregate to centres
  summarise(num_orders = sum(num_orders, na.rm = T)) %>%
  as_tsibble(key = center_id, index = week_date) %>%
  fill_gaps(num_orders = 0, .full = end()) %>%
  autoplot(num_orders) +
  scale_color_viridis(discrete = T)

На приведенном выше графике показано, что первые несколько недель транзакций для Центра № 24 равны 0; эти транзакции были удалены. Однако после этого периода времени существуют непрерывные транзакции, которые были включены в данные для соответствия модели.

master_data_tbl <- master_data_tbl %>%
  filter(center_id != 24) %>%
  bind_rows(master_data_tbl %>%
              filter(center_id == 24 & week_date > as.Date("2016-07-16"))) # remove entries before 2016/07/16 for center 24

График 2: количество заказов по идентификаторам блюд

master_data_tbl %>%
  # Randomly Pick 4 Meals
  distinct(meal_id) %>%
  sample_n(3) %>%
  # Joining the transaction data
  left_join(master_data_tbl) %>% 
  group_by(week_date, meal_id) %>%
  summarise(num_orders = sum(num_orders, na.rm = T)) %>%
  as_tsibble(key = meal_id, index = week_date) %>%
  fill_gaps(num_orders = 0, .full = end()) %>%
  autoplot(num_orders) +
  scale_color_viridis(discrete = T)

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

Категоризация спроса - метод SBC.

Теперь мы собираемся определить каждую категорию модели спроса на комбинированные блюда / комплекс (S непостоянный, неустойчивый, неровный и прерывистый).

Почему?

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

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

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

Как?

В R мы можем использовать функцию idclass в пакете R tsintermittent. В функции idclass, когда параметр type равен SBC, будут вычислены следующие два значения:

  1. cv2 - измеряет изменение количества
  2. p - измеряет интервал между запросами

Основываясь на этих двух показателях, мы можем разделить структуру спроса на Сглаженный (p ‹1,32 & cv2‹ 0,49) , Неустойчивый (p ‹1,32 & cv2 ≥ 0,49 ) , неровный (p ≥1,32 и cv2 ≥0,49) и прерывистый (p ≥1,32 и cv2 ‹0,49) .

Плавный:

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

Ошибочно:

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

Периодически:

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

Неровно:

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

Приступим к кодированию!

Во-первых, мы преобразуем данные более длинного формата в более широкий формат, т. Е. Создаем 3 548 столбцов (общее количество данных временных рядов для приема пищи / центра). Например:

# make each combo ts as column
  wide_dt <- .x %>%
    transmute(week_date, id = paste0("x_", center_id, "_", meal_id), num_orders) %>%
    pivot_wider(names_from = id, values_from = num_orders, values_fill = 0) %>%
    arrange(week_date) %>% # arrange by week date
    select(-week_date) %>%
    data.frame()

Затем примените idclass к преобразованному фрейму данных.

ts_cate_obj <- idclass(wide_dt, type = "SBC", outplot = "none")

ts_cate_obj, показанный выше, представляет собой матрицу. Теперь мы изменим этот формат матрицы на thedata.frame, а затем применим значения отсечения для категоризации моделей спроса.

ts_categorization <- data.frame(id = row.names(t(wide_dt)),
                                  cv2 = ts_cate_obj$cv2,
                                  p = ts_cate_obj$p) %>%
    separate(id, into = c("x", "center_id", "meal_id"), sep = "_") %>%
    select(-x) %>%
    mutate(demand_cate = case_when(p < 1.32 & cv2 < 0.49 ~ "Smooth",
                                   p >= 1.32 & cv2 < 0.49 ~ "Intermittent",
                                   p < 1.32 & cv2 >= 0.49 ~ "Erratic",
                                   p >= 1.32 & cv2 >= 0.49 ~ "Lumpy")) %>%
    mutate(center_id = as.integer(as.character(center_id)),
           meal_id = as.integer(as.character(meal_id)))

Давайте посмотрим сводку приведенного выше анализа в виде гистограммы.

Приведенный выше график показывает, что в данных большинство комбинаций приема пищи / центра временного ряда попадают в категорию «Плавный и непостоянный». Это означает, что хорошо подошла бы модель обычного временного ряда, такая как ARIMA, ETS и т. Д. Кроме того, были установлены передовые модели, такие как Croston & SBA, чтобы справиться с неустойчивой и неоднородной структурой спроса. Модели машинного обучения / глубокого обучения также можно адаптировать, используя этот тип шаблона спроса в качестве функции. Метод перекрестной проверки использовался для соответствия комбинациям без спроса (т. е. транзакций менее 20).

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

Ссылки

Куренцес, Н., 2014. Пакет периодического прогнозирования спроса для Р. - Николаоса Курентеса. Kourentzes.com. Доступно по адресу: ‹https://kourentzes.com/forecasting/2014/06/23/intermittent-demand-forecasting-package-for-r/› [по состоянию на 22 января 2021 г.].

БЕСПЛАТНО. 2021. Классификация спроса: почему имеет значение прогнозируемость - Frepple APS. Доступно по адресу: ‹https://frepple.com/blog/demand-classification/› [по состоянию на 22 января 2021 г.].