Сезонность временных рядов. В чем отличие аддитивной от мультипликативной?

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

Природа и причины сезонности

Сезонные колебания возникают по множеству причин, часто связанных с естественными циклами или устоявшимися социальными практиками:

  • Природные циклы — изменения температуры, осадков и других метеорологических показателей в течение года влияют на сельское хозяйство, энергетику, строительство и многие другие сферы.
  • Административные периоды — финансовый год, налоговые периоды, квартальная отчетность создают регулярные всплески или падения в бизнес-показателях.
  • Социокультурные факторы — праздники, отпускные периоды, учебные семестры вызывают предсказуемые колебания в потребительском поведении и экономической активности.
  • Технологические особенности — производственные циклы, плановые техобслуживания, регулярные обновления систем также могут создавать сезонные паттерны.

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

Типы сезонности по периодичности

Анализируя временные ряды, важно различать разные типы сезонности:

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

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

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

Недельная сезонность отражает различия между рабочими и выходными днями. Анализируя данные интернет-трафика или посещаемости розничных магазинов, всегда обнаруживаю еженедельные циклы активности.

Суточная сезонность проявляется в течение 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) — остаточный компонент (шум)

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

Читайте также:  Методы предиктивной аналитики и машинного обучения для оптимизации конверсии веб-сайтов

Когда применять аддитивную модель

На основе моего опыта работы с временными рядами могу сказать, что аддитивная модель наиболее подходит в следующих случаях:

  • Постоянная амплитуда сезонных колебаний — когда размах сезонных колебаний не зависит от общего уровня ряда. Например, если объем продаж сезонного товара увеличивается каждый год на примерно одинаковое абсолютное значение.
  • Относительно стабильная дисперсия — когда разброс значений вокруг тренда примерно одинаков на всем протяжении временного ряда.
  • Работа с данными, которые могут принимать отрицательные значения — поскольку аддитивная модель допускает отрицательные значения как для исходного ряда, так и для его компонентов.
  • Линейные зависимости между компонентами — когда эффекты различных факторов просто суммируются без взаимного усиления.

Преимущества и недостатки аддитивной модели

В процессе разработки аналитических решений я определил несколько ключевых преимуществ аддитивной модели:

Преимущества:

  1. Интуитивная интерпретация — компоненты выражены в тех же единицах, что и исходный ряд;
  2. Простота вычислений и реализации;
  3. Хорошая работа с линейными трендами;
  4. Устойчивость к выбросам (по сравнению с мультипликативной моделью);
  5. Возможность работы с отрицательными значениями.

Недостатки:

  1. Неадекватность для рядов с изменяющейся амплитудой сезонных колебаний;
  2. Ограниченная способность моделировать экспоненциальный рост;
  3. Сложности при работе с гетероскедастичными данными (когда дисперсия меняется со временем).

Практический пример аддитивной модели

Рассмотрим пример реализации аддитивной декомпозиции и прогнозирования с использованием 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) — остаточный компонент (шум)

Фундаментальное отличие этой модели от аддитивной заключается в том, что сезонные колебания пропорциональны уровню тренда. То есть, амплитуда сезонных колебаний увеличивается или уменьшается вместе с ростом или падением тренда.

Когда применять мультипликативную модель

В своей аналитической практике я выделил следующие ситуации, когда мультипликативная модель является предпочтительным выбором:

  • Изменяющаяся амплитуда сезонных колебаний — когда размах сезонных колебаний растет или уменьшается пропорционально общему уровню ряда. Например, если розничные продажи не только растут в абсолютном выражении, но и сезонные пики становятся все более выраженными.
  • Растущая или уменьшающаяся дисперсия — когда разброс значений вокруг тренда увеличивается с ростом уровня ряда.
  • Только положительные значения — поскольку мультипликативная модель основана на умножении, она не подходит для данных, которые могут принимать отрицательные или нулевые значения.
  • Экспоненциальный рост — когда данные демонстрируют нелинейный, экспоненциальный рост или спад.
  • Процентные изменения — когда сезонные эффекты удобнее интерпретировать как процентные отклонения от тренда.

Преимущества и недостатки мультипликативной модели

На основе опыта работы с различными типами временных рядов, могу выделить следующие преимущества и ограничения мультипликативной модели:

Преимущества:

  1. Естественное представление для данных с экспоненциальным ростом;
  2. Хорошая работа с изменяющейся амплитудой сезонных колебаний;
  3. Сезонные компоненты интерпретируются как относительные (процентные) отклонения;
  4. Часто лучше соответствует реальным экономическим и бизнес-процессам с растущим масштабом.

Недостатки:

  1. Невозможность работы с отрицательными или нулевыми значениями;
  2. Большая чувствительность к выбросам и аномалиям;
  3. Более сложная интерпретация компонентов;
  4. Сложности при наличии структурных изменений в данных.

Практический пример мультипликативной модели

Рассмотрим пример реализации мультипликативной декомпозиции и прогнозирования с использованием 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

Читайте также:  Прогнозирование трафика и конверсий сайта с помощью LightGBM

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

Обратите внимание что метрики ошибок модели стали еще лучше: RMSE=15.81, MAPE=2.21%. То есть мультипликативная сезонность лучше описывает этот временной ряд, чем аддитивная. Но почему?

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

Также важно запомнить, что сезонный компонент в мультипликативной модели интерпретируется как коэффициент (множитель), а не абсолютное отклонение, как в аддитивной модели.

Сравнение аддитивной и мультипликативной моделей сезонности

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

Ключевые различия между моделями:

Характеристика Аддитивная модель Мультипликативная модель
Математическое представление Y(t) = T(t) + S(t) + R(t) Y(t) = T(t) × S(t) × R(t)
Амплитуда сезонных колебаний Постоянная Пропорциональна уровню тренда
Единицы измерения сезонного компонента Те же, что и у исходного ряда Безразмерный коэффициент (множитель)
Работа с отрицательными значениями Допускает Не допускает
Интерпретация Абсолютные отклонения от тренда Относительные (процентные) отклонения от тренда
Тип роста Линейный Экспоненциальный
Дисперсия ошибки Постоянная Пропорциональна квадрату уровня тренда
Чувствительность к выбросам Умеренная Высокая
Типичные области применения Данные с постоянной амплитудой, финансовые индексы, показатели с небольшим ростом Экономические показатели, данные продаж, временные ряды с экспоненциальным ростом

Визуальные признаки для выбора модели

За годы работы с временными рядами я выработал несколько визуальных признаков, которые помогают быстро определить, какая модель будет более подходящей:

Признаки аддитивной модели:

  1. На графике видно, что амплитуда сезонных колебаний примерно одинакова на всем протяжении ряда.
  2. Разброс точек вокруг тренда относительно постоянен.
  3. Значения могут быть близкими к нулю или отрицательными.
  4. При делении ряда на несколько равных временных отрезков сезонные паттерны выглядят примерно одинаково.

Признаки мультипликативной модели:

  1. Амплитуда сезонных колебаний растет с ростом тренда.
  2. Вариабельность значений увеличивается с ростом уровня ряда.
  3. Данные строго положительны и далеки от нуля.
  4. При логарифмировании данных сезонные колебания становятся более равномерными.

Статистические тесты для выбора модели

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

  • Тест на гетероскедастичность — если дисперсия остатков коррелирует с уровнем ряда, это может указывать на необходимость использования мультипликативной модели.
  • Тест Бокса-Кокса — помогает определить оптимальное преобразование данных для стабилизации дисперсии. Значение параметра λ, близкое к 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}")

STL-декомпозиция временного ряда

Рис. 12: STL-декомпозиция временного ряда

Сила сезонного компонента: 0.9720
Сила тренда: 0.9957

STL имеет несколько преимуществ перед классической декомпозицией:

  1. Работает с любым типом сезонности, не только с аддитивной или мультипликативной;
  2. Тренд и сезонный компонент могут меняться со временем;
  3. Робастность к выбросам;
  4. Возможность контроля сглаживания компонентов.

Современные методы моделирования сезонности

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

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()

Прогноз пассажиропотока авиалиний с помощью Prophet

Рис. 13: Прогноз пассажиропотока авиалиний с помощью Prophet

Декомпозиция ряда на тренд и годовую сезонностью моделью 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()

Прогноз пассажиропотока авиалиний с помощью SARIMAX

Рис. 15: Прогноз пассажиропотока авиалиний с помощью SARIMAX

Практические рекомендации по работе с сезонностью

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

  1. Всегда начинайте с визуального изучения данных и проверки статистических гипотез о характере сезонности. Используйте тесты на стационарность и гетероскедастичность.
  2. Выбор между аддитивной и мультипликативной моделями должен основываться на характере данных: аддитивная модель для постоянной амплитуды колебаний, мультипликативная модель для изменяющейся амплитуды, пропорциональной уровню ряда
  3. Преобразования данных (логарифмирование, преобразование Бокса-Кокса) часто помогают привести мультипликативную сезонность к аддитивной форме, упрощая моделирование.
  4. Множественная сезонность требует специальных подходов — STL, MSTL или моделей с несколькими сезонными компонентами.
  5. Современные методы (Prophet, SARIMAX, нейронные сети) часто превосходят классические подходы, особенно для сложных сезонных паттернов.
  6. Всегда проверяйте остатки после выделения сезонности — они должны быть стационарными и не содержать автокорреляции.
  7. Учитывайте внешние факторы — праздники, календарные эффекты, изменения законодательства могут искажать сезонные паттерны.
  8. Обновляйте модели — сезонные паттерны могут меняться со временем, поэтому важно регулярно переоценивать параметры моделей.

Перспективные направления

Если вы часто работаете со сложными временными рядами с множественной сезонностью, то я рекомендую обратить внимание на более сложные модели:

  • Модели deep learning — они могут автоматически выявлять сложные сезонные паттерны (но их долго учить).
  • Модели с вниманием (attention) — хорошо работают с временными рядами с нерегулярной сезонностью.
  • Гибридные подходы, сочетающие классические статистические методы с машинным обучением.

Заключение

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

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