Frage

Ich habe eine Reihe von Daten und eine Messung an jedem dieser Termine. Ich möchte einen exponentiellen gleitenden Durchschnitt für jedes der Daten berechnen. Weiß jemand, wie dies zu tun?

Ich bin neu in Python. Es scheint nicht, dass Mittelwerte in die Standard-Python-Bibliothek gebaut werden, die mich als ein wenig seltsam trifft. Vielleicht an der richtigen Stelle ich bin nicht auf der Suche.

Also, der folgende Code gegeben, wie kann ich den gleitenden gewichteten Durchschnitt der IQ-Punkte für Kalenderdaten berechnen?

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

(es gibt wahrscheinlich einen besseren Weg, um die Daten zu strukturieren, würde jede Beratung geschätzt werden)

War es hilfreich?

Lösung

EDIT: Es scheint, dass mov_average_expw() Funktion von scikits.timeseries.lib.moving_funcs Submodul von SciKits (Add-on-Toolkits, dass Komplement SciPy besser) passt die Formulierung Ihrer Frage.


exponentielle Glättung Ihre Daten mit einem Glättungsfaktor alpha Zur Berechnung (es ist (1 - alpha) in Wikipedias Begriffe):

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

Die oben ist nicht schön, so machen wir es ein wenig Refactoring:

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))

Beispiel:

$ 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

Andere Tipps

Ich habe ein bisschen googeln und ich fand den folgenden Beispielcode ( 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

Ich bin die Berechnung immer EMAs mit Pandas:

Hier ist ein Beispiel, wie es geht:

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)

Mehr Infos über Pandas EWMA:

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

Mein Python ist ein wenig rostig (jeder kann diesen Code fühlen Sie sich frei zu bearbeiten, Korrekturen vorzunehmen, wenn ich habe die Syntax irgendwie vermasselt), aber hier geht ....

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

verschiebt diese Funktion zurück, von dem Ende der Liste auf den Beginn für jeden Wert für den exponentiell gleitenden Durchschnitt berechnet wird, indem rückwärts zu arbeiten, bis der Gewichtungskoeffizient für ein Element kleiner ist als das gegebene epsilon.

Am Ende der Funktion, sie die Werte umkehrt, bevor die Liste zurückkehrt (so dass sie in der richtigen Reihenfolge für die Anrufer sind).

(Randbemerkung: wenn ich eine andere Sprache als Python verwendet, würde ich zuerst ein Full-Size leeres Array erstellen und dann fülle rückwärts Ordnung, so dass ich es nicht am Ende umkehren würde. aber ich glaube nicht, dass Sie ein großes leeres Array in python erklären können. Und in python-Listen, Anfügen ist viel weniger teuer als das Voranstellen, weshalb ich die Liste in umgekehrter Reihenfolge gebaut. Bitte korrigieren Sie mich, wenn ich falsch bin.)

Das ‚Alpha‘ Argument ist der Dämpfungsfaktor bei jeder Iteration. Zum Beispiel wäre, wenn Sie einen Alpha von 0,5 verwendet wird, dann heutige gleitender Mittelwert der folgenden gewichteten Werte zusammen:

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

Natürlich, wenn Sie eine riesige Auswahl an Werten haben, die Werte von zehn oder fünfzehn Tagen wird nicht sehr viel zu der heutigen gewichteter Durchschnitt beitragen. Das ‚epsilon‘ Argument kann Sie einen Cutoff-Punkt festgelegt, unter dem Sie aufhören zu alten Werten sorgen (da ihr Beitrag Wert auf dem heutigen unbedeutend sein wird).

Sie würden die Funktion so etwas wie folgt aufrufen:

result = movingAverageExponential(values, 0.75, 0.0001)

In matplotlib.org Beispiele ( http://matplotlib.org/examples/pylab_examples/finance_work2. html ) ist ein gutes Beispiel für Exponential bereitgestellt Moving Average (EMA) Funktion 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

Ich weiß nicht, Python, aber für den Mittelungsteil, meinen Sie ein exponentiell abfallenden Tiefpassfilter der Form

y_new = y_old + (input - y_old)*alpha

wobei alpha = dt / tau, dt = der Zeitschritt des Filters, tau = die Zeitkonstante des Filters? (Variable Zeitschritt Form hierfür ist wie folgt, nur befestigen dt / tau nicht mehr als 1,0 sein)

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

Wenn Sie so etwas wie ein Datum filtern mögen, stellen Sie sicher, dass Sie auf eine Floating-Point-Menge wie Anzahl der Sekunden seit dem 1. Januar 1970 konvertieren.

Sie können auch die SciPy Filtermethode verwenden, da die EMA ein IIR-Filter ist. Dies hat den Vorteil, etwa 64-mal schneller sein als auf meinem System gemessen mit timeit auf großen Mengen Daten im Vergleich zu dem aufzuzuzählen () Ansatz.

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)

fand ich den obigen Code-Schnipsel von @earino ziemlich nützlich - aber ich brauchte etwas, das kontinuierlich einen Strom von Werten glätten könnte - so ich Refactoring es dazu:

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

und ich verwende es wie folgt aus:

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()))

(wobei pin.read () den nächsten Wert Ich mag würde konsumieren).

Hier ist ein einfaches Beispiel I aufgearbeitet basierend auf http: // stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages

Beachten Sie, dass im Gegensatz zu in ihrer Tabelle, ich die SMA nicht berechnen, und ich warte nicht die EMA nach 10 Proben zu erzeugen. Das bedeutet, meine Werte unterscheiden sich geringfügig, aber wenn Sie es Diagramm, folgt genau nach 10 Proben. Während der ersten 10 Proben wird die EMA I berechnen entsprechend geglättet.

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

Eine schnelle Art und Weise (copy kleistert von hier ) ist die folgende:

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

Ich verwende eine Liste und eine Rate des Zerfalls als Eingänge. Ich hoffe, diese kleine Funktion mit nur zwei Linien hier, um Ihnen helfen kann, wenn man bedenkt tiefe Rekursion in Python nicht stabil ist.

def expma(aseries, ratio):
    return sum([ratio*aseries[-x-1]*((1-ratio)**x) for x in range(len(aseries))])
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top