Улучшение интерпретируемой модели Prophet с помощью глубокого обучения

Привет, хабровчане. В рамках набора учащихся на онлайн-курс "Machine Learning. Advanced" подготовили перевод материала.

Приглашаем всех желающих поучаствовать в открытом демо-уроке «Кластеризация временных рядов»: интереснейшая задача, которую можно прикрутить к временным рядам.
• Можно ли найти похожие друг на друга по динамике финансовые активы на бирже?
• Как сгруппировать пользователей по их поведению?
• Кто подставил кролика Роджера?
Ответы на некоторые из этих вопросов мы получим на онлайн-занятии. Присоединяйтесь!


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

Можете себе представить, насколько я был приятно удивлен, когда недавно наткнулся на новую библиотеку для прогнозирования временных рядов — NeuralProphet. Как вы можете понять из названия библиотеки, это по сути старая добрая Prophet только на стероидах, которыми в данном конкретном случае являются нейронные сети. Учитывая, что в настоящее время я довольно много работаю с временными рядами, я очень хотел проверить, какова она в сравнении с обычной Prophet.

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

NeuralProphet

Чтобы понять, что такое NeuralProphet, я кратко рассмотрю ее составные части и объясню, как все они складываются воедино.

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

Основное преимущество авторегрессионных моделей заключается в том, что они легко интерпретируемы — изучая коэффициенты модели, мы можем увидеть, как прошлый временной шаг влияет на прогноз. Однако за такую ??интерпретируемость приходится платить, поскольку эти параметрические модели могут оказаться слишком жесткими и неспособными учесть какие-либо признаки за пределами автокорреляции. Более того, они не так хорошо масштабируются на наборы данных не только с большим количеством наблюдений, но и с потенциальными признаками.

Источник

Мы можем рассматривать Prophet как расширение базовых авторегрессионных моделей. Вместо того, чтобы просто использовать лаговые значения целевой переменной, модель предоставляет дополнительную форму конструирования признаков — она ??применяет ряд Фурье к входной переменной. Это позволяет нам — аналитикам — дополнительно поднастраивать модель для повышения производительности, а также декомпозировать результаты для лучшей интерпретируемости. Prophet имеет множество других полезных функций, некоторые из которых мы перечислим ниже:

  • Prophet может использовать дополнительные внешние регрессоры — т.е. не только лаговые значения цели

  • модель может учитывать эффект праздников

  • она может автоматически обнаруживать поворотные точки в тенденции — например, когда возрастающая тенденция становится убывающей

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

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

  • настройка гиперпараметров, безусловно, не так проста, как в параметрических моделях

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

Как упоминалось во введении, основными преимуществами использования Prophet являются хорошая производительность, интерпретируемость, а также простота установки и использования. Именно на это авторы NeuralProphet ориентировались в разработке своей библиотеки — сохранить все преимущества Prophet, улучшив при этом его точность и масштабируемость за счет внедрения улучшенного бэкенда (PyTorch вместо Stan) и использования авторегрессионной сети (AR-Net), чтобы объединить масштабируемость нейронных сетей с интерпретируемостью авторегрессионных моделей. Если охарактеризовать AR-Net одним предложением, то это однослойная сеть, которая обучена имитировать авторегрессионный процесс в сигнале временного ряда, но в гораздо большем масштабе, чем традиционные модели.

NeuralProphet против Prophet

Кратко описав, что такое NeuralProphet, я хотел бы сосредоточиться на различиях между двумя библиотеками. Если опираться на документацию, то основные отличия заключаются в следующем:

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

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

  • Лаговые регрессоры моделируются с использованием отдельной нейронной сети прямого распространения.

  • Кроме того, модель имеет настраиваемые нелинейные глубокие слои сетевых сетей прямого распространения

  • Модель настраивается на определенные горизонты прогноза (больше 1).

  • Она предлагает настраиваемые потери и метрики.

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

Установка

На момент написания, лучший способ установить NeuralProphet — это клонировать репозиторий и установить ее прямо оттуда, запустив pip install. в каталоге. Самую актуальную информацию о процедуре установки см. в этой части инструкции.

Установив библиотеки, импортируем их в Python.

import pandas as pd
from fbprophet import Prophet
from neuralprophet import NeuralProphet
from sklearn.metrics import mean_squared_error

# plotting
import matplotlib.pyplot as plt

# settings
plt.style.use('seaborn')
plt.rcParams["figure.figsize"] = (16, 8)

neural_prophet_1.py hosted with ? by GitHub

Подготовка данных

В этом примере мы будем работать с набором данных Peyton Manning (звезда НФЛ). Если вы не американец, вам, вероятно, придется заглянуть в статью в Википедии, чтобы понять шутку в документации к Prophet. Но вернемся к нашей теме — набор данных содержит лог ежедневных  просмотров его странички в Википедии.

Набор данных был собран командой Facebook, чтобы показать, как работает Prophet, и доступен для использования как в Prophet, так и в NeuralProphet.

Мы загружаем данные, выполнив следующую строку:

# loading the dataset
df = pd.read_csv('../neural_prophet/example_data/wp_log_peyton_manning.csv')
print(f'The dataset contains {len(df)} observations.')
df.head()

neural_prophet_2.py hosted with ? by GitHub

Для тех, кто раньше не работал с Prophet, для запуска модели нам нужны два столбца с соответствующими именами: ds — столбец даты/таймстемпа, а y — переменная, которую мы хотим прогнозировать. Учитывая, что это учебный набор данных, он уже подготовлен.

Затем мы выводим данные на график, чтобы иметь возможность сделать некоторый базовые предположения. Учитывая взлеты и падения, я могу предположить, что рост популярности коррелирует с сезонами НФЛ. Пожалуйста, поправьте меня, если я ошибаюсь.

df.plot(x='ds', y='y', title='Log daily page views');
# getting the train/test split
test_length = 365
df_train = df.iloc[:-test_length]
df_test = df.iloc[-test_length:]

neural_prophet_3.py hosted with ? by GitHub

Prophet

Как уже упоминалось, Prophet упрощает конечным пользователям получение прогнозов. Мы уложились в 4 строчки кода. Мы можем кратко их рассмотреть. Сначала мы создаем экземпляр модели, используя настройки по умолчанию. Затем мы обучаем модель, используя обучающие данные. Чтобы получить прогнозы, нам нужно создать так называемый «future dataframe». Мы указываем количество дней, на которое мы хотим сделать прогноз. По умолчанию метод также включает исторические данные. Таким образом, мы получим подобранные величины (прогнозы с использованием данных из обучающей выборки). Наконец, мы получаем прогнозы и сохраняем их в preds_df_1.

prophet_model = Prophet()
prophet_model.fit(df_train)
future_df = prophet_model.make_future_dataframe(periods=test_length)
preds_df_1 = prophet_model.predict(future_df)

neural_prophet_4.py hosted with ? by GitHub

Обучив модель, мы сопоставляем прогнозы и фактические наблюдения (только из обучающего набора).

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

В качестве последнего шага мы отражаем на графике извлеченные компоненты. Этот процесс аналогичен стандартной декомпозиции временных рядов.

prophet_model.plot_components(preds_df_1);

Мы можем наблюдать на графике тенденцию на протяжении многих лет вместе с недельной и годовой составляющими.

NeuralProphet

К счастью, API NeuralProphet практически идентичен оригинальному Prophet. Таким образом, уже зная, что мы делали в предыдущем примере, нам будет очень легко применить NeuralProphet к задаче прогнозирования временных рядов.

nprophet_model = NeuralProphet()
metrics = nprophet_model.fit(df_train, freq="D")
future_df = nprophet_model.make_future_dataframe(df_train, 
                                                 periods = test_length, 
                                                 n_historic_predictions=len(df_train))
preds_df_2 = nprophet_model.predict(future_df)

neural_prophet_5.py hosted with ? by GitHub

Естественно, мы используем другой класс для инстанцирования экземпляра модели. Другие отличия заключаются в явном указании частоты данных при обучении модели (исходный Prophet был в первую очередь предназначен для ежедневных данных) и упоминании длины исторической выборки, которую мы хотим включить в «future dataframe». Чтобы примеры были как можно более похожими, мы включаем все исторические данные.

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

nprophet_model.plot(preds_df_2);

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

nprophet_model.plot_components(preds_df_2, residuals=True);

Мы также можем отразить на графике параметры модели, запустив.

nprophet_model.plot_parameters();

Мы включили сюда только два графика, так как оставшиеся два перекрываются с графиками, полученными с помощью plot_components (еженедельная и годовая сезонность).

Сравнение показателей

Наконец, мы сравниваем производительность моделей. Для этого мы помещаем все прогнозы в тестовый DataFrame, наносим на график результаты и вычисляем среднеквадратичную ошибку (MSE).

# prepping the DataFrame
df_test['prophet'] = preds_df_1.iloc[-test_length:].loc[:, 'yhat']
df_test['neural_prophet'] = preds_df_2.iloc[-test_length:].loc[:, 'yhat1']
df_test.set_index('ds', inplace=True)

print('MSE comparison ----')
print(f"Prophet:\t{mean_squared_error(df_test['y'], preds_df_1.iloc[-test_length:]['yhat']):.4f}")
print(f"NeuralProphet:\t{mean_squared_error(df_test['y'], preds_df_2.iloc[-test_length:]['yhat1']):.4f}")

df_test.plot(title='Forecast evaluation');

neural_prophet_6.py hosted with ? by GitHub

Запуск этого кода создаст следующий график.

Хотя может быть трудно однозначно сказать, какие прогнозы ближе к фактическим, расчет MSE ясно показывает победителя — NeuralProphet.

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

Выводы

NeuralProphet — очень молодая библиотека (все еще на стадии бета-тестирования), но у нее уже есть большой потенциал. Это можно понять, посмотрев хотя бы на участников и их предыдущий опыт. Авторы успешно улучшили исходную библиотеку Prophet, дополнительно улучшив точность модели и ее масштабируемость, сохранив при этом простоту использования и, самое главное, интерпретируемость.

Лично я бы не советовал всем отказываться пока от Prophet в пользу NeuralProphet, в основном потому, что библиотека все еще молода и постоянно развивается, что может быть не лучшим фактором для использования в производственной среде. Тем не менее, я однозначно рекомендую следить за ее развитием!

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

Ссылки:


Узнать подробнее о курсе "Machine Learning. Advanced"

Смотреть вебинар «Кластеризация временных рядов»