Введение
В данной статье буду рассматривать модель экспоненциального сглаживания временного ряда. Эта модель является одной из самых распространенных моделей для прогнозирования значений временного ряда не содержащего трендов и сезонности. В статье будет рассмотрена теоретическая часть, практика, а также реализация этой модели на одном из языков программирования.
Теоретическая часть.
Экспоненциальное сглаживание один из распространенных приемов выравнивания временного ряда. Данный прием основан на расчете экспоненциальных средних, и является простейшей адаптивной моделью.
Модель вычисляется рекурентной формулой:
$$S_t = \alpha x_t + \beta S_{t-1}$$
где
$S_t$ - значение экспоненциальной средней в момент t
$\alpha$ - параметр сглаживания
$\beta = 1 - \alpha$
Исходя из вышеописанного можно переписать $S_t$, следующим образом:
$$S_t = S_{t-1} + \alpha (x_t - S_{t-1})$$
После рекурсивного применения формулы для $S_t$, её можно выразаить через значения временного ряда $x$:
$$S_t = \alpha \sum_{i=0}^{N-1}\beta^{i} x_{t-i} + \beta^{N} S_0$$
где:
$N$ - кол-во членов ряда
$S_0$ - некоторая величина, характерезующая начальные условия, первого применения формулы.
По сути $S_t$ является средневзвешанной суммой всех членов ряда и соответственно чем старше компонента, т.е. находится ближе к началу ряда, тем меньший вес будет иметь она. Кроме того слагаемое $x_t - S_{t-1}$ по сути является погрешностью прогноза, соответственно каждое последующее значение и является корректировкой предыдущего.
Поэтому рекурентная для прогнозирования:
$$S_{t+d} = \alpha x_t + (1 - \alpha)\widehat{x_t}$$,
где
$x_t$ - фактическое значение на момент $t$,
$\widehat{x_t}$ - прогнозное значение на момент $t$,
Надо пояснить, что для применения данного сглаживание всегда необходимо иметь какое-то значение $S_0$, для расчета первого сглаженного значения, и в большинстве случаев это может быть обычная срденяя N-го количества начальных элементов.
Важным моментом в поиске наилучшей модели является подбор коэффициента $\alpha$. Как показывает практика данный коэффициент зависит от срока на который требуется получить прогноз. Для небольшого срока $\alpha$ должен быть ближе к 1, т. к. таким образом последним элементам последовательности будет придаваться больший вес. Для получения среднесрочных прогнозов начальные элементы последовательности должны иметь больший вес и, соответственно, $\alpha$ должен быть ближе 0.
Однако необходимо помнить что, чем $\alpha$ ближе к 1, тем более вероятно что временной ряд имеет тренд(тенденцию) или сезонные колебания, а при таких условиях от модели экспоненциального сглаживая будет сложно ждать хороших результатов и надо будет подобрать более подходящую модель.
Также не мало важно знать как реагирует модель на типичные нарушения стационарности типа импульсов или сутпенчатого изменения. Импульс - это однократное событие вызванное внешним факторам. Например яркий пример имульса это нелицеприятный ответ Элона Маска анлитикам, на предмет анализа отчетночти Tesla Motors, когда акции одномоментно просели на 5%. Ступенчатые изменения - долговременное изменение структуры ряда. Например изменение уровня производства из-за появления какой-либо технологии.
Из описания импульсов и ступенчатых изменений следует, что хорошая модель должна хорошо сглаживать импульсы и быстро реагировать на изменения. Из выше описанного можно сделать вывод для адекватной реакции на импульсы первые члены последовательности должны иметь вес выше последних, а для это лучше использовать малое значение коэффициента сглаживания $\alpha$. Для сглаживаний ступенчатых изменений наборот большее $\alpha$ предпочтительнее, так как больший вес должны иметь последние элементы
При этом необхлдимо еще раз отметить, что если ряд имеет тенденцую роста (линейную или праболическую) от данной модели нельзя ожидать хороших прогнозов и лучше использовать другую модель.
Практика.
Для практической иллюстрации применения данной модели будет использоваться цена закрытия Bitcoin за последние 2 месяца (01.03.2018-13.05.2018).
В качестве значения $S_0$ будет использоваться среднее арифметическое первых 10 членов последовательности (с 01.03.2018 по 10.03.2018)
$S_0 = \frac{10951,00+11086,40+11489,70+11512,60+11573,30+10779,90+9965,57+9395,01+9337,55+8866,00}{10} = 10495,7$
На основе фактических данных эмпирическим путем был подобран коэффициент $\alpha = 0,43$
На основе полученной информации получился следующий прогноз:
Дата | Цена | Прогноз |
---|---|---|
01.03.2018 | 10 951,00 | 10 495,70 |
02.03.2018 | 11 086,40 | 10 691,48 |
03.03.2018 | 11 489,70 | 10 861,30 |
04.03.2018 | 11 512,60 | 11 131,51 |
05.03.2018 | 11 573,30 | 11 295,38 |
06.03.2018 | 10 779,90 | 11 414,88 |
… | … | … |
08.05.2018 | 9 234,82 | 9 552,29 |
09.05.2018 | 9 325,18 | 9 415,78 |
10.05.2018 | 9 043,94 | 9 376,82 |
11.05.2018 | 8 441,49 | 9 233,68 |
12.05.2018 | 8 504,89 | 8 893,04 |
13.05.2018 | 8 726,14 |
Реализация на С++
Реализация функции данной модели выглядит следующим образом:
const float ErrIncorrectAlpha = -1.0;
/*
Реализация молели экспоненциального сглаживания.
@param[in] time_series Временной ряд.
@param[in] alpha Коэффициент сглаживания между 0 и 1.
@param[in] s0 инициализированное первое значение S.
@return Прогнозное значение.
*/
float exponential_smoothing(std::list<float> time_series, float alpha, float s0) {
if (alpha > 1 || alpha < 0) {
// если параметр alpha задан не корректно, возвращается ошибка
return ErrIncorrectAlpha;
}
float predict_value = s0;
float fact_value;
for(std::list<float>::iterator r = time_series.begin(); r != time_series.end(); r++){
fact_value = *r;
predict_value = alpha * fact_value + (1 - alpha) * predict_value;
}
return predict_value;
}
На вход данная функция принимает временной ряд, начальное значение $S_0$, и параметр $\alpha$. На выходе она выведет следующее прогноное значение.
Код тестовой программы:
#include <iostream>
#include <list>
const float ErrIncorrectAlpha = -1.0;
/*
Реализация молели экспоненциального сглаживания.
@param[in] time_series Временной ряд.
@param[in] alpha Коэффициент сглаживания между 0 и 1.
@param[in] s0 инициализированное первое значение S.
@return Прогнозное значение.
*/
float exponential_smoothing(std::list<float> time_series, float alpha, float s0) {
if (alpha > 1 || alpha < 0) {
// если параметр alpha задан не корректно, возвращается ошибка
return ErrIncorrectAlpha;
}
float predict_value = s0;
float fact_value;
for(std::list<float>::iterator r = time_series.begin(); r != time_series.end(); r++){
fact_value = *r;
predict_value = alpha * fact_value + (1 - alpha) * predict_value;
}
return predict_value;
}
int main()
{
// тестовые значения
std::list<float> ts = {9325.18, 9043.94, 8441.49, 8504.89};
float predict_value;
// строим модель с alpha=0.43 и s0 = 9552.29
predict_value = exponential_smoothing(ts, 0.43, 9552.29);
if (predict_value == ErrIncorrectAlpha) {
std::cout << "Alpha must be between 0 and 1" << std::endl;
} else {
std::cout << "Predict value: " << predict_value << std::endl;
}
return 0;
}
Вывод
Была построена и разобрана адаптивная модель экспоненциального сглаживания для прогнозирования цены Bitcoin. В итоге средняя ошибка прогноза получившийся модели находится в районе 4% что является хорошим результатом.
В последующих статьях я буду рассматривать другие адаптивные модели для рядов с трендом и сезонностью.
Ссылки
- Экспоненциальное сглаживание
- Лукашин Ю. П. - Адаптивные методы краткосрочного прогнозирования временных рядов.
- Bitcoin - CoinMarketCap
- Gist Exponential smoothing