Скользящее среднее как сглаживание
Осваиваем самый простой фильтр: усреднение окна гасит шум и проявляет тренд, но платит запаздыванием.
Скользящее среднее (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 точек, гася шум и проявляя тренд.
- Широкое окно — глаже, но больше запаздывает; узкое — отзывчивее, но шумнее.
- Взвешенное среднее даёт больший вес свежим точкам и меньше отстаёт.
Главная мысль раздела: сглаживание — это всегда сделка, где вы платите запаздыванием за гладкость, и осознанный выбор окна важнее самой формулы. Скользящее среднее стоит держать в голове как первый, дешёвый и понятный инструмент — но именно его ограничения (жёсткая память, запаздывание в половину окна, артефакты прямоугольного окна) мотивируют переход к экспоненциальному сглаживанию, которому посвящён следующий урок.