Сезонность — это регулярно повторяющиеся паттерны в данных, которые происходят с фиксированной периодичностью. Работая с разнообразными временными рядами, я неоднократно наблюдал эти циклические колебания в самых разных областях: от розничных продаж и туристических потоков до энергопотребления и финансовых показателей.
Природа и причины сезонности
Сезонные колебания возникают по множеству причин, часто связанных с естественными циклами или устоявшимися социальными практиками:
- Природные циклы — изменения температуры, осадков и других метеорологических показателей в течение года влияют на сельское хозяйство, энергетику, строительство и многие другие сферы.
- Административные периоды — финансовый год, налоговые периоды, квартальная отчетность создают регулярные всплески или падения в бизнес-показателях.
- Социокультурные факторы — праздники, отпускные периоды, учебные семестры вызывают предсказуемые колебания в потребительском поведении и экономической активности.
- Технологические особенности — производственные циклы, плановые техобслуживания, регулярные обновления систем также могут создавать сезонные паттерны.
В своей аналитической практике я обнаружил, что понимание первопричин сезонности значительно помогает в выборе правильного подхода к моделированию. Особенно это важно при работе с комплексными данными, где могут одновременно присутствовать несколько сезонных паттернов с разными периодами.
Типы сезонности по периодичности
Анализируя временные ряды, важно различать разные типы сезонности:
Годовая сезонность наблюдается практически во всех отраслях экономики. В розничной торговле, например, продажи зимней одежды предсказуемо растут с наступлением холодов, а продажи кондиционеров — с приходом летней жары. Работая с многолетними данными, я всегда начинаю с поиска именно этого типа сезонности.
Квартальная сезонность часто связана с деловой отчетностью и бюджетными циклами. Бизнес-показатели многих компаний демонстрируют устойчивые паттерны, повторяющиеся каждый квартал.
Месячная сезонность может быть связана с регулярными выплатами зарплат, кредитов или абонентских платежей. Например, в банковской сфере я наблюдал четкие ежемесячные пики транзакционной активности в определенные дни месяца.
Недельная сезонность отражает различия между рабочими и выходными днями. Анализируя данные интернет-трафика или посещаемости розничных магазинов, всегда обнаруживаю еженедельные циклы активности.
Суточная сезонность проявляется в течение 24 часов и наиболее заметна в энергопотреблении, телекоммуникациях и транспортных потоках. Утренние и вечерние пики часто формируют характерный профиль, повторяющийся изо дня в день.
Многоуровневая сезонность — это комбинация нескольких сезонных паттернов с разной периодичностью. Например, потребление электроэнергии демонстрирует одновременно суточные, недельные и годовые сезонные колебания. Это один из самых сложных случаев для моделирования, требующий продвинутых техник декомпозиции.
Декомпозиция временных рядов: основные компоненты
Для эффективного анализа и прогнозирования временные ряды обычно разделяют на несколько ключевых компонентов. Этот подход позволяет лучше понять структуру данных и выбрать оптимальную модель для работы с ними.
Тренд, сезонность и остаточный компонент
В классической декомпозиции временной ряд представляется как комбинация трех основных компонентов:
- Тренд (T) — долгосрочная тенденция в данных, отражающая общее направление развития процесса. Тренд может быть восходящим, нисходящим или стационарным. В своей практике я часто использую методы сглаживания, такие как скользящие средние или экспоненциальное сглаживание, для выделения этого компонента.
- Сезонный компонент (S) — регулярно повторяющиеся колебания с фиксированным, известным периодом. Как уже обсуждалось выше, сезонность может быть годовой, квартальной, месячной и т.д.
- Остаточный компонент или шум (R) — нерегулярные, случайные колебания, остающиеся после выделения тренда и сезонности. Хотя этот компонент часто рассматривается как шум, в некоторых случаях он может содержать важные паттерны, не уловленные моделью.
Дополнительно, в некоторых моделях выделяют циклический компонент (C) — колебания без фиксированной периодичности, связанные, например, с экономическими циклами. В отличие от сезонности, длительность и амплитуда циклов может существенно варьироваться, что усложняет их моделирование.
Способы выделения компонентов
Существует несколько подходов к декомпозиции временных рядов:
- Классическая декомпозиция использует скользящие средние для выделения тренда. После вычитания (для аддитивной модели) или деления (для мультипликативной модели) исходного ряда на тренд, получают сезонные и нерегулярные компоненты.
- STL (Seasonal-Trend decomposition using LOESS) — более гибкий метод, основанный на локально взвешенной регрессии. Он позволяет работать с нелинейными трендами и меняющимися со временем сезонными компонентами.
- Метод сезонной декомпозиции X-12-ARIMA особенно эффективен для экономических данных и учитывает календарные эффекты.
В своих исследованиях я часто применяю вейвлет-преобразования для декомпозиции временных рядов со сложной структурой. Этот метод хорошо справляется с выделением компонентов разной частоты и особенно полезен при работе с нестационарными рядами.
Вот пример декомпозиции временного ряда на Python с использованием библиотеки statsmodels:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose
# Создаем временной ряд с ежемесячными данными за 5 лет
np.random.seed(42)
dates = pd.date_range('2018-01-01', periods=60, freq='M')
trend = np.linspace(10, 30, 60) # Линейный растущий тренд
# Создаем сезонный компонент с годовым циклом
period = 12
seasonal = [5 * np.sin(2 * np.pi * i / period) for i in range(60)]
# Добавляем случайный шум
noise = np.random.normal(0, 1, 60)
# Создаем временной ряд (аддитивная модель)
additive_ts = trend + seasonal + noise
df_additive = pd.DataFrame({'value': additive_ts}, index=dates)
# Создаем временной ряд (мультипликативная модель)
# Для мультипликативной модели преобразуем сезонный компонент
seasonal_factor = [1 + 0.2 * np.sin(2 * np.pi * i / period) for i in range(60)]
multiplicative_ts = trend * np.array(seasonal_factor) + noise
df_multiplicative = pd.DataFrame({'value': multiplicative_ts}, index=dates)
# Декомпозиция аддитивной модели
result_additive = seasonal_decompose(df_additive, model='additive', period=period)
# Декомпозиция мультипликативной модели
result_multiplicative = seasonal_decompose(df_multiplicative, model='multiplicative', period=period)
# Визуализация результатов
plt.figure(figsize=(14, 10))
# Аддитивная модель
plt.subplot(2, 1, 1)
plt.suptitle('Декомпозиция временных рядов', fontsize=16)
plt.title('Аддитивная модель', fontsize=14)
plt.plot(df_additive, label='Исходный ряд')
plt.plot(result_additive.trend, label='Тренд')
plt.plot(result_additive.seasonal, label='Сезонность')
plt.plot(result_additive.resid, label='Остаток')
plt.legend()
# Мультипликативная модель
plt.subplot(2, 1, 2)
plt.title('Мультипликативная модель', fontsize=14)
plt.plot(df_multiplicative, label='Исходный ряд')
plt.plot(result_multiplicative.trend, label='Тренд')
plt.plot(result_multiplicative.seasonal, label='Сезонность')
plt.plot(result_multiplicative.resid, label='Остаток')
plt.legend()
plt.tight_layout()
plt.show()
Рис. 1: Сравнение аддитивной и мультипликативной сезонной декомпозиции ряда
Этот код создает два искусственных временных ряда — с аддитивной и мультипликативной структурой — и проводит их декомпозицию. Визуализация результатов наглядно демонстрирует различия между двумя моделями, о которых поговорим подробнее в следующих разделах.
Аддитивная модель сезонности: сущность и применение
Аддитивная модель — это один из фундаментальных подходов к представлению временных рядов с сезонностью. Ее глубокое понимание необходимо для правильного выбора аналитических инструментов.
Математическое представление аддитивной модели
В аддитивной модели временной ряд представляется как сумма его компонентов:
Y(t) = T(t) + S(t) + R(t)
где:
- Y(t) — значение временного ряда в момент времени t
- T(t) — значение тренда
- S(t) — сезонный компонент
- R(t) — остаточный компонент (шум)
Ключевая особенность этой модели заключается в том, что сезонные колебания имеют примерно одинаковую амплитуду независимо от уровня тренда. Другими словами, абсолютная величина сезонных колебаний остается постоянной во времени.
Когда применять аддитивную модель
На основе моего опыта работы с временными рядами могу сказать, что аддитивная модель наиболее подходит в следующих случаях:
- Постоянная амплитуда сезонных колебаний — когда размах сезонных колебаний не зависит от общего уровня ряда. Например, если объем продаж сезонного товара увеличивается каждый год на примерно одинаковое абсолютное значение.
- Относительно стабильная дисперсия — когда разброс значений вокруг тренда примерно одинаков на всем протяжении временного ряда.
- Работа с данными, которые могут принимать отрицательные значения — поскольку аддитивная модель допускает отрицательные значения как для исходного ряда, так и для его компонентов.
- Линейные зависимости между компонентами — когда эффекты различных факторов просто суммируются без взаимного усиления.
Преимущества и недостатки аддитивной модели
В процессе разработки аналитических решений я определил несколько ключевых преимуществ аддитивной модели:
Преимущества:
- Интуитивная интерпретация — компоненты выражены в тех же единицах, что и исходный ряд;
- Простота вычислений и реализации;
- Хорошая работа с линейными трендами;
- Устойчивость к выбросам (по сравнению с мультипликативной моделью);
- Возможность работы с отрицательными значениями.
Недостатки:
- Неадекватность для рядов с изменяющейся амплитудой сезонных колебаний;
- Ограниченная способность моделировать экспоненциальный рост;
- Сложности при работе с гетероскедастичными данными (когда дисперсия меняется со временем).
Практический пример аддитивной модели
Рассмотрим пример реализации аддитивной декомпозиции и прогнозирования с использованием Python:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.holtwinters import ExponentialSmoothing
from sklearn.metrics import mean_absolute_percentage_error, mean_squared_error
# Загрузка демонстрационных данных о пассажиропотоке авиалиний
from statsmodels.datasets import get_rdataset
airline = get_rdataset('AirPassengers').data
if 'value' in airline.columns:
airline = airline[['value']] # Оставляем только нужный столбец
airline.columns = ['Passengers']
# Устанавливаем индекс как временной ряд
airline.index = pd.date_range(start='1949-01-01', periods=len(airline), freq='ME')
# Визуальный анализ исходных данных
plt.figure(figsize=(12, 6))
plt.plot(airline)
plt.title('Количество пассажиров авиалиний (1949-1960)')
plt.xlabel('Дата')
plt.ylabel('Количество пассажиров (тыс.)')
plt.grid(True)
plt.show()
# Логарифмируем данные для приближения к аддитивной модели
airline_log = np.log(airline)
# Декомпозиция временного ряда
decomposition = seasonal_decompose(airline_log, model='additive', period=12)
# Визуализация компонентов
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(12, 10))
decomposition.observed.plot(ax=ax1)
ax1.set_title('Логарифмированный ряд')
ax1.set_ylabel('log(Пассажиры)')
decomposition.trend.plot(ax=ax2)
ax2.set_title('Тренд')
ax2.set_ylabel('log(Пассажиры)')
decomposition.seasonal.plot(ax=ax3)
ax3.set_title('Сезонность')
ax3.set_ylabel('log(Пассажиры)')
decomposition.resid.plot(ax=ax4)
ax4.set_title('Остатки')
ax4.set_ylabel('log(Пассажиры)')
plt.tight_layout()
plt.show()
# Прогнозирование с использованием модели Хольта-Винтерса (аддитивная сезонность)
# Разделим данные на обучающую и тестовую выборки
train = airline_log.iloc[:-12]
test = airline_log.iloc[-12:]
# Создаем и обучаем модель
model = ExponentialSmoothing(
train,
seasonal_periods=12,
trend='add',
seasonal='add'
)
model_fit = model.fit()
# Делаем прогноз на 12 месяцев вперед
forecast = model_fit.forecast(12)
# Преобразуем обратно из логарифмической шкалы
forecast_actual = np.exp(forecast)
train_actual = np.exp(train)
test_actual = np.exp(test)
# Визуализация результатов
plt.figure(figsize=(12, 6))
plt.plot(train_actual.index, train_actual, label='Обучающие данные')
plt.plot(test_actual.index, test_actual, label='Тестовые данные')
plt.plot(test_actual.index, forecast_actual, label='Прогноз')
plt.title('Прогнозирование пассажиропотока с аддитивной моделью сезонности')
plt.xlabel('Дата')
plt.ylabel('Количество пассажиров (тыс.)')
plt.legend()
plt.grid(True)
plt.show()
# Оценка качества прогноза
mape = mean_absolute_percentage_error(test_actual, forecast_actual)
rmse = np.sqrt(mean_squared_error(test_actual, forecast_actual))
print(f'MAPE: {mape:.2%}')
print(f'RMSE: {rmse:.2f}')
Рис. 2: Анализируемый временной ряд — Количество пассажиров авиалиний по месяцам
Рис. 3: Декомпозиция временного ряда: логарифмирование, тренд, сезонность и остатки
Рис. 4: Прогнозирование пассажиропотока с аддитивной моделью сезонности
MAPE: 5.08%
RMSE: 28.68
В этом примере мы сначала логарифмируем данные, чтобы привести мультипликативную структуру к аддитивной, затем проводим декомпозицию и строим прогноз с помощью модели Хольта-Винтерса с аддитивной сезонностью. Обратите внимание насколько малы ошибки в прогнозировании: RMSE, MAPE. Последний составляет 5.08%, что означает что наша модель ошиблась лишь в 5% случаев.
Разумеется, это довольно простенький временной ряд, и чаще приходится иметь дело с куда более сложными. Тем не менее, такое преобразование часто используется в практике анализа временных рядов и демонстрирует гибкость подходов к моделированию.
Мультипликативная модель сезонности: особенности и применение
Мультипликативная модель представляет собой альтернативный подход к декомпозиции временных рядов, который особенно эффективен для определенных типов данных. Разберем подробно ее структуру и области применения.
Математическое представление мультипликативной модели
В мультипликативной модели временной ряд представляется как произведение его компонентов:
Y(t) = T(t) × S(t) × R(t)
где:
- Y(t) — значение временного ряда в момент времени t
- T(t) — значение тренда
- S(t) — сезонный компонент
- R(t) — остаточный компонент (шум)
Фундаментальное отличие этой модели от аддитивной заключается в том, что сезонные колебания пропорциональны уровню тренда. То есть, амплитуда сезонных колебаний увеличивается или уменьшается вместе с ростом или падением тренда.
Когда применять мультипликативную модель
В своей аналитической практике я выделил следующие ситуации, когда мультипликативная модель является предпочтительным выбором:
- Изменяющаяся амплитуда сезонных колебаний — когда размах сезонных колебаний растет или уменьшается пропорционально общему уровню ряда. Например, если розничные продажи не только растут в абсолютном выражении, но и сезонные пики становятся все более выраженными.
- Растущая или уменьшающаяся дисперсия — когда разброс значений вокруг тренда увеличивается с ростом уровня ряда.
- Только положительные значения — поскольку мультипликативная модель основана на умножении, она не подходит для данных, которые могут принимать отрицательные или нулевые значения.
- Экспоненциальный рост — когда данные демонстрируют нелинейный, экспоненциальный рост или спад.
- Процентные изменения — когда сезонные эффекты удобнее интерпретировать как процентные отклонения от тренда.
Преимущества и недостатки мультипликативной модели
На основе опыта работы с различными типами временных рядов, могу выделить следующие преимущества и ограничения мультипликативной модели:
Преимущества:
- Естественное представление для данных с экспоненциальным ростом;
- Хорошая работа с изменяющейся амплитудой сезонных колебаний;
- Сезонные компоненты интерпретируются как относительные (процентные) отклонения;
- Часто лучше соответствует реальным экономическим и бизнес-процессам с растущим масштабом.
Недостатки:
- Невозможность работы с отрицательными или нулевыми значениями;
- Большая чувствительность к выбросам и аномалиям;
- Более сложная интерпретация компонентов;
- Сложности при наличии структурных изменений в данных.
Практический пример мультипликативной модели
Рассмотрим пример реализации мультипликативной декомпозиции и прогнозирования с использованием Python:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.holtwinters import ExponentialSmoothing
from sklearn.metrics import mean_absolute_percentage_error, mean_squared_error
# Загрузка демонстрационных данных о пассажиропотоке авиалиний
from statsmodels.datasets import get_rdataset
airline = get_rdataset('AirPassengers').data
if 'value' in airline.columns:
airline = airline[['value']] # Оставляем только нужный столбец
airline.columns = ['Passengers']
# Устанавливаем индекс как временной ряд
airline.index = pd.date_range(start='1949-01-01', periods=len(airline), freq='ME')
# Декомпозиция с использованием мультипликативной модели
decomposition = seasonal_decompose(airline, model='multiplicative', period=12)
# Визуализация компонентов
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(12, 10))
decomposition.observed.plot(ax=ax1)
ax1.set_title('Исходный ряд')
ax1.set_ylabel('Пассажиры (тыс.)')
decomposition.trend.plot(ax=ax2)
ax2.set_title('Тренд')
ax2.set_ylabel('Пассажиры (тыс.)')
decomposition.seasonal.plot(ax=ax3)
ax3.set_title('Сезонность')
ax3.set_ylabel('Сезонный фактор')
decomposition.resid.plot(ax=ax4)
ax4.set_title('Остатки')
ax4.set_ylabel('Случайный фактор')
plt.tight_layout()
plt.show()
# Прогнозирование с использованием модели Хольта-Винтерса (мультипликативная сезонность)
# Разделим данные на обучающую и тестовую выборки
train = airline.iloc[:-12]
test = airline.iloc[-12:]
# Создаем и обучаем модель
model = ExponentialSmoothing(
train,
seasonal_periods=12,
trend='add',
seasonal='mul'
)
model_fit = model.fit()
# Делаем прогноз на 12 месяцев вперед
forecast = model_fit.forecast(12)
# Визуализация результатов
plt.figure(figsize=(12, 6))
plt.plot(train.index, train, label='Обучающие данные')
plt.plot(test.index, test, label='Тестовые данные')
plt.plot(test.index, forecast, label='Прогноз')
plt.title('Прогнозирование пассажиропотока с мультипликативной моделью сезонности')
plt.xlabel('Дата')
plt.ylabel('Количество пассажиров (тыс.)')
plt.legend()
plt.grid(True)
plt.show()
# Оценка качества прогноза
from sklearn.metrics import mean_absolute_percentage_error, mean_squared_error
mape = mean_absolute_percentage_error(test, forecast)
rmse = np.sqrt(mean_squared_error(test, forecast))
print(f'MAPE: {mape:.2%}')
print(f'RMSE: {rmse:.2f}')
# Сравнение сезонных компонентов в разные годы
plt.figure(figsize=(10, 6))
seasonal = decomposition.seasonal.values
plt.plot(range(1, 13), seasonal[:12], label='1949')
plt.plot(range(1, 13), seasonal[12:24], label='1950')
plt.plot(range(1, 13), seasonal[24:36], label='1951')
plt.plot(range(1, 13), seasonal[-12:], label='1960')
plt.title('Сезонные компоненты по годам (мультипликативная модель)')
plt.xlabel('Месяц')
plt.ylabel('Сезонный фактор')
plt.grid(True)
plt.legend()
plt.show()
Рис. 5: Декомпозиция временного ряда на тренд, сезонность и остатки
Рис. 6: Прогнозирование пассажиропотока с мультипликативной моделью сезонности
Рис. 7: Сезонные компоненты по годам (мультипликативная модель)
MAPE: 2.21%
RMSE: 15.81
В этом примере мы напрямую применяем мультипликативную декомпозицию к данным о пассажиропотоке авиалиний, которые демонстрируют растущую амплитуду сезонных колебаний.
Обратите внимание что метрики ошибок модели стали еще лучше: RMSE=15.81, MAPE=2.21%. То есть мультипликативная сезонность лучше описывает этот временной ряд, чем аддитивная. Но почему?
Все дело в растущей дисперсии из года в год и ускорении тренда. Если внимательно посмотреть на исходный график временного ряда, то становится очевидным что с середины 50х гг растущий тренд ускоряется, а также растет дисперсия. Аддитивная модель ожидает более плавного роста, и поэтому она прогнозирует хуже.
Также важно запомнить, что сезонный компонент в мультипликативной модели интерпретируется как коэффициент (множитель), а не абсолютное отклонение, как в аддитивной модели.
Сравнение аддитивной и мультипликативной моделей сезонности
Выбор между аддитивной и мультипликативной моделями является ключевым решением при анализе временных рядов. В этом разделе я подробно рассмотрю критерии выбора и сравню эти два подхода.
Ключевые различия между моделями:
Характеристика | Аддитивная модель | Мультипликативная модель |
Математическое представление | Y(t) = T(t) + S(t) + R(t) | Y(t) = T(t) × S(t) × R(t) |
Амплитуда сезонных колебаний | Постоянная | Пропорциональна уровню тренда |
Единицы измерения сезонного компонента | Те же, что и у исходного ряда | Безразмерный коэффициент (множитель) |
Работа с отрицательными значениями | Допускает | Не допускает |
Интерпретация | Абсолютные отклонения от тренда | Относительные (процентные) отклонения от тренда |
Тип роста | Линейный | Экспоненциальный |
Дисперсия ошибки | Постоянная | Пропорциональна квадрату уровня тренда |
Чувствительность к выбросам | Умеренная | Высокая |
Типичные области применения | Данные с постоянной амплитудой, финансовые индексы, показатели с небольшим ростом | Экономические показатели, данные продаж, временные ряды с экспоненциальным ростом |
Визуальные признаки для выбора модели
За годы работы с временными рядами я выработал несколько визуальных признаков, которые помогают быстро определить, какая модель будет более подходящей:
Признаки аддитивной модели:
- На графике видно, что амплитуда сезонных колебаний примерно одинакова на всем протяжении ряда.
- Разброс точек вокруг тренда относительно постоянен.
- Значения могут быть близкими к нулю или отрицательными.
- При делении ряда на несколько равных временных отрезков сезонные паттерны выглядят примерно одинаково.
Признаки мультипликативной модели:
- Амплитуда сезонных колебаний растет с ростом тренда.
- Вариабельность значений увеличивается с ростом уровня ряда.
- Данные строго положительны и далеки от нуля.
- При логарифмировании данных сезонные колебания становятся более равномерными.
Статистические тесты для выбора модели
Помимо визуального анализа, существуют формальные статистические методы для выбора между аддитивной и мультипликативной моделями:
- Тест на гетероскедастичность — если дисперсия остатков коррелирует с уровнем ряда, это может указывать на необходимость использования мультипликативной модели.
- Тест Бокса-Кокса — помогает определить оптимальное преобразование данных для стабилизации дисперсии. Значение параметра λ, близкое к 0, указывает на необходимость логарифмического преобразования и, соответственно, на мультипликативную структуру.
- Информационные критерии (AIC, BIC) — сравнение моделей по критериям Акаике и Байеса позволяет выбрать наиболее эффективную модель с учетом её сложности.
Практическая реализация теста Бокса-Кокса в Python:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.holtwinters import ExponentialSmoothing
from sklearn.metrics import mean_absolute_percentage_error, mean_squared_error
# Загрузка демонстрационных данных о пассажиропотоке авиалиний
from statsmodels.datasets import get_rdataset
airline = get_rdataset('AirPassengers').data
if 'value' in airline.columns:
airline = airline[['value']] # Оставляем только нужный столбец
airline.columns = ['Passengers']
# Устанавливаем индекс как временной ряд
airline.index = pd.date_range(start='1949-01-01', periods=len(airline), freq='ME')
# Разделение на обучающую и тестовую выборки
train = airline.iloc[:-24]
test = airline.iloc[-24:]
# Аддитивная модель
model_add = ExponentialSmoothing(
train,
seasonal_periods=12,
trend='add',
seasonal='add'
)
model_add_fit = model_add.fit()
forecast_add = model_add_fit.forecast(24)
# Мультипликативная модель
model_mul = ExponentialSmoothing(
train,
seasonal_periods=12,
trend='add',
seasonal='mul'
)
model_mul_fit = model_mul.fit()
forecast_mul = model_mul_fit.forecast(24)
# Логарифмическая трансформация + аддитивная модель
train_log = np.log(train)
model_log_add = ExponentialSmoothing(
train_log,
seasonal_periods=12,
trend='add',
seasonal='add'
)
model_log_add_fit = model_log_add.fit()
forecast_log_add = np.exp(model_log_add_fit.forecast(24))
# Визуализация результатов
plt.figure(figsize=(14, 7))
plt.plot(train.index, train, label='Обучающие данные')
plt.plot(test.index, test, label='Тестовые данные')
plt.plot(test.index, forecast_add, '--', label='Аддитивная модель')
plt.plot(test.index, forecast_mul, '--', label='Мультипликативная модель')
plt.plot(test.index, forecast_log_add, '--', label='Лог + Аддитивная')
plt.title('Сравнение прогнозов моделей с разными типами сезонности')
plt.xlabel('Дата')
plt.ylabel('Количество пассажиров (тыс.)')
plt.legend()
plt.grid(True)
plt.show()
# Оценка точности моделей
metrics = pd.DataFrame(index=['MAPE', 'RMSE'])
metrics['Аддитивная'] = [
mean_absolute_percentage_error(test, forecast_add),
np.sqrt(mean_squared_error(test, forecast_add))
]
metrics['Мультипликативная'] = [
mean_absolute_percentage_error(test, forecast_mul),
np.sqrt(mean_squared_error(test, forecast_mul))
]
metrics['Лог + Аддитивная'] = [
mean_absolute_percentage_error(test, forecast_log_add),
np.sqrt(mean_squared_error(test, forecast_log_add))
]
print(metrics)
Рис. 8: Сравнение прогнозов моделей с разными типами сезонности
Аддитивная Мультипликативная Лог + Аддитивная
MAPE 0.066360 0.063909 0.066644
RMSE 35.757539 32.488181 37.017451
Интересно, что третий подход (логарифмическая трансформация + аддитивная модель) фактически эквивалентен мультипликативной модели, но иногда дает более стабильные результаты. Этот гибридный метод в data science применяют довольно часто, особенно при работе с данными, демонстрирующими экспоненциальный рост.
Смешанные и гибридные модели
Помимо чисто аддитивных и мультипликативных моделей, существуют более гибкие подходы, которые комбинируют элементы обоих типов или добавляют дополнительные компоненты. В своей практике я иногда использую эти продвинутые техники для работы со сложными временными рядами.
Модели с комбинированными эффектами
Аддитивно-мультипликативная модель:
Y(t) = [T(t) + SA(t)] × SM(t) × R(t)
где:
- T(t) — тренд
- SA(t) — аддитивный сезонный компонент
- SM(t) — мультипликативный сезонный компонент
- R(t) — остаточный компонент
Такая модель может использоваться, когда временной ряд демонстрирует несколько типов сезонности с разным характером. Например, при наличии недельной сезонности с постоянной амплитудой и годовой сезонности с растущей амплитудой.
Модели с множественной сезонностью
В некоторых случаях временные ряды содержат несколько сезонных компонентов с разными периодами. Для таких данных я использую модели с множественной сезонностью:
Аддитивная модель с множественной сезонностью:
Y(t) = T(t) + S1(t) + S2(t) + … + Sk(t) + R(t)
Мультипликативная модель с множественной сезонностью:
Y(t) = T(t) × S1(t) × S2(t) × … × Sk(t) × R(t)
Где S1, S2, …, Sk — сезонные компоненты с разными периодами.
Пример реализации модели с множественной сезонностью в Python:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.statespace.structural import UnobservedComponents
# Создаем синтетический временной ряд с дневной и недельной сезонностью
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=180, freq='D')
trend = np.linspace(100, 200, 180) # Линейный тренд
# Дневная сезонность (24 часа)
daily_seasonal = 15 * np.sin(2 * np.pi * np.arange(180) / 1)
# Недельная сезонность (7 дней)
weekly_seasonal = 40 * np.sin(2 * np.pi * np.arange(180) / 7)
# Комбинируем компоненты и добавляем шум
noise = np.random.normal(0, 10, 180)
ts_additive = trend + daily_seasonal + weekly_seasonal + noise
ts_multiplicative = trend * (1 + daily_seasonal/100) * (1 + weekly_seasonal/100) + noise
# Создаем DataFrame
df_add = pd.DataFrame({'value': ts_additive}, index=dates)
df_mul = pd.DataFrame({'value': ts_multiplicative}, index=dates)
# Визуализация временного ряда
plt.figure(figsize=(14, 7))
plt.subplot(2, 1, 1)
plt.plot(df_add)
plt.title('Временной ряд с аддитивной множественной сезонностью')
plt.subplot(2, 1, 2)
plt.plot(df_mul)
plt.title('Временной ряд с мультипликативной множественной сезонностью')
plt.tight_layout()
plt.show()
# Моделирование с использованием модели структурных компонентов
# для аддитивного ряда
model_add = UnobservedComponents(
df_add['value'],
level='local linear trend',
freq_seasonal=[{'period': 7, 'harmonics': 3}], # Только недельная сезонность
irregular=True
)
res_add = model_add.fit()
# Визуализация компонентов
fig = plt.figure(figsize=(14, 10))
fig = res_add.plot_components(fig=fig)
plt.tight_layout()
plt.show()
# Прогнозирование
forecast = res_add.get_forecast(steps=30)
mean_forecast = forecast.predicted_mean
conf_int = forecast.conf_int()
# Визуализация прогноза
plt.figure(figsize=(14, 7))
plt.plot(df_add.index, df_add, label='Исходные данные')
plt.plot(pd.date_range(start=df_add.index[-1], periods=31, freq='D')[1:],
mean_forecast, label='Прогноз')
plt.fill_between(pd.date_range(start=df_add.index[-1], periods=31, freq='D')[1:],
conf_int.iloc[:, 0], conf_int.iloc[:, 1], alpha=0.2)
plt.title('Прогноз модели с множественной сезонностью')
plt.legend()
plt.grid(True)
plt.show()
Рис. 9: Сравнение временных рядов с аддитивиной и мультипликативной множественной сезонностью
Рис. 10: Декомпозиция временного ряда с наложенными прогнозными значениями
Рис. 11: Прогноз модели с множественной сезонностью
Этот код демонстрирует, как можно моделировать временные ряды с несколькими сезонными компонентами, используя модель структурных компонентов из библиотеки statsmodels.
Декомпозиция STL и MSTL
Для более гибкой декомпозиции временных рядов, особенно с нелинейными трендами или меняющимися сезонными паттернами, я часто использую методы STL (Seasonal-Trend decomposition using LOESS) и его расширение для множественной сезонности MSTL.
Пример использования STL-декомпозиции:
from statsmodels.tsa.seasonal import STL
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Предположим, у нас есть временной ряд df
# Применяем STL-декомпозицию
stl = STL(airline,
period=12,
seasonal=13, # Параметр сглаживания для сезонного компонента
trend=21, # Параметр сглаживания для тренда
low_pass=13, # Параметр сглаживания для низкочастотного фильтра
seasonal_deg=1, # Степень полинома для сезонного компонента
trend_deg=1, # Степень полинома для тренда
robust=True) # Использование робастного метода
result = stl.fit()
# Визуализация результатов
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(14, 10))
ax1.plot(airline)
ax1.set_title('Исходный временной ряд')
ax2.plot(result.trend)
ax2.set_title('Трендовый компонент')
ax3.plot(result.seasonal)
ax3.set_title('Сезонный компонент')
ax4.plot(result.resid)
ax4.set_title('Остаточный компонент')
plt.tight_layout()
plt.show()
# Проверяем силу сезонного компонента
strength_seasonal = 1 - np.var(result.resid) / np.var(result.seasonal + result.resid)
print(f"Сила сезонного компонента: {strength_seasonal:.4f}")
# Проверяем силу тренда
strength_trend = 1 - np.var(result.resid) / np.var(result.trend + result.resid)
print(f"Сила тренда: {strength_trend:.4f}")
Рис. 12: STL-декомпозиция временного ряда
Сила сезонного компонента: 0.9720
Сила тренда: 0.9957
STL имеет несколько преимуществ перед классической декомпозицией:
- Работает с любым типом сезонности, не только с аддитивной или мультипликативной;
- Тренд и сезонный компонент могут меняться со временем;
- Робастность к выбросам;
- Возможность контроля сглаживания компонентов.
Современные методы моделирования сезонности
В последние годы появилось множество продвинутых подходов к моделированию сезонности, которые выходят за рамки классических аддитивных и мультипликативных моделей. Рассмотрим некоторые из наиболее эффективных.
Prophet
Модель машинного обучения Prophet — мощный инструмент для прогнозирования временных рядов, который хорошо моделирует сезонность разного масштаба:
from prophet import Prophet
import pandas as pd
import matplotlib.pyplot as plt
# Преобразование данных в формат для Prophet
prophet_df = pd.DataFrame({
'ds': airline.index,
'y': airline['Passengers'].values
})
# Создание и обучение модели
model = Prophet(
seasonality_mode='multiplicative', # Режим сезонности: 'additive' или 'multiplicative'
yearly_seasonality=True, # Годовая сезонность
weekly_seasonality=False, # Отключаем недельную сезонность (для месячных данных)
daily_seasonality=False # Отключаем дневную сезонность
)
model.fit(prophet_df)
# Создание датафрейма для прогноза
future = model.make_future_dataframe(periods=24, freq='M')
# Прогнозирование
forecast = model.predict(future)
# Визуализация результатов
fig = model.plot(forecast)
plt.title('Прогноз пассажиропотока с помощью Prophet')
plt.xlabel('Дата')
plt.ylabel('Количество пассажиров (тыс.)')
plt.show()
# Визуализация компонентов
fig = model.plot_components(forecast)
plt.show()
Рис. 13: Прогноз пассажиропотока авиалиний с помощью Prophet
Рис. 14: Декомпозиция ряда на тренд и годовую сезонностью моделью Prophet
Prophet может работать как с аддитивной, так и с мультипликативной моделями, может работать с дневной, недельной, месячной, годовой, квартальной, и даже кастомной сезонностью, а также учитывает эффекты праздников и других аномалий. Это делает его особенно полезным для бизнес-данных с множеством календарных эффектов.
SARIMAX
SARIMAX (Seasonal AutoRegressive Integrated Moving Average with eXogenous regressors) — другая мощная модель для работы с сезонными временными рядами:
from statsmodels.tsa.statespace.sarimax import SARIMAX
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Разделение на обучающую и тестовую выборки
train = airline.iloc[:-24]
test = airline.iloc[-24:]
# Создание и обучение модели SARIMAX
# (p,d,q)x(P,D,Q,s) = (1,1,1)x(1,1,1,12)
model = SARIMAX(
train,
order=(1, 1, 1), # Несезонная часть (p,d,q)
seasonal_order=(1, 1, 1, 12) # Сезонная часть (P,D,Q,s)
)
result = model.fit(disp=False)
# Прогнозирование
forecast = result.get_forecast(steps=24)
mean_forecast = forecast.predicted_mean
conf_int = forecast.conf_int()
# Визуализация результатов
plt.figure(figsize=(14, 7))
plt.plot(train.index, train, label='Обучающие данные')
plt.plot(test.index, test, label='Тестовые данные')
plt.plot(test.index, mean_forecast, label='Прогноз SARIMAX')
plt.fill_between(test.index, conf_int.iloc[:, 0], conf_int.iloc[:, 1], alpha=0.2)
plt.title('Прогноз пассажиропотока с помощью SARIMAX')
plt.xlabel('Дата')
plt.ylabel('Количество пассажиров (тыс.)')
plt.legend()
plt.grid(True)
plt.show()
Рис. 15: Прогноз пассажиропотока авиалиний с помощью SARIMAX
Практические рекомендации по работе с сезонностью
Сезонность — это мощный и часто недооцененный аспект временных рядов, который при правильном анализе может значительно повысить точность прогнозов. На основе проведенного исследования и практического опыта работы с различными типами данных, я сформулировал несколько ключевых рекомендаций.
- Всегда начинайте с визуального изучения данных и проверки статистических гипотез о характере сезонности. Используйте тесты на стационарность и гетероскедастичность.
- Выбор между аддитивной и мультипликативной моделями должен основываться на характере данных: аддитивная модель для постоянной амплитуды колебаний, мультипликативная модель для изменяющейся амплитуды, пропорциональной уровню ряда
- Преобразования данных (логарифмирование, преобразование Бокса-Кокса) часто помогают привести мультипликативную сезонность к аддитивной форме, упрощая моделирование.
- Множественная сезонность требует специальных подходов — STL, MSTL или моделей с несколькими сезонными компонентами.
- Современные методы (Prophet, SARIMAX, нейронные сети) часто превосходят классические подходы, особенно для сложных сезонных паттернов.
- Всегда проверяйте остатки после выделения сезонности — они должны быть стационарными и не содержать автокорреляции.
- Учитывайте внешние факторы — праздники, календарные эффекты, изменения законодательства могут искажать сезонные паттерны.
- Обновляйте модели — сезонные паттерны могут меняться со временем, поэтому важно регулярно переоценивать параметры моделей.
Перспективные направления
Если вы часто работаете со сложными временными рядами с множественной сезонностью, то я рекомендую обратить внимание на более сложные модели:
- Модели deep learning — они могут автоматически выявлять сложные сезонные паттерны (но их долго учить).
- Модели с вниманием (attention) — хорошо работают с временными рядами с нерегулярной сезонностью.
- Гибридные подходы, сочетающие классические статистические методы с машинным обучением.
Заключение
Сезонность — это не просто статистический артефакт, а отражение глубинных закономерностей в данных. Правильное понимание и моделирование сезонных эффектов открывает новые возможности для точного прогнозирования и принятия обоснованных решений в бизнесе, экономике и многих других областях.
Как показывает практика, не существует универсального подхода к моделированию сезонности — каждый временной ряд требует индивидуального анализа и выбора методов. Однако систематическое применение описанных подходов позволяет значительно повысить качество работы с сезонными данными.