2012-02-08 15 views
9

I zasadniczo mają tablicę wartości takiego:Wdrażanie wykładnicza średnia ruchoma w Javie

0.25, 0.24, 0.27, 0.26, 0.29, 0.34, 0.32, 0.36, 0.32, 0.28, 0.25, 0.24, 0.25 

Powyższa tablica jest zbyt uproszczona, jestem zbieranie 1 wartość na milisekundę w moim rzeczywisty kod i trzeba przetwarzać wyjście na algorytmie, który napisałem, aby znaleźć najbliższy szczyt przed punktem w czasie. Moja logika kończy się niepowodzeniem, ponieważ w powyższym przykładzie, 0.36 jest prawdziwym szczytem, ​​ale mój algorytm będzie wyglądał wstecz i zobacz ostatni numer 0.25 jako szczyt, ponieważ przed nim jest spadek do 0.24.

Celem jest pobranie tych wartości i zastosowanie do nich algorytmu, który "wygładzi" je tak, żebym miał więcej wartości liniowych. (tj .: chciałbym, aby moje wyniki były krzywoliniowe, nie poszarpane)

Powiedziano mi, żebym zastosował wykładniczy filtr średniej kroczącej do moich wartości. Jak mogę to zrobić? Naprawdę trudno mi czytać równania matematyczne, z kodem radzę sobie znacznie lepiej.

Jak przetwarzać wartości w mojej tablicy, stosując obliczeniowe obliczenie średniej ruchomej, aby je wyrównać?

float[] mydata = ... 
mySmoothedData = exponentialMovingAverage(mydata, 0.5); 

float[] exponentialMovingAverage(float[] input, float alpha) { 
    // what do I do here? 
    return result; 
} 

Odpowiedz

27

Aby obliczyć wartość exponential moving average, należy zachować pewien stan i potrzebny jest parametr strojenia. Wymaga to trochę klasy (zakładając że używasz Java 5 lub później):

class ExponentialMovingAverage { 
    private double alpha; 
    private Double oldValue; 
    public ExponentialMovingAverage(double alpha) { 
     this.alpha = alpha; 
    } 

    public double average(double value) { 
     if (oldValue == null) { 
      oldValue = value; 
      return value; 
     } 
     double newValue = oldValue + alpha * (value - oldValue); 
     oldValue = newValue; 
     return newValue; 
    } 
} 

instancję z parametrem rozkładu chcesz (może brać strojenie; powinna być między 0 i 1), a następnie użyć average(…) filtrować .


Czytając stronę na jakimś matematycznym nawrotu, wszystko co naprawdę trzeba wiedzieć, kiedy przekształcając go w kodzie jest, że matematycy lubią pisać indeksów na tablice i sekwencje z indeksami. (Mają też kilka innych zapisów, co nie pomaga). Jednak EMA jest dość prosta, ponieważ wystarczy zapamiętać jedną starą wartość; nie są wymagane skomplikowane tablice stanów.

+0

W rzeczywistości, EMA jest _easiest_ średnia ruchoma do kodu (pod warunkiem, trzeba gdzieś przechowywać stan państwowej jak Java obiekt), ponieważ nie trzeba wykonywać złożonego zarządzania stanami. –

+1

Tak więc zasadniczo po prostu "dla (float dude: input) {output [index] = ema.average (dude); } '? –

+1

@ TKKocheran: Dosyć. Czy to nie jest miłe, kiedy wszystko może być proste? (Jeśli zaczynasz z nową sekwencją, zdobądź nowy uśredniony). Zauważ, że kilka pierwszych haseł w uśrednionej sekwencji będzie przeskakiwać nieco ze względu na efekty graniczne, ale otrzymasz także te z innymi ruchomymi średnimi. Jednak korzystną zaletą jest to, że można zawinąć logikę średniej ruchomej do uśredniania i eksperymentować, nie zakłócając zbytnio reszty programu. –

-4

Jeśli masz problemy z matematyką, możesz użyć zwykłej średniej ruchomej zamiast wykładniczej. Wynik wyjściowy będzie więc ostatnim x terminami podzielonymi przez x. Niesprawdzone pseudokod:

int data[] = getFilled(); 
int outdata[] = initializeme() 
for (int y = 0; y < data.length; y++) 
    int sum = 0; 
    for (int x = y; x < y-5; x++) 
     sum+=data[x]; 
    outdata[y] = sum/5; 

Należy pamiętać, że trzeba będzie obsłużyć początkowe i końcowe fragmenty danych, ponieważ wyraźnie nie można uśredniać ostatnie 5 terminów, kiedy jesteś na 2. punktu danych. Ponadto istnieją skuteczniejsze sposoby obliczania tej średniej ruchomej (suma = suma - najstarsza + najnowsza), ale ma to na celu uzyskanie koncepcji tego, co się dzieje.

4

Trudno mi zrozumieć twoje pytania, ale postaram się odpowiedzieć.

1) Jeśli twój algorytm znalazł 0.25 zamiast 0.36, to jest źle. Jest źle, ponieważ zakłada monotoniczny wzrost lub spadek (to znaczy "zawsze wzrasta" lub "zawsze spada"). O ile nie wytypujesz WSZYSTKICH twoich danych, twoje punkty danych --- podczas ich prezentacji --- są nieliniowe. Jeśli naprawdę chcesz znaleźć maksymalną wartość między dwoma punktami w czasie, a następnie podziel tablicę z t_min na t_max i znajdź maksimum tego podbarwa.

2) Teraz pojęcie "średnich kroczących" jest bardzo proste: wyobraź sobie, że mam następującą listę: [1.4, 1.5, 1.4, 1.5, 1.5]. Mogę "wygładzić", biorąc średnią z dwóch liczb: [1.45, 1.45, 1.45, 1.5].Zauważ, że pierwsza liczba to średnia z 1,5 i 1,4 (druga i pierwsza liczba); druga (nowa lista) to średnia z 1,4 i 1,5 (trzecia i druga stara lista); trzecia (nowa lista) to średnio 1,5 i 1,4 (czwarta i trzecia) i tak dalej. Mogłem zrobić "okres trzeci" lub "czwarty" lub "n". Zwróć uwagę, że dane są znacznie płynniejsze. Dobrym sposobem na "zobacz średnie ruchome w pracy" jest przejście do Google Finance, wybór akcji (wypróbuj Tesla Motors, pretty volatile (TSLA)) i kliknij "technicals" na dole wykresu. Wybierz "Średnia ruchoma" z danym okresem i "Wykładniczą średnią ruchomą", aby porównać różnice.

Wykładnicza średnia krocząca jest tylko kolejnym opracowaniem tego, ale waży "starsze" dane mniej niż "nowe" dane; jest to sposób na "odchylenie" wygładzania w kierunku tyłu. Proszę przeczytać wpis w Wikipedii.

To jest bardziej komentarz niż odpowiedź, ale małe pole komentarza było tylko maleńkie. Powodzenia.

+0

+1: Stosunkowo łatwo jest znaleźć minimalne i maksymalne, ale znacznie trudniej jest określić ich znaczenie, ponieważ trzeba spojrzeć na odchylenia od długoterminowych wzorców. Przy założeniu, że takie wzorce w ogóle istnieją. –

0

W tocznie .... Używam również commons.apache bibliotekę matematyczną

public LinkedList EMA(int dperiods, double alpha) 
       throws IOException { 
      String line; 
      int i = 0; 
      DescriptiveStatistics stats = new SynchronizedDescriptiveStatistics(); 
      stats.setWindowSize(dperiods); 
      File f = new File(""); 
      BufferedReader in = new BufferedReader(new FileReader(f)); 
      LinkedList<Double> ema1 = new LinkedList<Double>(); 
      // Compute some statistics 
      while ((line = in.readLine()) != null) { 
       double sum = 0; 
       double den = 0; 
       System.out.println("line: " + " " + line); 
       stats.addValue(Double.parseDouble(line.trim())); 
       i++; 
       if (i > dperiods) 
        for (int j = 0; j < dperiods; j++) { 
         double var = Math.pow((1 - alpha), j); 
         den += var; 
         sum += stats.getElement(j) * var; 
         System.out.println("elements:"+stats.getElement(j)); 
         System.out.println("sum:"+sum); 
        } 
       else 
        for (int j = 0; j < i; j++) { 
         double var = Math.pow((1 - alpha), j); 
         den += var; 
         sum += stats.getElement(j) * var; 
        } 
       ema1.add(sum/den); 
       System.out.println("EMA: " + sum/den); 
      } 
      return ema1; 
     } 
+0

PROSZĘ ZASTOSOWAĆ bibliotekę matematyczną commons.apache PRZED PRZYKAZANIEM KOŃCÓWEK :( – user3392362