\[y(t) = g(t) + s(t) + h(t) + \epsilon_t,\]
где \(g(t)\) - функция, аппроксимирующая тренд ряда, \(s(t)\) - функция, аппроксимирующая сезонные колебания (например, годовые, недельные и т.п.), \(h(t)\) - функция, отражающая эффекты праздников и других важных событий, а \(\epsilon_t\) - нормально распределенные случайные возмущения. В такой формулировке эта модель представляет собой частный случай обобщенных аддитивных моделей (Generalized Additive Models, GAM).
Как было отмечено ранее, сезонные компоненты аппроксимируются в Prophet с помощью частичных сумм ряда Фурье, число членов которого (порядок) определяет гладкость соответствующей функции (см., например, аргумент yearly.seasonality функции prophet()). В этом сообщении мы рассмотрим дополнительные способы спецификации сезонных составляющих.
Код для воспроизведения примеров
Все примеры, приведенные в сообщениях из этой серии, можно воспроизвести с помощью кода, который хранится в Github-репозитории ranalytics/intro_to_prophet. Описание используемых в примерах данных представлено в первом сообщении.
Функция add_seasonality()
Если анализируемый временной ряд охватывает как минимум два года, то функция prophet() автоматически добавит в модель компоненты годовой и недельной сезонности. Если гранулярность данных превышает дневную (например, если имеются почасовые наблюдения зависимой переменной), то в модель автоматически будет добавлена также дневная сезонность. Функция add_seasonality() позволяет исследователю добавить и любые другие сезонные составляющие (например, часовую, месячную, квартальную и т.п.). Эта функция имеет следующие аргументы:
- m - модельный объект;
- name - название сезонной состявляющей;
- period - число (необязательно целое), соответствующее количеству дней в одном сезонном цикле;
- fourier.order - порядок (количество членов) ряда Фурье (по умолчанию равен 3 для недельной сезонности и 10 для годовой);
- mode - тип модели; принимает два возможных значения - "additive" (аддитивная; выбирается по умолчанию) и "multiplicative" (мультипликативная);
- condition.name - название сторонней переменной, которая задает разные режимы моделируемой сезонности.
Рассмотрим примеры использования функции add_seasonality() и ее аргументов.
Сезонные компоненты, заданные пользователем
В приведенном ниже коде мы сначала отключаем автоматически добавляемую в модель недельную сезонность и вместо нее добавляем месячную сезонность (исходя из того, что один месячный период составляет 30.5 дней). На рис. 1 представлены все компоненты полученной модели (тренд, годовая сезонность и месячная сезонность).
M10 <- prophet(weekly.seasonality = FALSE) # отключаем недельную сезонность
M10 <- add_seasonality(m = M10, # добавляем месячную сезонность
name = "monthly",
period = 30.5,
fourier.order = 5)
M10 <- fit.prophet(M10, train_df)
forecast_M10 <- predict(M10, future_df)
prophet_plot_components(M10, forecast_M10)
Аналогичным образом вместо месячной сезонной составляющей мы могли бы добавить, например, квартальную (задав длину периода в 365.25/4 дней):
M11 <- prophet(weekly.seasonality = FALSE) # отключаем недельную сезонность
M11 <- add_seasonality(m = M11, # добавляем квартальную сезонность
name = "quarter",
period = 365.25/4,
fourier.order = 2)
M11 <- fit.prophet(M11, train_df)
forecast_M11 <- predict(M11, future_df)
prophet_plot_components(M11, forecast_M11)
Рис. 2 |
Условные режимы сезонности
В ряде случаев функция, аппроксимирующая ту или иную сезонную составляющую, может изменять свои свойства в зависимости от каких-то сторонних факторов. Например, колебания в течение рабочих дней могут иметь характер, сильно отличающийся от такового в выходные дни. Пакет Prophet позволяет моделировать такие условные режимы сезонности (т.е. режимы, которые зависят от сторонних факторов) с помощью аргумента condition.name функции add_seasonality(). Как следует из названия, на этот аргумент подается имя (булевой) переменной, которая определяет соответствующий режим. Такие переменные должны хранится в той же таблице, что и основные данные по временному ряду.
Исключительно в качестве примера предположим, что недельные колебания стоимости биткоина в летние месяцы отличаются от таковых в другие месяцы. Чтобы смоделировать такое различие, добавим в таблицу с данными train_df две новые индикаторные переменные - summer (принимает значение TRUE в летние месяцы и FALSE в другие месяцы) и not_summer (TRUE в нелетние месяцы и FALSE летом). Важно помнить, что такие же переменные нужно добавить и в таблицу с будущими датами future_df - иначе прогнозные значения расчитать не получится:
# Функция для удобного добавления переключателей режимов в данные:
is_summer <- function(ds) {
month <- as.numeric(format(ds, '%m'))
return(month > 5 & month < 9)
}
# Добавляем переключатели в обучающие данные и в таблицу с будущими датами:
train_df$summer <- is_summer(train_df$ds)
train_df$not_summer <- !train_df$summer
future_df$summer <- is_summer(future_df$ds)
future_df$not_summer <- !future_df$summer
# Подгоняем модель:
M12 <- prophet(weekly.seasonality = FALSE) # отключаем автоматическую подгонку
# недельной сезонности
M12 <- add_seasonality(M12, name = 'weekly_summer',
period = 7,
fourier.order = 3,
condition.name = 'summer') # добавляем летний режим
M12 <- add_seasonality(M12, name = "weekly_not_summer",
period = 7,
fourier.order = 3,
condition.name = "not_summer") # добавляем нелетний режим
M12 <- fit.prophet(M12, train_df)
forecast_M12 <- predict(M12, future_df)
prophet_plot_components(M12, forecast_M12)
Согласно полученной модели, в нелетние месяцы стоимость биткоина в течение недели обычно достигает максимума по средам, тогда как в летние месяцы по средам обычно наблюдается противоположная картина.
В Prophet по умолчанию подгоняются аддитивные модели временных рядов. Уравнение для таких моделей было приведено в начале этого сообщения. В мультипликативных моделях, как следует из их названия, сезонная составляющая умножается на тренд (в итоге это приводит к тому, что сезонная составляющая моделируется в виде доли от уровня тренда - см. ниже):
\[y(t) = g(t) \times s(t) + h(t) + \epsilon_t\]
В приведенном уравнении предполагается, что амплитуда всех сезонных составляющих существенно изменяется во времени. Для подгонки соответствующих моделей необходимо воспользоваться аргументом seasonality.mode функции prophet():
Однако в Prophet имеется возможность и более гранулярного контроля над аддитивностью сезонных составляющих. Так, например, можно построить модели, в которых недельная составляющая представлена в аддитивном виде, а годовая - в мультипликативном. Вероятно, вы уже догадались, что для этого применяется функция add_seasonality():
Обратите внимание: на рис. 6 внизу вклад годовой сезонной компоненты представлен в процентах от уровня тренда.
В следующем сообщении мы рассмотрим, как в модель временного ряд можно добавить дополнительные предикторы.
Другие статьи из этой серии:
Регуляризация сезонных составляющих
Подобно тому, как это было с эффектами праздников и других важных событий, мы можем контролировать уровень вклада сезонных составляющих. Глобальный контроль выполняется с помощью аргумента seasonality.prior.scale функции prophet(). Контроль же на уровне отдельных сезонных составляющих возможен с помощью аргумента prior.scale функции add_seasonality(). По умолчанию prior.scale = 10. Уменьшение этого значения приведет к подавлению вклада соответствующего компонента модели.Аддитивная и мультипликативная сезонности
В прогнозировании временных рядов различают два основных вида моделей - аддитивные и мультипликативные. Первый из них применяется в случаях, когда амплитуда сезонных колебаний приблизительно постоянна. Если же эта амплитуда заметно изменяется во времени (обычно возрастает), то строят мультипликативную модель.В Prophet по умолчанию подгоняются аддитивные модели временных рядов. Уравнение для таких моделей было приведено в начале этого сообщения. В мультипликативных моделях, как следует из их названия, сезонная составляющая умножается на тренд (в итоге это приводит к тому, что сезонная составляющая моделируется в виде доли от уровня тренда - см. ниже):
\[y(t) = g(t) \times s(t) + h(t) + \epsilon_t\]
В приведенном уравнении предполагается, что амплитуда всех сезонных составляющих существенно изменяется во времени. Для подгонки соответствующих моделей необходимо воспользоваться аргументом seasonality.mode функции prophet():
M14 <- prophet(train_df, seasonality.mode = "multiplicative")
forecast_M14 <- predict(M14, future_df)
plot(M14, forecast_M14)
Рис. 4 |
M15 <- prophet(yearly.seasonality = FALSE)
M15 <- add_seasonality(M15, name = 'yearly',
period = 365.25,
fourier.order = 10,
mode = "multiplicative")
M15 <- fit.prophet(M15, train_df)
forecast_M15 <- predict(M15, future_df)
prophet_plot_components(M15, forecast_M15)
Рис. 6 |
***
В следующем сообщении мы рассмотрим, как в модель временного ряд можно добавить дополнительные предикторы.
Другие статьи из этой серии:
Отправить комментарий