Скользящее среднее как сглаживание

Осваиваем самый простой фильтр: усреднение окна гасит шум и проявляет тренд, но платит запаздыванием.

Скользящее среднее (SMA) заменяет каждую точку средним из w последних значений, сглаживая случайные колебания и подсвечивая тренд.

Зачем сглаживать

Сырой ряд дрожит от шума, и тренд за ним не виден. Скользящее среднее усредняет соседние точки, гасит случайность и оставляет плавную линию. На неё проще смотреть, по ней проще принимать решения. Кроме того, само скользящее среднее — это уже наивный прогноз: «завтра будет как в среднем за последние w дней».

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

Тот же приём работает с трафиком сайта, нагрузкой на серверы, ценами акций и температурой за окном. Везде, где полезный сигнал медленный, а помехи быстрые, усреднение окна отделяет одно от другого почти бесплатно. Именно поэтому SMA — первый инструмент, который аналитик пробует на новом ряде: он не требует подбора параметров, кроме ширины окна, и сразу даёт интуицию о форме данных.

Считаем SMA

def sma(xs, w):
    out = []
    for i in range(len(xs)):
        if i + 1 < w:
            out.append(None)             # окно ещё не набралось
        else:
            out.append(round(sum(xs[i+1-w:i+1]) / w, 2))
    return out

data = [10, 12, 11, 13, 15, 14, 16, 18, 17, 19]
print("Ряд:    ", data)
print("SMA(3): ", sma(data, 3))

Вывод:

Ряд:     [10, 12, 11, 13, 15, 14, 16, 18, 17, 19]
SMA(3):  [None, None, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0]

Первые две точки — None: окно из трёх ещё не набралось. Дальше линия SMA плавно ползёт вверх вслед за трендом, но без скачков исходного ряда. Заметьте: SMA «отстаёт» — она реагирует на изменения с запаздыванием в половину окна.

Разберём, что именно делает код. На каждом шаге i мы берём срез xs[i+1-w:i+1] — это ровно w последних точек, заканчивая текущей. Пока индекс меньше, чем нужно для полного окна (i + 1 < w), честно ставим None: придумывать среднее из неполного набора — значит вносить искажение в самое начало ряда, где данных и так мало. Срез, заканчивающийся на текущей точке, а не заглядывающий вперёд, делает это среднее каузальным — оно опирается только на прошлое и пригодно для прогноза. Обратите внимание, что значения SMA(3) идут ровно по 1.0 шагу вверх: исходный ряд в среднем растёт на единицу за шаг, и сглаживание этот средний наклон сохраняет, просто убирая дрожание вокруг него.

Запаздывание и выбор окна

Широкое окно сильнее сглаживает, но сильнее запаздывает: к моменту, когда SMA «догонит» новый уровень, пройдёт половина окна. Узкое окно отзывчивее, но хуже давит шум. Это всегда компромисс между гладкостью и отзывчивостью. Для недельной сезонности часто берут окно ровно в период (7), чтобы усреднить весь цикл.

Откуда берётся «половина окна»? Среднее из w точек по своей геометрии относится к середине окна, а не к его правому краю. Если окно заканчивается сегодня, то центр масс этих данных лежит на (w-1)/2 шагов в прошлом — туда и «приклеена» сглаженная точка. Поэтому при окне в 30 дней SMA отражает обстановку примерно двухнедельной давности: на спокойном ряде это незаметно, но если уровень спроса резко прыгнул вверх из-за вирусного видео, широкое SMA будет ещё две недели уверять вас, что всё по-старому. Для систем, где важна быстрая реакция (мониторинг сбоев, торговые сигналы), запаздывание критично, и широкое окно становится опасным.

Выбор периода под сезонность — отдельный важный приём. Если продажи имеют недельный цикл (понедельник тихий, суббота шумная), окно ровно в 7 дней усредняет полный цикл и сезонная волна гасится сама собой, оставляя чистый тренд. Окно в 5 или 9 дней так не умеет: оно захватывает неполный цикл и сезонность «протекает» в сглаженную линию рябью. То же с годовым циклом и помесячными данными: окно в 12. Правило простое — если хотите убрать сезонность усреднением, делайте окно кратным периоду.

Взвешенное скользящее среднее

У обычного SMA все точки окна равноправны, хотя свежие данные важнее. Взвешенное среднее (WMA) даёт больший вес последним точкам и потому меньше запаздывает.

def wma(xs, weights):
    w = len(weights); sw = sum(weights)
    out = []
    for i in range(len(xs)):
        if i + 1 < w:
            out.append(None)
        else:
            win = xs[i+1-w:i+1]
            out.append(round(sum(v*k for v, k in zip(win, weights)) / sw, 2))
    return out

data = [10, 12, 11, 13, 15, 14, 16, 18, 17, 19]
print("WMA(1,2,3):", wma(data, [1, 2, 3]))

Вывод:

WMA(1,2,3): [None, None, 11.17, 12.17, 13.67, 14.17, 15.17, 16.67, 17.17, 18.17]

Веса [1,2,3] отдают свежей точке втрое больший голос, поэтому WMA ближе к концу ряда и меньше отстаёт от тренда, чем простое SMA.

Деление на sw (сумму весов) здесь обязательно: без него «среднее» раздулось бы пропорционально весам и потеряло бы масштаб исходного ряда. Нормировка гарантирует, что если все точки окна равны, скажем, десяти, то и WMA выдаст ровно десять, а не утроенное значение. Сравните сами: на одних и тех же данных WMA(1,2,3) на конце даёт 18.17 против 18.0 у SMA(3) — взвешенная версия чуть ближе к свежим, растущим значениям, потому что меньше тянет назад старая точка с весом 1. На быстро меняющемся ряде эта разница в запаздывании окупается; на спокойном — почти незаметна, и проще обойтись обычным SMA.

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

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

Что значит «пропускает рябь» на пальцах? Прямоугольное окно — это резкий обрыв весов: точка либо полностью внутри (вес 1/w), либо полностью снаружи (вес 0). Такой жёсткий край в частотной области отзывается побочными лепестками: фильтр давит большинство высоких частот, но некоторые узкие полосы пропускает почти без ослабления, и они проявляются как остаточные волны в сглаженной линии. Плавно спадающие веса (треугольные, как у WMA, или экспоненциальные, к которым мы перейдём дальше) таких резких краёв не имеют и подавляют высокие частоты монотонно. Это и есть теоретическая причина, почему следующий шаг курса — экспоненциальное сглаживание: оно убирает артефакты прямоугольного окна и заодно хранит всю историю в одном числе, не таская срез из w точек.

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

  • Брать слишком широкое окно и сглаживать сам сигнал вместе с шумом.
  • Забывать про запаздывание SMA и удивляться, что прогноз «опаздывает».
  • Использовать центрированное SMA (заглядывающее в будущее) для прогноза — это утечка.

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

Итоги

  • SMA усредняет окно из w точек, гася шум и проявляя тренд.
  • Широкое окно — глаже, но больше запаздывает; узкое — отзывчивее, но шумнее.
  • Взвешенное среднее даёт больший вес свежим точкам и меньше отстаёт.

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

Проверьте себя
1. Какой главный недостаток скользящего среднего как сглаживателя?
AОно усиливает шум
BОно запаздывает: реагирует на изменения с задержкой около половины окна
CОно требует numpy
DОно меняет среднее ряда
2. Чем взвешенное скользящее среднее (WMA) лучше простого SMA?
AОно всегда точнее
BОно даёт больший вес свежим точкам и меньше запаздывает
CОно не требует окна
DОно убирает тренд