سؤال

لدي مجموعة من التواريخ و القياس على كل من تلك التواريخ.أود لحساب المتوسط المتحرك الأسي لكل من التواريخ.لا أحد يعرف كيفية القيام بذلك ؟

أنا جديدة على الثعبان.لا يبدو أن المتوسطات في مستوى بيثون المكتبة ، الذي يبدو لي غريبا.ربما أنا لا أبحث في المكان المناسب.

وذلك نظرا البرمجية التالية كيف يمكن لي حساب نقل متوسط من الذكاء نقاط تقويم التواريخ ؟

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

(ربما هناك طريقة أفضل هيكل البيانات ، أي نصيحة سيكون موضع تقدير)

هل كانت مفيدة؟

المحلول

تحرير:يبدو أن mov_average_expw() وظيفة من scikits.timeseries.lib.moving_funcs submodule من 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

أنا دائما حساب ايماس مع الباندا:

هنا هو مثال على كيفية القيام بذلك:

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)

معلومات أكثر حول الباندا EWMA:

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

بلدي الثعبان قليلا صدئ (أي شخص يمكن أن لا تتردد في تعديل هذه التعليمة البرمجية إلى إجراء التصحيحات إذا لقد افسدت الجملة بطريقة أو بأخرى) ، ولكن هنا يذهب....

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

هذه الوظيفة يتحرك إلى الخلف من نهاية القائمة إلى بداية حساب المتوسط المتحرك الأسي لكل قيمة من خلال العمل الخلف حتى وزن معامل عنصر أقل من معين ابسيلون.

في نهاية الدالة ، عكس القيم قبل أن يعود قائمة (بحيث انهم في الترتيب الصحيح للحصول على المتصل).

(ملاحظة جانبية:إذا كنت تستخدم لغة أخرى غير بيثون ، أود إنشاء الحجم الكامل مجموعة فارغة أولا ثم ملء الوراء النظام, حتى لا تضطر إلى عكس ذلك في نهاية المطاف.ولكن أنا لا أعتقد أنك يمكن أن تعلن مجموعة كبيرة فارغة في بيثون.و في بيثون قوائم إلحاق هو أقل تكلفة بكثير من أن يتبع ، الذي هو السبب في أنني بنيت القائمة في ترتيب عكسي.يرجى تصحيح لي إذا كنت مخطئا.)

إن 'ألفا' الحجة هو تسوس عامل على كل التكرار.على سبيل المثال, إذا كنت تستخدم ألفا من 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)

في 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

أنا لا أعرف بيثون ، ولكن بمعدل جزء تعني بشكل كبير المتحللة مرشح تمرير منخفض من شكل

y_new = y_old + (input - y_old)*alpha

حيث ألفا = dt/تاو ، dt = على timestep من مرشح ، tau = وقت ثابت من مرشح ؟ (المتغير-timestep شكل هذا هو كما يلي, فقط احجز dt/تاو أن لا يكون أكثر من 1.0)

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

إذا كنت ترغب في تصفية ما يشبه التاريخ ، تأكد من تحويل إلى نقطة عائمة الكمية مثل # ثوان منذ 1 يناير 1970.

يمكنك أيضا استخدام SciPy تصفية الأسلوب لأن EMA هو IIR التصفية.هذا سوف يكون لها فائدة من أن ما يقرب من 64 مرات أسرع كما تقاس على النظام باستخدام مرةلا على مجموعات البيانات الكبيرة بالمقارنة مع تعداد() النهج.

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)

وجدت رمز أعلاه مقتطف من قبل @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's 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()))

(حيث دبوس.قراءة() تنتج القيمة التالية أود أن تستهلك).

هنا عينة بسيطة لقد عملت على أساس 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

طريقة سريعة (نسخ-لصق من هنا) هو التالي:

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

أنا باستخدام قائمة معدل تسوس كمدخلات.آمل أن يكون هذا القليل وظيفة مع سطرين فقط قد تساعدك هنا بالنظر العميق العودية ليست مستقرة في بيثون.

def expma(aseries, ratio):
    return sum([ratio*aseries[-x-1]*((1-ratio)**x) for x in range(len(aseries))])
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top