Pandas & NumPy Academy · Урок

Экспоненциально взвешенное скользящее среднее

Применяйте экспоненциальное сглаживание, придающее больший вес недавним значениям, с помощью ewm(span=) — стандартного метода финансового анализа.

Урок 3 из 413 шагов

«Экспоненциально взвешенное скользящее среднее» — бесплатный урок Pandas & NumPy Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Pandas & NumPy Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Pandas & NumPy Academy содержит 4 уроков всего.

Проблема простых скользящих средних

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

import pandas as pd
import numpy as np

np.random.seed(42)
prices = pd.Series(
    100 + np.cumsum(np.random.normal(0.5, 2, 30)),
    index=pd.date_range('2024-01-01', periods=30)
)

df = pd.DataFrame({'price': prices})
df['SMA_7'] = df['price'].rolling(7).mean()
df['EWM_span7'] = df['price'].ewm(span=7).mean()
print(df.tail(5).round(2))

Как работает взвешивание EWMA

EWMA вычисляет каждое значение как взвешенную комбинацию текущего наблюдения и предыдущего значения EWMA: EWM_t = alpha * x_t + (1 - alpha) * EWM_{t-1}. alpha (коэффициент сглаживания) определяет скорость уменьшения весов: большое alpha (близкое к 1) быстро реагирует на недавние изменения (сглаживание слабее), а маленькое alpha (близкое к 0) реагирует медленно (сглаживание сильнее). Веса образуют геометрический ряд: самое недавнее значение имеет вес alpha, предыдущее — alpha*(1-alpha), и так далее.

import numpy as np

# Manually show EWMA weights
alpha = 0.3
n_points = 8
weights = [alpha * (1 - alpha)**i for i in range(n_points)]

print(f'Alpha = {alpha}')
print(f'Weights (most recent first):')
for i, w in enumerate(weights):
    print(f'  t-{i}: {w:.4f}')
print(f'Sum of shown weights: {sum(weights):.4f} (converges to 1.0)')

Метод ewm() и параметр span

Pandas реализует EWMA с помощью Series.ewm(). Самый интуитивно понятный параметр — span, аналогичный окну простого скользящего среднего: alpha = 2 / (span + 1). Значение span, равное 10, примерно соответствует 10-периодному SMA, но использует экспоненциально уменьшающиеся веса вместо одинаковых. Используйте ewm(span=n).mean() для получения EWMA, а ewm(span=n).std() — для экспоненциально взвешенной волатильности.

import pandas as pd
import numpy as np

np.random.seed(0)
data = pd.Series(
    np.random.normal(100, 10, 50),
    index=pd.date_range('2024-01-01', periods=50)
)

df = pd.DataFrame({'value': data})
df['EWM_3'] = df['value'].ewm(span=3).mean()
df['EWM_10'] = df['value'].ewm(span=10).mean()
df['EWM_20'] = df['value'].ewm(span=20).mean()

print('Alpha values:')
for span in [3, 10, 20]:
    alpha = 2 / (span + 1)
    print(f'  span={span} → alpha={alpha:.3f}')
print(df.tail(5).round(2))

Параметр halflife

Параметр halflife определяет, сколько периодов требуется, чтобы вес уменьшился вдвое. Если halflife=5, значение пятилетней давности имеет половину веса текущего значения. Соотношение имеет вид: alpha = 1 - exp(log(0.5) / halflife). Параметр halflife часто интуитивнее, чем span или alpha, поскольку напрямую выражает «память» среднего в понятных для бизнеса терминах — например: «цены двухнедельной давности должны влиять вдвое меньше, чем сегодняшняя цена».

import pandas as pd
import numpy as np

np.random.seed(5)
prices = pd.Series(
    100 + np.cumsum(np.random.normal(0, 2, 30)),
    index=pd.date_range('2024-01-01', periods=30)
)

df = pd.DataFrame({'price': prices})
# halflife=5: weight halves every 5 days
df['EWM_hl5'] = df['price'].ewm(halflife=5).mean()
# halflife=14: weight halves every 14 days (longer memory)
df['EWM_hl14'] = df['price'].ewm(halflife=14).mean()

print(df.tail(5).round(2))

Параметр alpha напрямую

Коэффициент сглаживания также можно задать напрямую с помощью ewm(alpha=). Alpha должно быть строго больше 0 и меньше 1. Большое alpha, например 0.8, даёт очень слабое сглаживание — EWMA почти точно следует исходному сигналу. Маленькое alpha, например 0.1, даёт сильное сглаживание — EWMA изменяется медленно и отстаёт от резких сдвигов. Выбор подходящего alpha зависит от компромисса между быстрой реакцией (быстрое обнаружение реальных изменений тренда) и стабильностью (игнорированием случайного шума).

import pandas as pd
import numpy as np

np.random.seed(3)
data = pd.Series(
    [100]*20 + [120]*20,  # sudden level shift at row 20
    dtype=float
) + np.random.normal(0, 2, 40)

df = pd.DataFrame({'signal': data})
df['alpha_0.1'] = df['signal'].ewm(alpha=0.1).mean()  # slow
df['alpha_0.5'] = df['signal'].ewm(alpha=0.5).mean()  # medium
df['alpha_0.9'] = df['signal'].ewm(alpha=0.9).mean()  # fast

print('After the level shift (rows 20-25):')
print(df.iloc[18:26].round(2))

EWMA для волатильности: ewm().std()

ewm(span=).std() вычисляет экспоненциально взвешенное стандартное отклонение. Это основа модели волатильности EWMA, используемой в управлении финансовыми рисками (также известной как модель RiskMetrics с коэффициентом затухания lambda=0.94). Экспоненциально взвешенная волатильность быстрее реагирует на резкие скачки, чем простое скользящее std, поскольку больший вес получает недавнее наблюдение с высокой дисперсией.

import pandas as pd
import numpy as np

np.random.seed(42)
# Simulate returns: quiet period then volatile period
returns = pd.Series(
    np.concatenate([
        np.random.normal(0, 0.01, 60),
        np.random.normal(0, 0.04, 60)  # 4x more volatile
    ]),
    index=pd.date_range('2024-01-01', periods=120)
)

df = pd.DataFrame({'returns': returns})
df['rolling_vol'] = df['returns'].rolling(20).std()
df['ewm_vol'] = df['returns'].ewm(span=20).std()

print('Volatility comparison (transition at row 60):')
print(df.iloc[58:65].round(5))

MACD: объединение двух EWMA

MACD (схождение-расхождение скользящих средних) — классический финансовый индикатор, построенный на основе двух EWMA. Он представляет собой разность между быстрой EWMA (с коротким интервалом) и медленной EWMA (с длинным интервалом) цены. Когда MACD пересекает нулевую отметку снизу вверх, это сигнализирует о возможном восходящем импульсе (сигнале к покупке); пересечение сверху вниз сигнализирует о нисходящем импульсе. MACD — отличный пример применения двух EWMA для получения производного индикатора.

import pandas as pd
import numpy as np

np.random.seed(7)
prices = pd.Series(
    100 + np.cumsum(np.random.normal(0.3, 2, 100)),
    index=pd.date_range('2024-01-01', periods=100)
)

df = pd.DataFrame({'price': prices})
df['EMA_12'] = df['price'].ewm(span=12).mean()  # fast
df['EMA_26'] = df['price'].ewm(span=26).mean()  # slow
df['MACD'] = df['EMA_12'] - df['EMA_26']
df['Signal'] = df['MACD'].ewm(span=9).mean()   # signal line

print('MACD values (last 8 rows):')
print(df[['price', 'MACD', 'Signal']].tail(8).round(2))

EWMA с периодом полураспада, заданным по времени

Pandas 1.1+ поддерживает задание halflife, span и com как временных интервалов (например, halflife='7D') при работе с DatetimeIndex. Это позволяет корректно вычислять EWMA для неравномерных временных рядов: например, если у Вас есть почасовые данные с пропусками по выходным, halflife '7D' означает, что вес действительно уменьшается вдвое каждые 7 календарных дней независимо от количества строк за этот период.

import pandas as pd
import numpy as np

np.random.seed(0)
# Business-day data (no weekends)
biz_dates = pd.bdate_range('2024-01-01', periods=20)
prices = pd.Series(100 + np.cumsum(np.random.randn(20)), index=biz_dates)

# halflife as a time offset (7 calendar days)
ewm_7d = prices.ewm(halflife='7D', times=biz_dates).mean()
# halflife as row count (7 rows)
ewm_7rows = prices.ewm(halflife=7).mean()

df = pd.DataFrame({'price': prices, 'hl_7D': ewm_7d, 'hl_7rows': ewm_7rows})
print(df.round(2))

Выбор между EWMA, rolling и expanding

Кратко о том, когда использовать каждый подход:

  • Rolling(n).mean(): все n недавних наблюдений имеют одинаковый вес — подходит для простых показателей за предшествующий период и случаев, когда все недавние периоды одинаково важны.
  • ewm(span=n).mean(): экспоненциальное взвешивание — лучший выбор, когда сглаживание должно сильнее реагировать на недавние изменения; этот подход часто используется в финансах и обработке сигналов.
  • expanding().mean(): все исторические данные имеют одинаковый вес — лучший вариант для показателей YTD или статистик за всё время, когда нельзя забывать старые данные.

Визуализация EWMA и SMA

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

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)
prices = pd.Series(
    np.concatenate([
        100 + np.cumsum(np.random.normal(0.3, 1.5, 50)),
        130 + np.cumsum(np.random.normal(-0.3, 1.5, 50))
    ]),
    index=pd.date_range('2024-01-01', periods=100)
)

df = pd.DataFrame({'price': prices})
df['SMA_10'] = df['price'].rolling(10).mean()
df['EWMA_10'] = df['price'].ewm(span=10).mean()

df.plot(figsize=(12, 5), title='SMA vs EWMA — EWMA reacts faster to trend reversals')
plt.ylabel('Price')
plt.axvline(x=df.index[50], color='red', linestyle='--', label='Trend change')
plt.legend()
plt.show()

EWMA в бизнес-приложениях

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

Быстрая проверка

Проверьте, насколько хорошо Вы поняли тему экспоненциально взвешенных скользящих средних из этого урока.

Итоги урока

В этом уроке Вы узнали, что ewm(span=) применяет экспоненциально уменьшающиеся веса, поэтому недавние наблюдения важнее, alpha управляет скоростью реакции (большое значение = быстро, маленькое = плавно), а параметр halflife выражает «память» в понятных для бизнеса терминах. EWMA превосходит SMA, когда важно быстро обнаруживать развороты тренда. Далее мы рассмотрим вычисление рангов и процентилей внутри групп с помощью groupby().rank() и pd.qcut.

Можно начать бесплатно

Изучай Python с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
30
Уроки
120

Часто задаваемые вопросы

Урок «Экспоненциально взвешенное скользящее среднее» бесплатный?

Да — полный текст урока «Экспоненциально взвешенное скользящее среднее» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Pandas & NumPy Academy, подпишись на CoddyKit PRO. Курс Pandas & NumPy Academy содержит 4 уроков всего.

Чему я научусь в уроке «Экспоненциально взвешенное скользящее среднее»?

Применяйте экспоненциальное сглаживание, придающее больший вес недавним значениям, с помощью ewm(span=) — стандартного метода финансового анализа. Ты практикуешь Pandas & NumPy Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Pandas & NumPy Academy?

Предыдущий опыт не требуется. Pandas & NumPy Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Экспоненциально взвешенное скользящее среднее»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Pandas & NumPy Academy?

Да. Каждый урок Pandas & NumPy Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Скользящие окна
  2. Расширяющиеся окна
  3. Экспоненциально взвешенное скользящее среднее
  4. Ранги и процентили внутри групп
← Назад к Pandas & NumPy Academy