Править: Это кажется этим 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
Я немного погуглил и нашел следующий пример кода ( 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
Мой 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)
Я не знаю 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 года.
Быстрый способ (скопированный из здесь ) следующий:
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
Может быть самым коротким:
#Specify decay in terms of span
#data_series should be a DataFrame
ema=data_series.ewm(span=5, adjust=False).mean()
проще, с помощью панд
def EMA(tw):
for x in tw:
data["EMA{}".format(x)] = data['close'].ewm(span=x, adjust=False).mean()
EMA([10,50,100])