Метод Хольта и Хольта-Винтерса

Достраиваем экспоненциальное сглаживание до полноценной модели с трендом и сезонностью.

Метод Хольта добавляет к уровню отдельно сглаживаемый тренд, а Хольта-Винтерса — ещё и сезонную компоненту, что позволяет прогнозировать рост и повторяющиеся пики.

Зачем расширять SES

SES прогнозирует плоскую линию — для растущего ряда это плохо. Хольт вводит вторую компоненту, тренд, которая тоже сглаживается экспоненциально (параметром β). Теперь прогноз на h шагов вперёд — это уровень плюс тренд, умноженный на h: модель умеет экстраполировать рост. Хольта-Винтерса добавляет третью компоненту, сезонность (параметр γ), и становится рабочей лошадкой для рядов спроса с недельным или годовым циклом.

Почему это важно для бизнеса, проще всего увидеть на планировании. Допустим, стартап растёт: выручка прибавляет примерно 5% в месяц. Модель без тренда (SES) будет упрямо прогнозировать «следующий месяц как текущий» и хронически недооценивать спрос — склад опустеет, серверы не выдержат нагрузки, отдел найма опоздает. Хольт же отслеживает не только текущий уровень, но и скорость роста, поэтому его прогноз продолжает восходящую линию в будущее. Для финансового планирования, закупок и найма это разница между «вечно реагируем постфактум» и «готовимся заранее».

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

Метод Хольта в коде

def holt(xs, alpha, beta):
    level = xs[0]
    trend = xs[1] - xs[0]
    out = []
    for x in xs:
        prev_level = level
        level = alpha * x + (1 - alpha) * (level + trend)
        trend = beta * (level - prev_level) + (1 - beta) * trend
        out.append((round(level, 2), round(trend, 2)))
    return out

data = [10, 12, 14, 16, 18, 20]
for lv, tr in holt(data, 0.5, 0.5):
    print("уровень:", lv, " тренд:", tr)

Вывод:

уровень: 11.0  тренд: 1.5
уровень: 12.25  тренд: 1.38
уровень: 13.81  тренд: 1.47
уровень: 15.64  тренд: 1.65
уровень: 17.64  тренд: 1.83
уровень: 19.74  тренд: 1.96

Модель отдельно отслеживает текущий уровень (19.74) и скорость роста (1.96 за шаг). Это и даёт способность к экстраполяции, которой не было у SES.

Вглядимся в два уравнения внутри цикла. Первое обновляет уровень, но в отличие от SES оно усредняет свежее наблюдение не с прежним уровнем, а с прогнозом (level + trend) — то есть с тем, куда уровень должен был сместиться с учётом известной скорости роста. Без этой поправки на тренд уровень снова отставал бы. Второе уравнение обновляет сам тренд: оно сравнивает, насколько уровень фактически вырос за этот шаг (level − prev_level), со старой оценкой тренда и смешивает их через β. Так скорость роста тоже сглаживается экспоненциально и не дёргается от каждого случайного скачка. Заметьте в выводе, как тренд стартует с 1.5, слегка проседает до 1.38, а затем плавно подбирается к 1.96 — модель «нащупывает» истинную скорость роста ряда, которая здесь равна 2 за шаг.

Прогноз с трендом

Имея конечные уровень и тренд, прогноз на h шагов — это level + trend · h.

def holt(xs, alpha, beta):
    level = xs[0]; trend = xs[1] - xs[0]
    for x in xs:
        prev = level
        level = alpha * x + (1 - alpha) * (level + trend)
        trend = beta * (level - prev) + (1 - beta) * trend
    return level, trend

data = [10, 12, 14, 16, 18, 20]
level, trend = holt(data, 0.5, 0.5)
forecast = [round(level + trend * h, 2) for h in (1, 2, 3)]
print("Прогноз на 3 шага:", forecast)

Вывод:

Прогноз на 3 шага: [21.69, 23.65, 25.61]

Прогноз растёт линейно — модель «продолжила» тренд в будущее. Именно так Хольт превосходит SES на трендовых рядах.

Соседние значения прогноза отличаются ровно на 1.96 — на величину финального тренда. Это наглядно показывает, что прогноз Хольта — прямая линия, выходящая из последнего уровня с наклоном, равным последней оценке тренда. SES в этом же месте выдала бы три одинаковых числа (плоскую линию на уровне 19.74), и на растущем ряде это было бы заметным недолётом. Линейность прогноза — одновременно сила и слабость метода: на горизонте в несколько шагов она работает отлично, но именно из-за неё нельзя бездумно экстраполировать тренд далеко вперёд, о чём ниже.

Хольта-Винтерса: три уравнения

Полная модель держит три величины: уровень, тренд и набор сезонных индексов (по одному на позицию внутри периода). На каждом шаге обновляются все три, а прогноз складывает уровень + h·тренд + сезонный индекс соответствующей позиции. В аддитивном варианте сезонность прибавляется, в мультипликативном — умножается. Это самый ходовой метод для рядов спроса с выраженной сезонностью.

Выбор между аддитивной и мультипликативной сезонностью — не формальность, а вопрос о природе данных. Аддитивная подходит, когда сезонные колебания постоянны по абсолютной величине: например, в декабре всегда продают на 200 единиц больше, независимо от общего масштаба бизнеса. Мультипликативная нужна, когда сезонность растёт вместе с уровнем: декабрь даёт +30% к продажам, и в год с оборотом миллион это +300 тысяч, а в год с оборотом два миллиона — уже +600 тысяч. Признак на глаз: если на графике сезонные «зубцы» становятся выше по мере роста ряда (амплитуда расширяется), берите мультипликативную модель; если зубцы держат одинаковую высоту — аддитивную. Ошибка в этом выборе систематически искажает прогноз пиков.

Важная деталь — инициализация сезонных индексов. Чтобы модель стартовала осмысленно, ей нужен хотя бы один полный период данных для оценки начального сезонного профиля, а лучше два-три. Если истории меньше одного цикла, сезонную компоненту просто не из чего оценить, и Хольта-Винтерса применять рано — это частая причина, по которой метод «не заводится» на коротких рядах.

Как работает под капотом

Все три компоненты — уровень, тренд, сезонность — обновляются как экспоненциальные средние: новая оценка = доля свежего наблюдения + доля старой оценки. Параметры α, β, γ обычно подбирают совместно, минимизируя сумму квадратов ошибок прогноза на истории. Хольта-Винтерса — частный случай пространства состояний (ETS), и в библиотеках он реализован именно через эту формализацию с автоподбором параметров.

Совместный подбор трёх параметров устроен сложнее, чем оптимизация одного α в SES, но идея та же: оптимизатор прогоняет модель по истории, считает одношаговые ошибки прогноза, суммирует их квадраты и ищет тройку (α, β, γ), которая эту сумму минимизирует. Поверхность ошибки здесь многомерная и может иметь несколько локальных минимумов, поэтому библиотеки стартуют из разумных начальных приближений и нередко перебирают несколько стартов — это полезно понимать, когда два запуска на одних данных дают чуть разные параметры.

Связь с ETS (Error-Trend-Seasonality) стоит держать в голове как карту семейства. ETS — это единая система обозначений, где каждая буква описывает тип компоненты: ошибка аддитивная или мультипликативная, тренд отсутствует / аддитивный / затухающий, сезонность отсутствует / аддитивная / мультипликативная. В этих терминах SES — это ETS(A,N,N), метод Хольта — ETS(A,A,N), а Хольта-Винтерса — ETS(A,A,A) или (A,A,M). Современные библиотеки умеют автоматически перебирать варианты ETS и по информационному критерию выбирать лучший, так что на практике вы часто не выбираете модель вручную, а доверяете этому перебору — но понимать, что под капотом именно эти уравнения, важно для интерпретации результата.

Частые ошибки

  • Применять Хольта (без сезонности) к ряду с явной сезонностью — пики останутся непойманными.
  • Путать аддитивную и мультипликативную сезонность Хольта-Винтерса при растущей амплитуде.
  • Экстраполировать линейный тренд Хольта слишком далеко — на длинном горизонте он «улетает».

Третья ошибка особенно болезненна в долгосрочном планировании. Линейный тренд Хольта продолжает расти с постоянной скоростью бесконечно, но реальные процессы так себя не ведут: рост рано или поздно упирается в потолок рынка, насыщение спроса, ограничения мощностей. Если взять текущую скорость роста и спроецировать её на два года вперёд, прогноз может выдать абсурдно большие числа, под которые опасно закладывать бюджет. Лекарство — затухающий тренд (damped trend): в него вводят параметр φ из (0;1), который на каждом шаге горизонта умножает вклад тренда, так что прогноз постепенно выходит на плато вместо бесконечной прямой. На средних и длинных горизонтах затухающий тренд почти всегда устойчивее обычного, и многие практики ставят его по умолчанию.

Итоги

  • Хольт добавляет к уровню сглаживаемый тренд и умеет экстраполировать рост.
  • Хольта-Винтерса добавляет сезонность — лучший простой выбор для рядов спроса с циклом.
  • Все компоненты обновляются экспоненциально; параметры подбирают по ошибке прогноза.

Связав три урока вместе, мы прошли путь от грубого усреднения окна к семейству моделей экспоненциального сглаживания, которое аккуратно раскладывает ряд на уровень, тренд и сезонность и каждую компоненту обновляет одной и той же простой идеей экспоненциального среднего. Эти методы дёшевы, прозрачны и на удивление сильны: на многих рядах спроса хорошо настроенный Хольта-Винтерса бьёт куда более сложные модели и служит честной базовой линией, ниже которой опускаться стыдно. С него и стоит начинать любой прогноз, усложняя модель лишь тогда, когда данные доказывают, что усложнение окупается.

Проверьте себя
1. Что добавляет метод Хольта к простому экспоненциальному сглаживанию?
AСезонность
BОтдельно сглаживаемую компоненту тренда
CЛогарифмирование
DПроверку стационарности
2. Когда выбирают модель Хольта-Винтерса, а не Хольта?
AКогда ряд чисто случаен
BКогда в ряде есть выраженная сезонность с периодом
CКогда нет тренда
DКогда мало данных