Привет, Хабр! Есть мнение, что прогнозирование временных рядов - сложная задача. Но не будем расстраиваться, ведь есть и плюсы - существует ещё большое количество задач, когда рядов сразу несколько, и такие задачи ещё сложнее! Когда начинаем сравнивать, понимаем, что прогнозировать одномерные временные ряды не так уж и сложно. А вот что делать с ситуацией, когда временной ряд обрастает параллельно идущими с ним последовательностями других параметров (многомерный ряд), какие методы и алгоритмы использовать, и что делать, если задача прогнозировать такие ряды есть, а опыта не очень много (спойлер - используйте AutoML, а пока он работает восполните пробел прочитав пару статей по теме), разбираем под катом.

Что такое временной ряд 

Если начинать совсем издалека, то это последовательность значений, упорядоченная по времени. Во временных рядах есть закономерность: текущие значения ряда связаны с предыдущими. Если такого свойства у ряда нет, то поздравляем (или не поздравляем), вы имеете дело с процессом, который прогнозировать классическими (и не очень) моделями не выйдет, в таком случае стоит смотреть в сторону Марковских процессов.

Простенькая картинка ниже иллюстрирует описанное выше свойство, - этого бэкграунда для продолжения чтения поста достаточно (Рисунок 1).

Рисунок 1. Пример временного ряда
Рисунок 1. Пример временного ряда

Если хочется узнать подробнее как временные ряды прогнозировать (особенно при помощи AutoML), можете изучить пост Прогнозирование временных рядов с помощью AutoML

Что такое многомерный временной ряд

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

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

Рисунок 2. Схема многомерного временного ряда. Целевой параметр показан красным цветом, экзогенные временные ряды - синим
Рисунок 2. Схема многомерного временного ряда. Целевой параметр показан красным цветом, экзогенные временные ряды - синим

Как видно из картинки, чтобы прогнозировать будущие состояния временного ряда 1 мы можем также использовать значения временных рядов 2 и 3. Если интересуют прикладные примеры таких рядов - то вот, уровень моря, измеряемый в разных точках показан на Рисунке 3.

Рисунок 3. Многомерный временной ряд уровня воды в разных точках Тихого океана. По данным спутниковой альтиметрии (данные Copernicus “Sea level daily gridded data from satellite observations”)
Рисунок 3. Многомерный временной ряд уровня воды в разных точках Тихого океана. По данным спутниковой альтиметрии (данные Copernicus “Sea level daily gridded data from satellite observations”)

Теперь стоит выделить два разных случая “прогнозирования многомерных временных рядов”. В первом у нас на момент формирования прогноза будут доступны данные экзогенных временных рядов только на текущий момент времени и предыстория, то есть t, t-1, t-2, t-n, в то время как данные на индексы прогноза t+1, t+2, t+f (где f - горизонт прогнозирования), неизвестны. Или второй вариант, когда для целевого временного ряда значения на прогнозные индексы неизвестны, но зато есть информация об экзогенных в эти моменты времени. Красочнее всего это можно показать на схеме (см. Рисунок 4).

Рисунок 4. Прогнозирование целевой переменной с использование вспомогательных временных рядов
Рисунок 4. Прогнозирование целевой переменной с использование вспомогательных временных рядов

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

P.S. Если хотите послушать про построение динамических регрессий с использованием временных закономерностей, ставьте лайки этой статье, жмите на колокольчик и пишите комментарии. Если наберем 30 классов, то обязательно напишем и про это :)

Как их можно прогнозировать

Ещё ближе к основной теме. Поведение системы из нескольких временных рядов прогнозируется при помощи векторной авторегрессии (VAR). VAR является обобщением идеи авторегрессии для нескольких временных рядов, так что считается классическим выбором для специалиста, занимающимся прогнозированием многомерных рядов. Несколько временных рядов могут включаться в классические модели прогнозирования, такую как, например, ARIMA. В таком случае такие модели будут называться Vector Auto Regressive Moving Average models (VARMA). Для решения данной задачи также применяются рекуррентные нейронные сети, и являются очень популярным инструментом в данной области. Использование “более продвинутых” подходов, например на основе оптимизации того же самого VAR, обычно встречается в научных статьях по ключевым словам “multivariate time series forecasting”.

Попробуем рассмотреть подход обобщения уже известного нам способа прогнозирования одномерных временных рядов на многомерный случай. Как было рассказано в статье Прогнозирование временных рядов с помощью AutoML, временные ряды можно прогнозировать как при помощи классических моделей (AR, ARIMA), так и при помощи регрессионных моделей машинного обучения. Только для использования регрессионных моделей может потребоваться сделать специальное преобразование ряда в матрицу. Для одномерного случая схема преобразования представлена на картинке ниже (Рисунок 5).

Рисунок 5. Преобразование в траекторную матрицу одномерного временного ряда
Рисунок 5. Преобразование в траекторную матрицу одномерного временного ряда

Для многомерного временного ряда будет получена следующая таблица (Рисунок 6). Размер скользящего окна и горизонт прогнозирования не меняются по сравнению с предыдущей схемой.

Рисунок 6. Преобразование в траекторную матрицу многомерного временного ряда.
Рисунок 6. Преобразование в траекторную матрицу многомерного временного ряда.

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

  • Размер скользящего окна, которое используется для всех временных рядов одновременно, может быть неоптимальным. Для одного из рядов может быть достаточно “заглянуть в прошлое” только на 5-10 элементов, чтобы успешно прогнозировать будущее, в то время как для других рядов лаговый сдвиг потребуется делать на сотни элементов;

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

Бороться с этими проблемами, естественно, можно. И дальше мы рассмотрим как именно. А пока сконцентрируемся на том, как можно всё таки запустить AutoML инструмент для решения задачи прогнозирования многомерного временного ряда.

Как такие ряды прогнозируются в FEDOT (взгляд снаружи) 

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

Описание данных

Демонстрацию произведем на данных уровня моря, полученных при помощи модели NEMO (Nucleus for European Modelling of the Ocean). Данная модель позволила подготовить нам датасет с измерениями уровня моря SSH (sea surface height). Временных рядов мы собрали в количестве 25 штук, их расположение на условной карто-схеме можно увидеть на картинке ниже.

Интересующий нас временной ряд выделен на картинке квадратиком. Именно его мы и будем прогнозировать при помощи предыстории параметра в этой точке и при помощи предыстории из соседних. Горизонт прогнозирования - 50 элементов. 

Датасет целиком (под названием SSH) как и код для запуска есть в репозитории pytsbe.

Для этого воспользуемся следующим кодом (наши временные ряды - это numpy массивы, а сам пример запуска есть здесь, версия fedot для эксперимента - 0.6.0):

# Collect dataset with time series to train model
train_data = {}
feature_series = list(train_df['label'].unique())
for feature_ts in feature_series:
  current_ts = train_df[train_df['label'] == feature_ts]
  train_data.update({str(feature_ts): np.array(current_ts['value'])})
  
# Configure AutoML
task_parameters = TsForecastingParams(forecast_length=forecast_horizon)
model = Fedot(problem='ts_forecasting', task_params=task_parameters)
target_series = train_df[train_df['label'] == target_column]
obtained_pipeline = model.fit(features=train_data, 
                              target=np.array(target_series['value']))
# Use historical value to make forecast
forecast = model.predict(train_data)

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

Немного о возможностях конфигурации

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

Если же запускать AutoML алгоритм нет необходимости, но построить хоть какую-то простую модель за небольшое время требуется, можно воспользоваться параметром predefined_model='auto' в методе fit. Как знаете, AutoML ядро FEDOT основано на эволюционном алгоритме. А эволюционный алгоритм перед началом оптимизации генерирует один или несколько пайплайнов (начальных приближений), модифицируя которые итеративно получает всё более и более точные решения. Итак, возвращаемся к параметру predefined_model='auto'. Это сделает следующее - AutoML алгоритм сгенерирует начальное приближение. Однако процесс оптимизации не запустит, а только обучит это одно автоматически сгенерированное начальное приближение и вернёт обученный пайплайн. Это позволит быстро подготовить модель без запуска AutoML алгоритма. То есть мы используем заранее определенную конфигурацию пайплайна (в данном случае, автоматически генерируемую самим алгоритмом) и обучаем только её и ничего больше. Естественно, этот процесс требует значительно меньше времени, чем запуск AutoML ядра. Пример как это должно выглядеть в коде показан ниже:

obtained_pipeline = model.fit(features=train_data, 
                              target=np.array(target_series['value']), 
                              predefined_model='auto')

Итак, запускается эволюционный процесс, который после определенного числа поколений позволяет получить следующий результат (Рисунок 7).

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

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

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

Как такие ряды прогнозируются в FEDOT (взгляд изнутри) 

Теперь рассмотрим процесс поиска решения. Сначала алгоритму необходимо с чего-то начать процесс эволюции, - с некоторого корректного начального приближения. Такое начальное приближение генерируется автоматически, и получается следующий пайплайн - см. Рисунок 8. 

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

Выглядит конечно монструозно, но с чего-то надо начинать :) Что же тут происходит. Сначала нам временные ряды подаются каждый в свой “data source” узел (1). Эти временные узлы ничего каждый со своим временным рядом не делают, а передают его дальше. 

Зачем это сделано? - Чтобы можно было подключать к пайплайну новые источники данных, плюс это помогает разобраться с каким именно временным рядом какие преобразования происходят в пайплайне (обратим внимание на названия после слэша, там показаны метки временных рядов, что позволяет однозначно идентифицировать их). Таким образом можно понять, что для временного ряда с названием 0 были применены lagged преобразование и при этом его копия была передана в GLM модель (2). GLM - это обобщенная линейная модель, которая может работать напрямую с временным рядом и ей не требуется его преобразование в траекторную матрицу. Вывод из lagged преобразования передается в модель гребневой регрессии (3). 

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

Затем уже на основе данного начального приближения посредством применения мутаций генерируется начальная популяция из пайплайнов для эволюционного алгоритма. В процессе оптимизации структуры пайплайна AutoML алгоритм может менять операции (модели) в узлах, удалять узлы и ребра, добавлять новые и настраивать гиперпараметры операций. Это значит, что потенциально возможным становится получать следующие структуры (Рисунок 9).

Рисунок 9. Возможные структуры пайплайнов, получаемые в ходе оптимизации
Рисунок 9. Возможные структуры пайплайнов, получаемые в ходе оптимизации

Как видно из Рисунка 9, при необходимости мы можем удалять узлы и целые ветки и таким образом избавляться от временных рядов, которые никак не связаны с целевым. 

Также в процессе оптимизации графа мы можем настраивать отдельно размер скользящего окна для каждого из рядов (регулируется гиперпараметром window size в lagged преобразовании). Это решает проблему с использованием в модели не репрезентативных экзогенных рядов-предикторов.

Ради чего столько мучений?

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

Сначала попробуем спрогнозировать временной ряд при помощи автоматически сгенерированного алгоритмом начального приближения. При этом в качестве предикторов будем использовать предысторию целевого временного ряда, а затем будем итеративно расширять количество используемых временных рядов. На последних 50 элементах временного ряда будут сопоставляться прогнозные и действительные значения. Метрика: средняя абсолютная ошибка (MAE). Результаты данной проверки представлены на анимации ниже:

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

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

Рисунок 10. Значение MAE при использовании различного количества временных рядов в модели
Рисунок 10. Значение MAE при использовании различного количества временных рядов в модели

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

Заключение

В данном посте мы рассмотрели какие есть подходы к прогнозированию многомерных временных рядов. Обсудили как можно прогнозировать такие ряды при помощи AutoML. А после посмотрели подробнее как все устроено в этом AutoML инструменте изнутри. 

Прогнозируйте временные ряды, используйте FEDOT!

Полезные ссылки: 

  • Репозиторий open-source AutoML фреймворка FEDOT 

  • Репозиторий open-source библиотеки для запуска алгоритмов прогнозирования временных рядов и бенчмаркинга - pytsbe (модуль совсем новый, так что если вы хотите поучаствовать в его open-source разработке - присоединяйтесь!)

  • Канал NSS Lab — анонсы наших новых статей и выступлений, посвященных AI/ML

С объяснением концепции того как можно прогнозировать многомерные временные ряды выступал Сарафанов Михаил и команда NSS lab

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


  1. sunnybear
    30.10.2022 16:48

    AutoML/VAR проигрывает подходу GRU/LSTM, а там более трансформерам. У них нет проблемы с размерностью


    1. Dreamlone
      30.10.2022 18:46
      +4

      Спасибо за комментарий! Однако по поводу "проигрывает" не соглашусь. Смотря что взять как критерий.

      Если речь идёт про ошибку прогноза у финальной модели, полученной при помощи n-го количества часов работы m-го количества экспертов (как правило n и m здесь совсем немаленькие числа), то пожалуй да, подходы на основе нейронных сетей могут прогнозировать со значительно меньшей ошибкой (хотя и не всегда, но потенциально да, это более эффективные модели). С другой стороны, если речь идёт про интерпретируемость или обобщаемость подхода на смежные задачи (например прогнозирование временных рядов немного других процессов, чем тех для которых была подготовлена модель на основе нейронных сетей), то тут, как мне кажется, как раз GRU/LSTM и трансформеры уже уступают классическим моделям и моделям на основе AutoML описанных в данной статье.

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

      И ещё стоит сказать, что AutoML не предполагает исключение нейросетевых подходов в прогнозировании. В фреймворке например LSTM спокойно сущесвует как составной блок пайплайнов, наряду с ARIMA моделями и другими. Поэтому при необходиомсти эволюционный алгоритм способен выстраивать "гибридные" пайплайны, если это будет приводить к уменьшению ошибки прогноза. И если так смотреть на технологию, то описанный AutoML и нейронные сети совсем не являются конкурентами друг другу


  1. imageman
    31.10.2022 13:56
    +2

    А могли бы пару слов рассказать про ресурсы, необходимые на этапе обучения и на этапе прогнозирования? К примеру можно ли Федота настроить на получение быстрой и компактной модели (в ущерб качеству)? При обучении с расчетом на мобильные устройства какой метод обычно лучше -- трансформеры или ARIMA (через Федота)?

    Правильно ли я понимаю, что на небольшом наборе данных Федот даст лучший результат, нежели трансформеры?


    1. Dreamlone
      31.10.2022 19:34
      +1

      Да, конечно ответим :) Если что - коллеги подскажут более подробно, а начать могу я.

      Про ресурсы для обучения и прогнозирования: FEDOT версии 0.6.0 строится поверх, как правило, scikit-learn моделей машинного обучения. Поэтому ресурсов каждый узел потребляет соразмерно соответствующим реализациям sklearn'a. Учитывая, что признаков в таких крупных пайплайнах получается много, то и время обучения для разветвленных пайплайнов на больших временных рядах будет относительно большим. С другой стороны, в FEDOT, как и в большинстве современных AutoML фреймворков реализована система "пресетов". Под пресетом в FEDOT можно понимать сценарий использования. Например, пресет "best_quality" предполагает использование всех возможных в фреймворке моделей без каких-либо ограничений. "fast_train" будет использовать только те модели, которые быстрее обучаются, "gpu" - те модели, которые можно обучать на GPU и так далее. То есть при поиске равновесия между "качество" - "время обучения" в первую очередь стоит смотреть на пресеты. Подробнее можно посмотреть документацию - там описано за что каждый пресет отвечает и какие есть варианты.

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

      С третьей стороны, ограничивать сложность пайплайнов можно варьированием параметра "max_pipeline_fit_time". То есть оптимизационное ядро будет отметать все решения, которые обучаются дольше заданного порога.

      Если же речь про совсем быстрый способ. Если, как говорится, "нет времени объяснять, нужна модель пять минут назад", то в таком случае подойдёт вариант с "predefined_model", когда фреймворк строит и обучает всего одну модель по заранее определенным правилам. См. раздел "Немного о возможностях конфигурации" в текущей статье.

      Говоря про сравнение по быстродействию с нейронными сетями, то конечно обучить связку "траекторная матрица - гребневая регрессия" (а это как правило ключевой составной блок в начальных приближениях FEDOT) значительно быстрее, чем нейронную сеть. При этом, как я понимаю этот ваш компьютер саенс, быстрее такая связка обучаться будет на временных рядах любого размера (хоть одномерных, хоть многомерных) :) Но бенчмарки по производительности не проводил, ровно как и не припомню статьи на эту тему - хотя, возможно, они существуют

      И наконец про небольшой набор данных: да, на небольших временных рядах FEDOT в серии наших экспериментов показывал хорошие результаты. Простые модели действительно чаще "выживают" в процессе эволюции на таких данных. Однако, чтобы однозначно ответить на этот вопрос, надо конечно провести сравнение с нейросетевыми моделями, которые идентифицируются (то есть строятся и обучаются / дообучаются) примерно за такое же время, что и ансамбли при помощи FEDOT. Пока напрямую с нейронными сетями таких сравнений не проводили


      1. imageman
        31.10.2022 19:47

        В одном месте уточним. Я просил не "быстро обучить", а "обучить быструю модель", т.е. чтобы на клиентском устройстве (микроконтроллер, web-cam, телефон) модель работала быстро и не требовала гигабайты памяти. Частично это решается через задание вручную в конфигурацию подходящих именно мне моделей (на этапе обучения). Как понимаю пока специального пресета для создания легковесных моделей нет?
        Жаль нет сравнения с нейронками (хотя бы на сравнительно небольших наборах данных).


        1. niclnno
          31.10.2022 22:50
          +2

          >Как понимаю пока специального пресета для создания легковесных моделей нет?

          Есть близкий по назначению пресет fast_train.

          >Жаль нет сравнения с нейронками (хотя бы на сравнительно небольших наборах данных).

          Есть статья (не наша, от зарубежных пользователей), где авторы сравнивают FEDOT с с DeepAR и TFT - решениям на основе RNN: https://link.springer.com/chapter/10.1007/978-3-031-16474-3_45

          Получилось у них так:

          Вывод при этом такой:

          " Overall, the interesting results were obtained by the FEDOT AutoTSF tool. FEDOT obtained a low average forecasting error (around 4.58%), while requiring a reasonable computational effort, around 3 minutes to generate a new TSF model"


    1. niclnno
      31.10.2022 19:40
      +2

      >К примеру можно ли Федота настроить на получение быстрой и компактной модели (в ущерб качеству)? 

      Можно. Есть 2 варианта - или указать пул "легких" моделей, из которых будут строиться пайплпаны; или задать дополнительный критерий оптимизации (время обучения или предсказания, размер модели, etc).

      >Правильно ли я понимаю, что на небольшом наборе данных Федот даст лучший результат, нежели трансформеры?

      Скорее всего да - за счет того что данных для обучения трансформеров просто не хватит.