Es scheint keine Funktion zu geben, die einfach den gleitenden Durchschnitt für Numpy / Scipy berechnet, was zu verschlungenen Lösungen führt .
Meine Frage ist zweifach:
- Was ist der einfachste Weg, um einen gleitenden Durchschnitt mit numpy (richtig) zu implementieren?
- Gibt es einen guten Grund, die Batterien in diesem Fall nicht zu verwenden, da dies nicht trivial und fehleranfällig erscheint ?
python
numpy
scipy
time-series
moving-average
Goncalopp
quelle
quelle
Antworten:
Wenn Sie nur eine einfache wollen nicht gewichteten Durchschnitt bewegen, können Sie leicht implementieren es mit
np.cumsum
, wassein kann ,ist schneller als FFT basierte Methoden:BEARBEITEN Eine von Bean im Code entdeckte falsche Indizierung wurde korrigiert. BEARBEITEN
Die Antwort lautet also: Es ist wirklich einfach zu implementieren, und vielleicht ist Numpy bereits ein wenig aufgebläht mit speziellen Funktionen.
quelle
ret[n:] -= ret[:-n]
ist nicht das gleiche wieret[n:] = ret[n:] - ret[:-n]
. Ich habe den Code in dieser Antwort korrigiert. Edit: Nein, jemand anderes hat mich einfach geschlagen.Das Fehlen einer bestimmten domänenspezifischen Funktion durch NumPy ist möglicherweise auf die Disziplin und die Treue des Kernteams zur Hauptanweisung von NumPy zurückzuführen: Bereitstellung eines N-dimensionalen Array-Typs sowie Funktionen zum Erstellen und Indizieren dieser Arrays. Wie viele grundlegende Ziele ist auch dieses nicht klein, und NumPy macht es hervorragend.
Das (viel) größere SciPy enthält eine viel größere Sammlung domänenspezifischer Bibliotheken ( von SciPy-Entwicklern als Unterpakete bezeichnet) - zum Beispiel numerische Optimierung ( Optimierung ), Signalverarbeitung ( Signal ) und Integralrechnung ( Integration ).
Ich vermute, dass die Funktion, nach der Sie suchen, in mindestens einem der SciPy-Unterpakete enthalten ist ( scipy.signal vielleicht). Ich würde jedoch zuerst in der Sammlung der SciPy-Scikits nachsehen , die relevanten Scikits identifizieren und dort nach der interessierenden Funktion suchen.
Scikits sind unabhängig entwickelte Pakete, die auf NumPy / SciPy basieren und auf eine bestimmte technische Disziplin ausgerichtet sind (z. B. Scikits-Image , Scikits-Learn usw.). Einige davon waren (insbesondere das großartige OpenOpt für die numerische Optimierung) hoch angesehen. reife Projekte lange bevor sie sich für die relativ neue Rubrik Scikits entschieden haben . Auf der Scikits- Homepage wurden oben etwa 30 solcher Scikits aufgeführt , von denen sich jedoch mindestens einige nicht mehr in der aktiven Entwicklung befinden.
Das Befolgen dieses Ratschlags würde Sie zu Scikits-Zeitreihen führen ; Dieses Paket befindet sich jedoch nicht mehr in der aktiven Entwicklung. In der Tat Pandas geworden, AFAIK, die de facto NumPy Zeitreihe Bibliothek -basierte.
Pandas verfügt über mehrere Funktionen, mit denen ein gleitender Durchschnitt berechnet werden kann . Das einfachste davon ist wahrscheinlich rollendes Mittel , das Sie wie folgt verwenden:
Rufen Sie jetzt einfach die Funktion rolling_mean auf, die das Series-Objekt und eine Fenstergröße übergibt , die in meinem Beispiel unten 10 Tage beträgt .
Vergewissern Sie sich, dass es funktioniert hat - z. B. verglichen Sie die Werte 10 bis 15 in der Originalserie mit der neuen Serie, die mit dem rollierenden Mittelwert geglättet wurde
Die Funktion rolling_mean sowie etwa ein Dutzend anderer Funktionen sind in der Pandas-Dokumentation informell unter den Funktionen für das Verschieben von Fenstern in der Rubrik zusammengefasst . Eine zweite verwandte Gruppe von Funktionen in Pandas wird als exponentiell gewichtete Funktionen bezeichnet (z. B. ewma , das den exponentiell gleitenden gewichteten Durchschnitt berechnet). Die Tatsache, dass diese zweite Gruppe nicht in der ersten Gruppe enthalten ist ( Funktionen zum Verschieben von Fenstern ), liegt möglicherweise daran, dass die exponentiell gewichteten Transformationen nicht auf einem Fenster fester Länge beruhen
quelle
Ein einfacher Weg, dies zu erreichen, ist die Verwendung von
np.convolve
. Die Idee dahinter ist, die Art und Weise, wie die diskrete Faltung berechnet wird, zu nutzen und daraus einen rollierenden Mittelwert zurückzugeben . Dies kann durch Falten mit einer Folge vonnp.ones
einer Länge erfolgen, die der gewünschten Schiebefensterlänge entspricht.Dazu könnten wir folgende Funktion definieren:
Diese Funktion übernimmt die Faltung der Sequenz
x
und eine Sequenz von Längenw
. Beachten Sie, dass das gewählte somode
istvalid
, dass das Faltungsprodukt nur für Punkte angegeben wird, an denen sich die Sequenzen vollständig überlappen.Einige Beispiele:
Für einen gleitenden Durchschnitt mit einem Fenster Länge hätten
2
wir:Und für ein Fenster von Länge
4
:Wie funktioniert das
convolve
?Schauen wir uns die Art und Weise, wie die diskrete Faltung berechnet wird, genauer an. Die folgende Funktion zielt darauf ab, die Art und Weise der
np.convolve
Berechnung der Ausgabewerte zu replizieren :Was für dasselbe Beispiel oben auch ergeben würde:
Was also bei jedem Schritt getan wird, ist, das innere Produkt zwischen dem Array von Einsen und dem aktuellen Fenster zu nehmen . In diesem Fall ist die Multiplikation mit
np.ones(w)
überflüssig, da wirsum
die Sequenz direkt nehmen .Unten sehen Sie ein Beispiel dafür, wie die ersten Ausgaben so berechnet werden, dass sie etwas klarer sind. Nehmen wir an, wir wollen ein Fenster von
w=4
:Und die folgende Ausgabe würde wie folgt berechnet:
Und so weiter, indem ein gleitender Durchschnitt der Sequenz zurückgegeben wird, sobald alle Überlappungen durchgeführt wurden.
quelle
mode='valid'
kann das durch ersetzt werden'same'
. Nur in diesem Fall werden Kantenpunkte gegen Null verschoben.Hier finden Sie verschiedene Möglichkeiten, dies zusammen mit einigen Benchmarks. Die besten Methoden sind Versionen, die optimierten Code aus anderen Bibliotheken verwenden. Die
bottleneck.move_mean
Methode ist wahrscheinlich rundum am besten. Derscipy.convolve
Ansatz ist auch sehr schnell, erweiterbar und syntaktisch und konzeptionell einfach, lässt sich jedoch nicht gut für sehr große Fensterwerte skalieren. Dienumpy.cumsum
Methode ist gut, wenn Sie einen reinennumpy
Ansatz benötigen .Hinweis: Einige davon (z. B.
bottleneck.move_mean
) sind nicht zentriert und verschieben Ihre Daten.Timing, kleines Fenster (n = 3)
Timing, großes Fenster (n = 1001)
Speicher, kleines Fenster (n = 3)
Speicher, großes Fenster (n = 1001)
quelle
Diese Antwort mit Pandas wird von oben angepasst, da sie
rolling_mean
nicht mehr Teil von Pandas istRufen Sie jetzt einfach die Funktion
rolling
auf dem Datenrahmen mit einer Fenstergröße auf, die in meinem Beispiel unten 10 Tage beträgt.quelle
Ich bin der Meinung, dass dies mit Engpässen leicht gelöst werden kann
Siehe Basisbeispiel unten:
Dies ergibt einen Bewegungsmittelwert entlang jeder Achse.
"mm" ist das gleitende Mittel für "a".
"Fenster" ist die maximale Anzahl von Einträgen, die für den gleitenden Mittelwert berücksichtigt werden müssen.
"min_count" ist die minimale Anzahl von Einträgen, die für den gleitenden Mittelwert berücksichtigt werden müssen (z. B. für das erste Element oder wenn das Array Nanowerte hat).
Der gute Teil ist, dass Engpass beim Umgang mit Nanowerten hilft und auch sehr effizient ist.
quelle
Wenn Sie die Randbedingungen sorgfältig berücksichtigen möchten ( Mittelwert nur aus verfügbaren Elementen an den Kanten berechnen ), reicht die folgende Funktion aus.
quelle
Probieren Sie diesen Code aus. Ich denke, es ist einfacher und macht den Job. Lookback ist das Fenster des gleitenden Durchschnitts.
In der habe
Data[i-lookback:i, 0].sum()
ich mich0
auf die erste Spalte des Datensatzes bezogen, aber Sie können eine beliebige Spalte einfügen, falls Sie mehr als eine Spalte haben.quelle
Ich wollte eigentlich ein etwas anderes Verhalten als die akzeptierte Antwort. Ich habe einen Feature-Extraktor für den gleitenden Durchschnitt für eine
sklearn
Pipeline erstellt, daher musste die Ausgabe des gleitenden Durchschnitts dieselbe Dimension wie die Eingabe haben. Ich möchte, dass der gleitende Durchschnitt davon ausgeht, dass die Reihe konstant bleibt, dh ein gleitender Durchschnitt von[1,2,3,4,5]
mit Fenster 2 würde ergeben[1.5,2.5,3.5,4.5,5.0]
.Für Spaltenvektoren (mein Anwendungsfall) erhalten wir
Und für Arrays
Natürlich muss man keine konstanten Werte für die Polsterung annehmen, aber dies sollte in den meisten Fällen ausreichend sein.
quelle
talib enthält ein einfaches gleitendes Durchschnittswerkzeug sowie andere ähnliche Mittelungswerkzeuge (dh einen exponentiellen gleitenden Durchschnitt). Im Folgenden wird die Methode mit einigen anderen Lösungen verglichen.
Eine Einschränkung ist, dass das Reale Elemente von haben muss
dtype = float
. Andernfalls wird der folgende Fehler ausgelöstquelle
Hier ist eine schnelle Implementierung mit numba (beachten Sie die Typen). Beachten Sie, dass es Nans enthält, die verschoben wurden.
quelle
quelle
Ich verwende entweder die Lösung der akzeptierten Antwort , die leicht modifiziert wurde, um die gleiche Länge für die Ausgabe wie die Eingabe zu haben, oder
pandas
die Version, wie in einem Kommentar einer anderen Antwort erwähnt. Ich fasse beide hier mit einem reproduzierbaren Beispiel zum späteren Nachschlagen zusammen:quelle
Wenn Sie die unten stehende Lösung mit der Lösung vergleichen, die Cumum of Numpy verwendet, dauert diese fast die Hälfte der Zeit . Dies liegt daran, dass nicht das gesamte Array durchlaufen werden muss, um die Cumsum und dann die gesamte Subtraktion durchzuführen. Darüber hinaus kann das Cumsum " gefährlich " sein, wenn das Array riesig und die Anzahl riesig ist ( möglicher Überlauf ). Natürlich besteht auch hier die Gefahr, aber zumindest werden nur die wesentlichen Zahlen zusammengefasst.
quelle