Wednesday 18 January 2017

Effizient Gleitender Mittelwertfilter

Ich habe im Wesentlichen ein Array von Werten wie folgt: Das obige Array ist oversimplified, Im sammeln 1 Wert pro Millisekunde in meinem realen Code und ich muss die Ausgabe auf einem Algorithmus, den ich schrieb, um die nächste Peak vor einem Zeitpunkt zu finden verarbeiten. Meine Logik schlägt fehl, weil in meinem Beispiel oben 0.36 die wahre Spitze ist, aber mein Algorithmus würde rückwärts schauen und sehen die sehr letzte Zahl 0.25 als die Spitze, als theres eine Abnahme zu 0.24 vor ihm. Das Ziel ist, diese Werte zu nehmen und einen Algorithmus auf sie, die glätten sie ein wenig, so dass ich mehr lineare Werte. (Dh: Id wie meine Ergebnisse curvy, nicht jaggedy) Ive wurde gesagt, um einen exponentiellen gleitenden durchschnittlichen Filter auf meine Werte anzuwenden. Wie kann ich dies tun Es ist wirklich schwer für mich, mathematische Gleichungen zu lesen, gehe ich viel besser mit Code. Wie verarbeite ich Werte in meinem Array, die Anwendung einer exponentiellen gleitenden Durchschnittsberechnung, um sie herauszufordern, um einen exponentiellen gleitenden Durchschnitt zu berechnen. Müssen Sie einige Zustand zu halten und Sie benötigen einen Tuning-Parameter. Dies erfordert eine kleine Klasse (vorausgesetzt, Sie verwenden Java 5 oder höher): Instantiate mit dem Decay-Parameter, die Sie wollen (kann Abstimmung sollte zwischen 0 und 1) und dann mit Average () zu filtern. Beim Lesen einer Seite auf einige mathematische Rekursion, alles, was Sie wirklich wissen müssen, wenn Sie es in Code ist, dass Mathematiker gerne Indizes in Arrays und Sequenzen mit Indizes schreiben. (Theyve einige andere Anmerkungen außerdem, die nicht helfen.) Jedoch ist die EMA ziemlich einfach, da Sie nur an einen alten Wert erinnern müssen, der keine komplizierten Zustandarrays erfordert. Beantwortet Feb 8 12 at 20:42 TKKocheran: Ziemlich viel. Isn39t es schön, wenn die Dinge einfach sein können (Wenn Sie mit einer neuen Sequenz beginnen, erhalten Sie einen neuen Mittelwert.) Beachten Sie, dass die ersten paar Begriffe in der durchschnittlichen Sequenz wird ein bisschen durch Randeffekte springen, aber Sie erhalten die mit anderen gleitenden Durchschnitten auch. Allerdings ist ein guter Vorteil, dass Sie die gleitende durchschnittliche Logik in die Mittelung einwickeln und experimentieren können, ohne den Rest des Programms zu viel zu stören. Ndash Donal Fellows Ich habe eine harte Zeit, Ihre Fragen zu verstehen, aber ich werde versuchen, trotzdem zu beantworten. 1) Wenn Ihr Algorithmus 0,25 statt 0,36 gefunden hat, dann ist es falsch. Es ist falsch, weil es eine monotone Zunahme oder Abnahme (das ist immer nach oben oder immer nach unten). Wenn Sie ALLE Ihre Daten nicht klassifizieren, sind Ihre Datenpunkte - wie Sie sie darstellen - nichtlinear. Wenn Sie wirklich den maximalen Wert zwischen zwei Zeitpunkten finden wollen, dann schneiden Sie Ihr Array von tmin zu tmax und finden Sie das Maximum dieses Unterarrays. 2) Nun ist das Konzept der gleitenden Durchschnitte sehr einfach: vorstellen, dass ich die folgende Liste haben: 1.4, 1.5, 1.4, 1.5, 1.5. Ich kann es glätten, indem ich den Durchschnitt von zwei Zahlen: 1.45, 1.45, 1.45, 1.5. Beachten Sie, dass die erste Zahl ist der Durchschnitt von 1,5 und 1,4 (zweite und erste Zahlen) die zweite (neue Liste) ist der Durchschnitt von 1,4 und 1,5 (dritte und zweite alte Liste) die dritte (neue Liste) der Durchschnitt von 1,5 und 1,4 (Vierte und dritte), und so weiter. Ich könnte es Zeitraum drei oder vier gemacht haben, oder n. Beachten Sie, wie die Daten viel glatter sind. Ein guter Weg, um zu sehen, gleitende Durchschnitte bei der Arbeit ist, gehen Sie zu Google Finance, wählen Sie eine Aktie (versuchen Tesla Motors ziemlich volatil (TSLA)) und klicken Sie auf Technische Daten am unteren Rand des Diagramms. Wählen Sie Moving Average mit einer bestimmten Periode und Exponential gleitenden Durchschnitt, um ihre Differenzen zu vergleichen. Exponentielle gleitende Durchschnitt ist nur eine weitere Ausarbeitung dieser, aber Gewichte die älteren Daten weniger als die neuen Daten ist dies ein Weg, um die Glättung nach hinten auszugleichen. Bitte lesen Sie den Wikipedia-Eintrag. Also, dies ist eher ein Kommentar als eine Antwort, aber die kleine Kommentar-Box war nur zu klein. Viel Glück. Wenn Sie Probleme mit der Mathematik haben, könnten Sie mit einem einfachen gleitenden Durchschnitt statt exponentiell gehen. Also die Ausgabe erhalten Sie die letzten x-Terme durch x geteilt werden. Ungetestetes Pseudocode: Beachten Sie, dass Sie die Anfangs - und Endteile der Daten behandeln müssen, da deutlich, dass Sie die letzten 5 Ausdrücke nicht durchschnittlich sind, wenn Sie auf Ihrem 2. Datenpunkt sind. Außerdem gibt es effizientere Methoden, diesen gleitenden Durchschnitt (sum sum - älteste neueste) zu berechnen, aber dies ist, um das Konzept von dem, was passiert, zu bekommen. Ich habe vor kurzem über die Fortschritte in der Antwort auf diesen Beitrag gelernt. Und frage mich, wie ich sie verwenden, um einen gleitenden Durchschnitt Filter effizienter als das, was ich in diesem Beitrag vorgeschlagen (mit Faltungs-Filter) zu berechnen. Dies ist, was ich bisher habe. Es nimmt eine Ansicht des ursprünglichen Arrays dann rollt es um die notwendige Menge und summiert die Kernel-Werte, um den Durchschnitt zu berechnen. Ich bin mir bewusst, dass die Kanten nicht richtig gehandhabt werden, aber danach kann ich mich darum kümmern. Gibt es einen besseren und schnelleren Weg Das Ziel ist es, große Gleitkomma-Arrays bis zu 5000x5000 x 16 Schichten in der Größe zu filtern, eine Aufgabe, die scipy. ndimage. filters. convolve ist ziemlich langsam auf. Beachten Sie, dass ich nach 8-Nachbar-Konnektivität suche, dh ein 3x3-Filter nimmt den Durchschnitt von 9 Pixeln (8 um das Brennpixel) und weist diesen Wert dem Pixel im neuen Bild zu. EDIT Klarstellung, wie ich diese Arbeit sehen: Verwenden Sie stridetricks, um ein Array wie 0,1,2,1,2,3,2,3,4 generieren. Die der oberen Zeile des Filterkerns entspricht. Rollen Sie entlang der vertikalen Achse, um die mittlere Reihe des Kerns 10,11,12,11,12,13,13,14,15 zu erhalten. Und fügen Sie es auf das Array ich bekam in 1) Wiederholen, um die untere Zeile des Kernels 20,21,22,21,22,23,22,23,24 erhalten. . An diesem Punkt nehme ich die Summe jeder Zeile und dividiere sie durch die Anzahl der Elemente im Filter, wobei mir der Durchschnitt für jedes Pixel, (um 1 Zeile und 1 col verschoben, und mit einigen Merkwürdigkeiten um die Kanten, aber ich kann Kümmere dich darum später). Was ich erhoffte, ist eine bessere Verwendung von stridetricks, um die 9 Werte oder die Summe der Kernel-Elemente direkt, für das gesamte Array zu erhalten, oder dass jemand mich von einer anderen effizienteren Methode überzeugen kann. Fragte am 8. Februar um 18:05 für was sein Wert, heres, wie youd es mit fancy schreitenden Tricks tun. Ich wollte diese Post gestern, sondern wurde von der tatsächlichen Arbeit abgelenkt. ) Paul amp essen beide haben schöne Implementierungen mit verschiedenen anderen Möglichkeiten, dies zu tun. Nur um die Dinge aus der früheren Frage fortzusetzen, dachte ich Id post das N-dimensionale Äquivalent. Sie werden nicht in der Lage, scipy. ndimage Funktionen für 1D-Arrays deutlich zu schlagen. (Scipy. ndimage. uniformfilter sollte schlagen scipy. ndimage. convolve. though) Darüber hinaus, wenn youre versuchen, ein multidimensionales bewegliches Fenster zu erhalten, riskieren Sie, Speicherverwendung zu sprengen, wenn Sie versehentlich eine Kopie des Arrays zu machen. Während das anfängliche rollende Array gerade eine Ansicht in den Gedächtnis Ihres ursprünglichen Arrays ist, bilden alle Zwischenschritte, die das Array kopieren, eine Kopie, die Größenordnungen größer als Ihr ursprüngliches Array ist (dh Lets sagen, dass youre, das mit einem 100x100 ursprünglichen Array arbeitet (Für eine Filtergröße von (3,3)) wird 98x98x3x3, aber verwenden Sie den gleichen Speicher wie das Original. Allerdings werden alle Kopien die Menge an Speicher verwenden, dass eine vollständige 98x98x3x3 Array würde) Grundsätzlich mit verrückt Schreitenden Tricks ist ideal, wenn Sie verschieben Fenster Operationen auf einer einzigen Achse eines ndarray vektorisieren möchten. Es macht es wirklich einfach, Dinge wie eine bewegte Standardabweichung, etc. mit sehr wenig Overhead zu berechnen. Wenn Sie anfangen, dies zu tun entlang mehrerer Achsen, seine mögliche, aber youre in der Regel besser mit mehr spezialisierte Funktionen. (Wie scipy. ndimage etc.) Auf jeden Fall ist heres, wie Sie es tun: Also, was wir bekommen, wenn wir b Rollingwindow (a, filtsize) ist ein 8x8x3x3 Array, das ist eigentlich eine Ansicht in den gleichen Speicher wie das Original 10x10 Array. Wir könnten genauso leicht verschiedene Filtergrößen entlang verschiedener Achsen verwenden oder nur entlang ausgewählter Achsen eines N-dimensionalen Arrays betrieben werden (dh Filzgröße (0,3,0,3) auf einem 4-dimensionalen Array würde uns eine 6-dimensionale Ansicht geben ). Wir können dann eine beliebige Funktion auf die letzte Achse anwenden, um die Dinge in einem sich bewegenden Fenster effektiv zu berechnen. Jedoch, weil waren die Speicherung von temporären Arrays, die viel größer als unsere ursprüngliche Array auf jedem Schritt der Mittelwert (oder std oder was auch immer), das ist überhaupt nicht Speicher effizient Sein auch nicht zu sein, furchtbar schnell, entweder. Das Äquivalent für ndimage ist nur: Dies wird eine Vielzahl von Randbedingungen behandeln, das Unschärfen an Ort und Stelle durchführen, ohne eine temporäre Kopie des Arrays zu benötigen, und sehr schnell sein. Schiebe-Tricks sind eine gute Möglichkeit, eine Funktion auf ein bewegtes Fenster entlang einer Achse anzuwenden, aber theyre nicht ein guter Weg, um es entlang mehrerer Achsen zu tun, in der Regel. Nur meine 0.02, jedenfalls. Sehr gut: Schiebe-Tricks sind eine gute Möglichkeit, eine Funktion auf ein bewegtes Fenster entlang einer Achse anzuwenden, aber sie sind nicht ein guter Weg, um es entlang mehrerer Achsen zu tun, in der Regel. Und natürlich ist Ihre Erklärung der Erinnerung 39blow up39 wichtig. Art der Zusammenfassung aus Ihrer Antwort (zumindest für mich) ist: 39don39t gehen zu weit Angeln, ist der Quarterteed Fang allready in scipy39. Thanks ndash eat Feb 9 11 at 16:37 Vielen Dank, Joe, für diese Antwort. In rollendem Fenster sollte das, wenn nicht hasattr (.): Rollingwindowlastaxis (.) Statt Rolling zurückgeben. Ndash unutbu Ich bin nicht vertraut genug mit Python, um Code für das zu schreiben, aber die beiden besten Möglichkeiten zur Beschleunigung von Windungen ist entweder trennen Sie den Filter oder die Fourier-Transformation verwenden. Getrennter Filter. Faltung ist O (MN), wobei M und N die Anzahl der Pixel in dem Bild bzw. dem Filter sind. Da die durchschnittliche Filterung mit einem 3-mal-3-Kernel dem Filtern zuerst mit einem 3-mal-1-Kernel und dann einem 1-mal-3-Kernel gleichkommt, können Sie (33) 30-Geschwindigkeitsverbesserung durch konsekutive Faltung mit erhalten Zwei 1-d-Kerne (dies wird offensichtlich besser, da der Kernel größer wird). Sie können immer noch in der Lage, Schritt-Tricks hier zu verwenden, natürlich. Fourier-Transformation . Conv (A, B) ist äquivalent zu ifft (fft (A) fft (B)). D. h. eine Faltung im direkten Raum wird eine Multiplikation im Fourierraum, wobei A dein Bild und B dein Filter ist. Da die (elementweise) Multiplikation der Fourier-Transformationen A und B gleich groß ist, ist B ein Array der Größe (A) mit dem Kernel im Zentrum des Bildes und Nullen überall. Um einen 3-mal-3-Kernel in der Mitte eines Arrays zu platzieren, müssen Sie A bis ungerade Größe auffüllen. Abhängig von der Implementierung der Fourier-Transformation kann dies viel schneller sein als die Faltung (und wenn Sie denselben Filter mehrmals anwenden, können Sie fft (B) vorberechnen und weitere 30 Rechenzeit sparen). Antwortete am 9. Februar um 15:27 Für was es wert ist, in python, sind diese in scipy. ndimage. uniformfilter und scipy. signal. fftconvolve implementiert. beziehungsweise. Ndash Joe Kington Jonas: Cool Der seperate Filter Ansatz funktioniert gut, wie Sie sagen, es spart mehr Zeit als die Kernel-Größe erhöht. Für ein 5000x5000-Array, bei einer 11x11-Kernelgröße, bekomme ich 7.7s für 2d Convolution mit ndimage. convolve und 2.0s für zwei 1d-Convolutions mit ndimage. convolve1d. Für Ihre zweite Lösung, was ist B ndash Benjamin Eine Sache, die ich bin zuversichtlich, muss behoben werden, ist Ihr View-Array b. Es hat ein paar Elemente aus nicht zugeordneten Speicher, so youll erhalten Abstürze. Angesichts Ihrer neuen Beschreibung Ihres Algorithmus, ist die erste Sache, die Fixierung ist die Tatsache, dass Sie außerhalb der Zuweisung von a: Weil Im noch nicht ganz erfassen die Methode und es scheint einfacher Wege, um das Problem zu lösen, Im nur gehen Um das hier zu sagen: Das scheint nur der einfache Ansatz zu sein. Der einzige äußere Vorgang ist, dass er B nur einmal zugewiesen und bevölkert hat. Der Zusatz, die Teilung und die Indexierung müssen unbedingt durchgeführt werden. Wenn Sie 16 Bands machen, müssen Sie B nur noch einmal zuweisen, wenn Sie die Absicht haben, ein Bild zu speichern. Auch wenn dies keine Hilfe ist, könnte es klären, warum ich nicht verstehen, das Problem, oder zumindest dienen als ein Maßstab für die Zeit der Beschleunigungen von anderen Methoden. Dies läuft in 2,6 Sekunden auf meinem Laptop auf einem 5k x 5k-Array von float64s, 0,5 von denen die Schaffung von B beantwortet ist nicht so klar, Ihre Frage, aber Im, dass jetzt, dass youll wie zu verbessern Deutlich diese Art der Mittelung. Nun, welche Art von Leistungsverbesserungen würden Sie eigentlich erwarten Update: Zunächst einmal eine Warnung: der Code in seinem aktuellen Zustand passt sich nicht richtig an die Kernform an. Aber das ist nicht meine primäre Sorge jetzt (sowieso ist die Idee gibt es bereits, wie man richtig anpassen). Ich habe gerade die neue Form eines 4D A intuitiv gewählt, für mich ist es wirklich sinnvoll, darüber nachzudenken, ein 2D-Kernel zentriert zu jedem Raster Position des ursprünglichen 2D A. Aber dass 4D-Gestaltung kann nicht wirklich die beste sein. Ich denke, das eigentliche Problem hier ist die Leistung der Summierung. Man sollte in der Lage, die beste Ordnung (der 4D A) zu finden, um voll zu nutzen Ihre Maschinen Cache-Architektur. Allerdings kann diese Reihenfolge nicht die gleichen für kleine Arrays, die Art der Zusammenarbeit mit Ihrem Maschinen-Cache und die größeren, die nicht (zumindest nicht so einfach). Update 2: Hier ist eine leicht modifizierte Version von mf. Offensichtlich ist es besser, wieder zu einem 3D-Array zuerst und dann anstatt summieren einfach tun Punktprodukt (dies hat den Vorteil, alle so, dass Kernel willkürlich sein kann). Jedoch seine noch etwas 3x langsamer (auf meiner Maschine) als Pauls aktualisiert Funktion. Antwortete am 8. Februar um 19:33 Uhr


No comments:

Post a Comment