Скользящая средняя Уэллса Уайлдера с pandas - PullRequest
1 голос
/ 28 февраля 2020

Я пытаюсь вычислить скользящую среднюю типа Уэллса Уайлдера в кадре данных панды (также называемую кумулятивной скользящей средней).

Метод расчета скользящей средней Уайлдера для 'n' периодов серии 'A 'is:

  • Рассчитать среднее значение первых' n 'значений в' A 'и установить среднее значение для позиции' n '.
  • Для следующих значений используйте предыдущее среднее значение, взвешенное по (n-1), и текущее значение ряда, взвешенное по 1, и делим все на 'n'.

Мой вопрос: как реализовать это векторизованным способом?

Я попытался сделать это итерацией по фрейму данных (то, что я читаю, не рекомендуется, потому что медленно). Это работает, значения верны, но я получаю сообщение об ошибке

SettingWithCopyWarning:
Значение пытается быть установлено для копии фрагмента из DataFrame

и это, вероятно, не самый эффективный способ сделать это.

Мой код пока:

import pandas as pd
import numpy as np

#Building Random sample:
datas = pd.date_range('2020-01-01','2020-01-31')
np.random.seed(693)
A = np.random.randint(40,60, size=(31,1))
df = pd.DataFrame(A,index = datas, columns = ['A'])

period = 12 # Main parameter
initial_mean = A[0:period].mean() # Equation for the first value.

size = len(df.index)
df['B'] = np.full(size, np.nan)
df.B[period-1] = initial_mean

for x in range(period, size):
    df.B[x] = ((df.A[x] + (period-1)*df.B[x-1]) / period) # Equation for the following values. 

print(df)

1 Ответ

1 голос
/ 28 февраля 2020

Вы можете использовать метод Pandas ewm(), который ведет себя точно так же, как вы описали, когда adjust=False:

Когда настройка установлена ​​в False, вычисляются средневзвешенные значения рекурсивно как:

weighted_average[0] = arg[0];
weighted_average[i] = (1-alpha)*weighted_average[i-1] + alpha*arg[i]

Если вы хотите сделать простое среднее для первого периода элементов, вы можете сделать это первым и применить ewm() к результату.

Вы можете вычислить ряды со средним значением первых периодов элементов, а затем другие элементы, дословно повторяемые по формуле:

pd.Series(
    data=[df['A'].iloc[:period].mean()],
    index=[df['A'].index[period-1]],
).append(
    df['A'].iloc[period:]
)

Таким образом, чтобы вычислите скользящее среднее значение Уайлдера и сохраните его в новом столбце 'C', вы можете использовать:

df['C'] = pd.Series(
    data=[df['A'].iloc[:period].mean()],
    index=[df['A'].index[period-1]],
).append(
    df['A'].iloc[period:]
).ewm(
    alpha=1.0 / period,
    adjust=False,
).mean()

В этот момент вы можете вычислить df['B'] - df['C'], и вы увидите, что разница почти равна нулю (есть некоторая ошибка округления с числами с плавающей запятой.) Так что это эквивалентно вашему вычислению с использованием al oop.

Возможно, вы захотите пропустить прямое среднее между первыми элементами period и просто начните применять ewm() от т начало, при котором первая строка будет предыдущим средним в первом расчете. Результаты будут немного отличаться, но как только вы пройдете через пару периодов , эти начальные значения вряд ли повлияют на результаты.

Это будет намного более простой расчет:

df['D'] = df['A'].ewm(
    alpha=1.0 / period,
    adjust=False,
).mean()
...