Подтвердить что ты не робот

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

У меня есть диапазон дат и измерение в каждую из этих дат. Я бы хотел рассчитать экспоненциальную скользящую среднюю для каждой из дат. Кто-нибудь знает, как это сделать?

Я новичок в python. Не похоже, что средние значения встроены в стандартную библиотеку python, которая кажется мне немного странной. Может быть, я не смотрю в нужное место.

Итак, учитывая следующий код, как я могу рассчитать скользящее средневзвешенное значение точек IQ для календарных дат?

from datetime import date
days = [date(2008,1,1), date(2008,1,2), date(2008,1,7)]
IQ = [110, 105, 90]

(возможно, лучший способ структурирования данных, любой совет будет оценен)

4b9b3361

Ответ 1

EDIT: Кажется, что 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

Ответ 2

Я сделал несколько поисковых запросов, и я нашел следующий пример кода (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

Ответ 3

Я всегда рассчитываю EMA с Pandas:

Вот пример, как это сделать:

import pandas as pd
import numpy as np

def ema(values, period):
    values = np.array(values)
    return pd.ewma(values, span=period)[-1]

values = [9, 5, 10, 16, 5]
period = 5

print ema(values, period)

Дополнительная информация о Pandas EWMA:

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.ewma.html

Ответ 4

Мой 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

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

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

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

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

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

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

Вы вызываете функцию примерно так:

result = movingAverageExponential(values, 0.75, 0.0001)

Ответ 5

В примерах matplotlib.org(http://matplotlib.org/examples/pylab_examples/finance_work2.html) представлен один хороший пример функции экспоненциального скользящего среднего (EMA) с использованием numpy:

def moving_average(x, n, type):
    x = np.asarray(x)
    if type=='simple':
        weights = np.ones(n)
    else:
        weights = np.exp(np.linspace(-1., 0., n))

    weights /= weights.sum()

    a =  np.convolve(x, weights, mode='full')[:len(x)]
    a[:n] = a[n]
    return a

Ответ 6

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

y_new = y_old + (input - y_old)*alpha

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

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

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

Ответ 7

Вы также можете использовать метод фильтра SciPy, потому что EMA является фильтром IIR. Это будет иметь преимущество примерно в 64 раза быстрее, чем измеряется в моей системе, используя timeit для больших наборов данных по сравнению с методом enumerate().

import numpy as np
from scipy.signal import lfilter

x = np.random.normal(size=1234)
alpha = .1 # smoothing coefficient
zi = [x[0]] # seed the filter state with first value
# filter can process blocks of continuous data if <zi> is maintained
y, zi = lfilter([1.-alpha], [1., -alpha], x, zi=zi)

Ответ 8

Я нашел приведенный выше фрагмент кода by @earino довольно полезным - но мне нужно было что-то, что могло бы непрерывно сглаживать поток значений - поэтому я реорганизовал его на это:

def exponential_moving_average(period=1000):
    """ Exponential moving average. Smooths the values in v over ther period. Send in values - at first it'll return a simple average, but as soon as it gahtered 'period' values, it'll start to use the Exponential Moving Averge to smooth the values.
    period: int - how many values to smooth over (default=100). """
    multiplier = 2 / float(1 + period)
    cum_temp = yield None  # We are being primed

    # Start by just returning the simple average until we have enough data.
    for i in xrange(1, period + 1):
        cum_temp += yield cum_temp / float(i)

    # Grab the timple avergae
    ema = cum_temp / period

    # and start calculating the exponentially smoothed average
    while True:
        ema = (((yield ema) - ema) * multiplier) + ema

и я использую его следующим образом:

def temp_monitor(pin):
    """ Read from the temperature monitor - and smooth the value out. The sensor is noisy, so we use exponential smoothing. """
    ema = exponential_moving_average()
    next(ema)  # Prime the generator

    while True:
        yield ema.send(val_to_temp(pin.read()))

(где pin.read() создает следующее значение, которое я хотел бы использовать).

Ответ 9

Вот простой пример, который я разработал на основе http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages

Обратите внимание, что в отличие от таблицы, я не вычисляю SMA, и я не жду, чтобы создать EMA после 10 выборок. Это означает, что мои значения немного отличаются друг от друга, но если вы его нарисуете, то это будет точно после 10 образцов. Во время первых 10 выборок EMA, которые я вычисляю, соответствующим образом сглаживается.

def emaWeight(numSamples):
    return 2 / float(numSamples + 1)

def ema(close, prevEma, numSamples):
    return ((close-prevEma) * emaWeight(numSamples) ) + prevEma

samples = [
22.27, 22.19, 22.08, 22.17, 22.18, 22.13, 22.23, 22.43, 22.24, 22.29,
22.15, 22.39, 22.38, 22.61, 23.36, 24.05, 23.75, 23.83, 23.95, 23.63,
23.82, 23.87, 23.65, 23.19, 23.10, 23.33, 22.68, 23.10, 22.40, 22.17,
]
emaCap = 10
e=samples[0]
for s in range(len(samples)):
    numSamples = emaCap if s > emaCap else s
    e =  ema(samples[s], e, numSamples)
    print e

Ответ 10

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

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

Ответ 11

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

def expma(aseries, ratio):
    return sum([ratio*aseries[-x-1]*((1-ratio)**x) for x in range(len(aseries))])

Ответ 12

проще, используя панд

def EMA(tw):
    for x in tw:
        data["EMA{}".format(x)] = data['close'].ewm(span=x, adjust=False).mean()
        EMA([10,50,100])

Ответ 13

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

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

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