ARIMA: классический метод прогнозирования временных рядов

Что такое ARIMA

ARIMA (AutoRegressive Integrated Moving Average) — классическая модель для прогнозирования временных рядов. Расшифровка:

  • AR (AutoRegressive) — текущее значение зависит от прошлых значений.
  • I (Integrated) — differencing для получения стационарности.
  • MA (Moving Average) — текущее значение зависит от прошлых ошибок прогноза.

ARIMA записывается как ARIMA(p, d, q), где p — порядок AR, d — порядок differencing, q — порядок MA.

Разработана Box и Jenkins в 1970-х, до сих пор используется как baseline во многих forecasting задачах.

Когда применять ARIMA

ARIMA хорошо работает для:

  • Стационарных (или легко приводимых к стационарности) рядов.
  • Без сильной сезонности (или с SARIMA для сезонных).
  • Univariate (одна временная переменная).
  • Относительно короткие горизонты прогноза.

Плохо для:

  • Сложные нелинейные паттерны.
  • Множественные внешние факторы.
  • Очень длинные ряды (10 000+ точек — ML подходы лучше).
  • Intermittent demand (много нулей).

В product analytics ARIMA хороша для прогнозирования DAU, revenue, orders — когда паттерн относительно стабилен.

Компоненты: AR, I, MA

AR(p). Autoregressive.

y_t = c + φ₁·y_(t-1) + φ₂·y_(t-2) + ... + φ_p·y_(t-p) + ε_t

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

I(d). Integrated = differencing.

Если ряд не стационарен, берём разности.

y'_t = y_t - y_(t-1)  # d=1
y''_t = y'_t - y'_(t-1)  # d=2

Обычно d=1 достаточно. Тренды ряды становятся стационарными после одной разности.

MA(q). Moving Average.

y_t = c + ε_t + θ₁·ε_(t-1) + ... + θ_q·ε_(t-q)

Текущее значение зависит от q прошлых ошибок. «Корректирует» модель на основе recent errors.

Как определить p, d, q

d (differencing). Тест стационарности (Augmented Dickey-Fuller).

from statsmodels.tsa.stattools import adfuller

result = adfuller(y)
print(f'ADF statistic: {result[0]}')
print(f'p-value: {result[1]}')
# p < 0.05 → ряд стационарен

Если p-value > 0.05, применяем diff() и тестируем снова.

p и q. ACF и PACF графики.

from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

plot_acf(y)   # помогает определить q
plot_pacf(y)  # помогает определить p

Эмпирические правила:

  • Если PACF имеет резкий cutoff после lag p, а ACF затухает → AR(p).
  • Если ACF cutoff после lag q, PACF затухает → MA(q).
  • Оба затухают → ARMA(p,q), определять через grid search.

Практика в Python

from statsmodels.tsa.arima.model import ARIMA

# Fit модель
model = ARIMA(y_train, order=(1, 1, 1))
fitted = model.fit()
print(fitted.summary())

# Forecast на 10 периодов
forecast = fitted.forecast(steps=10)
print(forecast)

# Forecast с CI
forecast_result = fitted.get_forecast(steps=10)
mean = forecast_result.predicted_mean
ci = forecast_result.conf_int()

summary() показывает коэффициенты AR/MA, их significance, AIC/BIC.

Auto-ARIMA

Вместо ручного подбора — автоматический:

from pmdarima import auto_arima

model = auto_arima(
    y_train,
    start_p=0, max_p=5,
    start_q=0, max_q=5,
    d=None,  # автоматически выбирается
    seasonal=False,
    trace=True,
    error_action='ignore',
    suppress_warnings=True,
    stepwise=True
)

print(model.summary())
forecast = model.predict(n_periods=10)

auto_arima перебирает комбинации (p, d, q), минимизирует AIC, возвращает лучшую модель. Очень удобно для первой итерации.

SARIMA для сезонных

SARIMA — ARIMA с сезонностью. Параметры: (p, d, q) × (P, D, Q)s, где s — период сезонности (12 для месячных, 7 для дневных с недельной сезонностью).

from statsmodels.tsa.statespace.sarimax import SARIMAX

model = SARIMAX(
    y_train,
    order=(1, 1, 1),
    seasonal_order=(1, 1, 1, 12)  # годовая сезонность
)
fitted = model.fit()
forecast = fitted.forecast(steps=12)

Большинство бизнес-рядов имеют сезонность — SARIMA чаще используется, чем базовая ARIMA.

Альтернативы

Exponential Smoothing (ETS). Старый метод, но часто competitive. Holt-Winters для tрендов и сезонности. Проще ARIMA, хорошо работает out-of-the-box.

Prophet (Facebook). Декомпозиция на тренд, сезонность, праздники. Handle missing data. Хорошо для business time series. Но «чёрный ящик» сравнительно.

LSTM / Deep Learning. Для сложных паттернов и множества features. Нужен большой объём данных.

Gradient Boosting (LightGBM, XGBoost). Популярный подход — делают fe из time features (lag, rolling means) и учат boosting. Часто побеждает ARIMA на Kaggle.

Neural Prophet. Prophet + neural нетwork. Хорошая combination для больших данных.

Современные практики: начать с ARIMA/Prophet как baseline, потом пробовать ML при наличии data.

Временные ряды — важная тема для аналитиков в finance, ops, marketing. В тренажёре Карьерник есть задачи на time series analysis и forecasting.

Метрики оценки

Для train/test split используют временной split (не random):

train_size = int(len(y) * 0.8)
y_train, y_test = y[:train_size], y[train_size:]

Метрики:

  • MAE (Mean Absolute Error). mean(|y - y_hat|). Интерпретируется в единицах y.
  • RMSE (Root Mean Squared Error). sqrt(mean((y - y_hat)^2)). Штрафует большие ошибки.
  • MAPE (Mean Absolute Percentage Error). mean(|y - y_hat| / y) * 100%. Относительная ошибка.
  • SMAPE. Symmetric MAPE, устойчивее к near-zero values.

Для бизнеса MAPE — наиболее интерпретируемая.

Residual diagnostics

После fit проверяем residuals (остатки = факт - прогноз):

residuals = fitted.resid

# 1. Residuals должны быть белым шумом (no autocorrelation)
from statsmodels.stats.diagnostic import acorr_ljungbox
lb_test = acorr_ljungbox(residuals, lags=[10])
# p > 0.05 — остатки похожи на белый шум, модель адекватна

# 2. Нормальность (желательно)
from scipy import stats
stat, p = stats.jarque_bera(residuals)

# 3. Visual inspection
fitted.plot_diagnostics(figsize=(15, 8))

Если residuals имеют автокорреляцию — модель что-то упустила, нужно увеличить p или q.

Cross-validation для time series

Обычный k-fold не работает (leakage). Используется expanding window или rolling window:

from sklearn.model_selection import TimeSeriesSplit

tscv = TimeSeriesSplit(n_splits=5)
for train_idx, test_idx in tscv.split(y):
    y_train, y_test = y[train_idx], y[test_idx]
    # fit model, evaluate

Даёт robust оценку performance.

Обработка пропусков

ARIMA чувствительна к пропускам. Опции:

  • Forward fill (если редкие).
  • Interpolation (линейная или сезонная).
  • Seasonal decomposition и imputation по тренду/сезонности.
  • State space models (SARIMAX handles natively).

Prophet умеет работать с пропусками из коробки — одно из преимуществ.

Типичные ошибки

Игнорирование стационарности. Fitting ARIMA на нестационарном ряде → результаты бессмысленны. Всегда проверять и differences.

Overfitting. Высокие p, q → хорошо на train, плохо на test. Используйте AIC/BIC и cross-validation.

Экстраполяция далеко. ARIMA надёжна на короткие горизонты (3-12 периодов). Дальше — CI становятся очень широкими.

Не учитывать внешние факторы. Promo, праздники, события — влияют, но ARIMA их не знает. Используйте SARIMAX с exogenous variables или Prophet с holidays.

Читайте также

FAQ

ARIMA устарела?

Для многих задач — competitive. Для сложных multi-variate — уступает ML. Но начинать с ARIMA как baseline — правильно.

Сколько данных нужно?

Минимум 50 точек для простой ARIMA. Для SARIMA — 2-3 полных цикла сезонности.

ARIMA или Prophet?

Prophet — easier, хорошо для business time series с trends/seasonality/holidays. ARIMA — more control, better для stationary-like series.

Что такое ARIMAX?

ARIMA с exogenous переменными. Например, прогноз продаж + marketing spend как X. Мощнее для случаев с внешними факторами.