Amazon GluonTS: Deep Learning для временных рядов | OTUS

Amazon GluonTS: Deep Learning для временных рядов

DLE_Deep_28.10-5020-fe61f5.png

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

До этого момента одним из самых известных релизов открытой библиотеки для работы с временными рядами был Facebook Prophet, выпущенный в феврале 2017 года. В отличие от GluonTS, Facebook использовал более простой метод — аддитивную нелинейную модель временного ряда. Эта модель давала вполне адекватные результаты при минимуме затраченных усилий, однако не очень хорошо справлялась с данными, где отсутствовала ярко выраженная сезонность.

Что внутри GluonTS?

Amazon пошёл дальше и использовал рекуррентные нейронные сети (в частности, LSTM), а также свёртки и механизмы внимания, обернув всё это в крайне удобную верхнеуровневую библиотеку. В частности, GluonTS содержит: — инструменты, необходимые для построения и обучения наиболее распространённых архитектур нейронных сетей, а также компоненты для моделирования и трансформации вероятностных распределений; — механизмы для загрузки и предварительной обработки данных, в том числе автоматической генерации признаков из временных рядов; — несколько готовых к использованию state-of-the-art прогнозных моделей; — инструменты для оценки и сравнения различных моделей.

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

Пример на реальных данных

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

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

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('currency.csv', index_col=0)
df.index = pd.to_datetime(df.index)

df[:100].plot(linewidth=2, figsize=(17, 7))
plt.grid(axis='x')
plt.legend()
plt.show()

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

Попробуем построить модель. GluonTS предоставляет верхнеуровневую абстрацию Dataset, которая переводит разнородные форматы данных в один, удобный для последующей работы моделей. В частности, ListDataset переводит данные в список словарей, где отдельно записаны значения ряда и таймстэмпы. Для создания такого датасета мы передаём наш исходный временной ряд, указываем его частоту (в данном случае у нас дневные данные, поэтому частота "D"), а также точку, до которой наш ряд будет отнесён к тренировочной выборке:

from gluonts.dataset.common import ListDataset
training_data = ListDataset(
    [{"start": df.index[0], "target": df.currency_spent[:"2017-08-01"]}],
    freq = "D"
)

Посмотрим, в какой формат преобразовались данные:

training_data.list_data

[Out:] [{'start': Timestamp('2017-05-01 00:00:00', freq='D'),
  'target': array([1199436., 1045515.,  586111.,  856601.,  793775.,  606535.,
         1112763., 1121218.,  813844.,  903343.,  863465.,  639224.,
         1030389., 1132645., 1018672., 1726870., 1378430.,  532950.,
          828238.,  823948.,  592549.,  939337.,  862611.,  551557.,
          878375.,  784535.,  613603., 1054658., 1026401.,  682284.,
          986644.,  924769.,  633489., 1044957., 1088685.,  798582.,
         1139786., 1066560.,  754706., 1199406., 1186341.,  958210.,
         1564553., 1470865., 1201275., 2418723., 2123070.,  978338.,
         1536623., 1420586.,  966259., 1232735., 1090762.,  763828.,
         1153383., 1074039.,  733943., 1103070., 1123779.,  752524.,
         1123866., 1051964.,  756827., 1109486., 1059961.,  691291.,
          985221.,  932805.,  641340., 1038572., 1037868.,  732303.,
          962492.,  875898., 1029902., 1917268., 1662445.,  791812.,
         1061339.,  968767.,  685321., 1020324.,  995864.,  785353.,
         1192613., 1068292.,  710820., 1048429.,  991163.,  701672.,
         1239717., 1261953.,  857930.], dtype=float32),
  'source': SourceContext(source='list_data', row=1)}]

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

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

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

from gluonts.model.deepar import DeepAREstimator
from gluonts.trainer import Trainer

estimator = DeepAREstimator(
    freq="D", 
    prediction_length=30, 
    trainer=Trainer(epochs=20)
)
predictor = estimator.train(training_data=training_data)

После непродолжительной тренировки модель готова и можно смотреть на прогноз. Снова создадим ListDataset, на сей раз для отложенной выборки, и воспользуемся удобной утилитой to_pandas, чтобы перевести результаты прогноза в удобный для визуализации формат:

from gluonts.dataset.util import to_pandas

test_data = ListDataset(
    [{"start": df.index[0], "target": df.currency_spent[:"2017-08-01"]}],
    freq = "D"
)

for test_entry, forecast in zip(test_data, predictor.predict(test_data)):
    to_pandas(test_entry).plot(linewidth=2, figsize=(15, 7), label="historical values")
    forecast.plot(color='g', prediction_intervals=[50.0, 90.0], label="forecast")

plt.legend(loc='upper left')
plt.grid(axis='x')

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

Вывод

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

Подробнее о настройке гиперпараметров и сравнении качества GluonTS с другими методами прогнозирования временных рядов вы сможете узнать на занятии «Анализ временных рядов» курса «Machine Learning».

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться
Популярное
Сегодня тут пусто