вычислите экспоненциальное скользящее среднее в Python

21
задан Jason S 28 January 2009 в 18:07
поделиться

7 ответов

Править: Это кажется этим mov_average_expw() функция от scikits.timeseries.lib.moving_funcs подмодуля от SciKits (дополнительные инструментарии, что дополнительный SciPy) лучшие иски формулировка Вашего вопроса.


Вычислить экспоненциальное сглаживание Ваших данных с фактором сглаживания alpha (это (1 - alpha) в терминах Википедии):

>>> alpha = 0.5
>>> assert 0 < alpha <= 1.0
>>> av = sum(alpha**n.days * iq 
...     for n, iq in map(lambda (day, iq), today=max(days): (today-day, iq), 
...         sorted(zip(days, IQ), key=lambda p: p[0], reverse=True)))
95.0

Вышеупомянутое не симпатично, поэтому давайте осуществим рефакторинг его немного:

from collections import namedtuple
from operator    import itemgetter

def smooth(iq_data, alpha=1, today=None):
    """Perform exponential smoothing with factor `alpha`.

    Time period is a day.
    Each time period the value of `iq` drops `alpha` times.
    The most recent data is the most valuable one.
    """
    assert 0 < alpha <= 1

    if alpha == 1: # no smoothing
        return sum(map(itemgetter(1), iq_data))

    if today is None:
        today = max(map(itemgetter(0), iq_data))

    return sum(alpha**((today - date).days) * iq for date, iq in iq_data)

IQData = namedtuple("IQData", "date iq")

if __name__ == "__main__":
    from datetime import date

    days = [date(2008,1,1), date(2008,1,2), date(2008,1,7)]
    IQ = [110, 105, 90]
    iqdata = list(map(IQData, days, IQ))
    print("\n".join(map(str, iqdata)))

    print(smooth(iqdata, alpha=0.5))

Пример:

$ python26 smooth.py
IQData(date=datetime.date(2008, 1, 1), iq=110)
IQData(date=datetime.date(2008, 1, 2), iq=105)
IQData(date=datetime.date(2008, 1, 7), iq=90)
95.0
20
ответ дан 29 November 2019 в 03:50
поделиться

Я немного погуглил и нашел следующий пример кода ( http://osdir.com/ml/python.matplotlib.general/2005-04/msg00044.html ):

def ema(s, n):
    """
    returns an n period exponential moving average for
    the time series s

    s is a list ordered from oldest (index 0) to most
    recent (index -1)
    n is an integer

    returns a numeric array of the exponential
    moving average
    """
    s = array(s)
    ema = []
    j = 1

    #get n sma first and calculate the next n period ema
    sma = sum(s[:n]) / n
    multiplier = 2 / float(1 + n)
    ema.append(sma)

    #EMA(current) = ( (Price(current) - EMA(prev) ) x Multiplier) + EMA(prev)
    ema.append(( (s[n] - sma) * multiplier) + sma)

    #now calculate the rest of the values
    for i in s[n+1:]:
        tmp = ( (i - ema[j]) * multiplier) + ema[j]
        j = j + 1
        ema.append(tmp)

    return ema
10
ответ дан Joe Holloway 29 November 2019 в 03:50
поделиться

Мой Python немного ржав (любой может не стесняться редактировать этот код для создания исправлений, если я испортил синтаксис так или иначе), но здесь идет....

def movingAverageExponential(values, alpha, epsilon = 0):

   if not 0 < alpha < 1:
      raise ValueError("out of range, alpha='%s'" % alpha)

   if not 0 <= epsilon < alpha:
      raise ValueError("out of range, epsilon='%s'" % epsilon)

   result = [None] * len(values)

   for i in range(len(result)):
       currentWeight = 1.0

       numerator     = 0
       denominator   = 0
       for value in values[i::-1]:
           numerator     += value * currentWeight
           denominator   += currentWeight

           currentWeight *= alpha
           if currentWeight < epsilon: 
              break

       result[i] = numerator / denominator

   return result

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

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

(ПРИМЕЧАНИЕ СТОРОНЫ: если бы я использовал язык кроме Python, то я создал бы полноразмерный пустой массив сначала и затем заполнил бы его назад-порядок, так, чтобы я не должен был инвертировать его в конце. Но я не думаю, что можно объявить большой пустой массив в Python. И в списках Python, добавление является намного менее дорогим, чем предварительное ожидание, которое является, почему я создал список в обратном порядке. Исправьте меня, если я неправ.)

'альфа-' аргументом является фактор затухания на каждом повторении. Например, при использовании альфы 0,5 затем сегодняшнее значение скользящего среднего значения состояло бы из следующих взвешенных значений:

today:        1.0
yesterday:    0.5
2 days ago:   0.25
3 days ago:   0.125
...etc...

, Конечно, если у Вас есть огромный массив значений, значения от десять или пятнадцать дней назад не будут способствовать очень сегодняшнему взвешенному среднему. Аргумент 'эпсилона' позволяет Вам установить предел, ниже которого Вы прекратите заботиться о старых значениях (так как их вклад в сегодняшнее значение будет незначителен).

Вы вызвали бы функцию что-то вроде этого:

result = movingAverageExponential(values, 0.75, 0.0001)
5
ответ дан jfs 29 November 2019 в 03:50
поделиться

Я не знаю Python, но для усредняющей части вы имеете в виду экспоненциально затухающий фильтр нижних частот в форме

y_new = y_old + (input - y_old)*alpha

где alpha = dt / tau, dt = временной шаг фильтр, тау = постоянная времени фильтра? (Форма переменной-временного шага выглядит следующим образом, просто обрезайте dt / tau, чтобы она не превышала 1,0)

y_new = y_old + (input - y_old)*dt/tau

Если вы хотите отфильтровать что-то вроде даты, убедитесь, что вы преобразовали в плавающее количество точек, например, # секунд с 1 января 1970 года.

5
ответ дан Jason S 29 November 2019 в 03:50
поделиться

Быстрый способ (скопированный из здесь ) следующий:

def ExpMovingAverage(values, window):
    """ Numpy implementation of EMA
    """
    weights = np.exp(np.linspace(-1., 0., window))
    weights /= weights.sum()
    a =  np.convolve(values, weights, mode='full')[:len(values)]
    a[:window] = a[window]
    return a
1
ответ дан silgon 29 November 2019 в 03:50
поделиться

Может быть самым коротким:

#Specify decay in terms of span
#data_series should be a DataFrame

ema=data_series.ewm(span=5, adjust=False).mean()

0
ответ дан 29 November 2019 в 03:50
поделиться

проще, с помощью панд

def EMA(tw):
    for x in tw:
        data["EMA{}".format(x)] = data['close'].ewm(span=x, adjust=False).mean()
        EMA([10,50,100])
0
ответ дан 29 November 2019 в 03:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: