Calculation of the weighted moving average with exponential adjustment

4

How could I compute a in the following formula in java:

Ididthefollowing:Df=Df+a(1-a)xxi

GeneralizedformulaIjustdonotknowhowtocalculatea,typemakeaformulawherea=...

Thisformulaisknownastheexponentiallyadjustedweightedmovingaverage.IsearchedinEnglishwebsitesongooglewiththefollowingsearch:"exponential smoothing formula" but did not succeed.

    
asked by anonymous 09.05.2017 / 15:59

1 answer

3

Looking at the formula, I think the solution would be this:

public static double smooth(double a, double... d) {
    double soma = 0.0;
    double potencia = 1.0;
    for (int i = d.length - 1; i >= 0; i--) {
        soma += a * potencia * d[i];
        potencia *= 1.0 - a;
    }
    return soma;
}

I performed a test:

System.out.println(smooth(0.05, 10, 40, 50, 20, 35));

Here's the result:

7.078253125000002

Now to find the term a (assuming it is between 0.0 and 1.0), we search through iterations, the global maximum of the function, knowing that there are no local maxima:

public static double bestSmooth(double... d) {
    double v1 = 0.0;
    double v5 = 1.0;
    while (true) {
        double v3 = (v1 + v5) / 2;
        if (v3 == v1 || v3 == v5) return v3;
        double s1 = smooth(v1, d);
        double s3 = smooth(v3, d);
        double s5 = smooth(v5, d);
        if (s5 >= s3 && s5 >= s1) {
            v1 = v3;
        } else if (s1 >= s3 && s1 >= s5) {
            v5 = v3;
        } else {
            double v2 = (v1 + v3) / 2;
            double v4 = (v3 + v5) / 2;
            double s2 = smooth(v2, d);
            double s4 = smooth(v4, d);
            if (s4 >= s3 && s4 >= s5) {
                v1 = v3;
                v3 = v4;
            } else if (s2 >= s3 && s2 >= s1) {
                v5 = v3;
                v3 = v2;
            } else if (s3 >= s2 && s3 >= s4) {
                v1 = v2;
                v5 = v4;
            }
        }
    }
}

Now to find the term a based on soma and d , there is no way to reverse the formula of smooth directly, so we need to find the corresponding value in an iterative way:

private static boolean ordered(double a, double b, double c) {
    return (a <= b && b <= c) || (c <= b && b <= a);
}

public static double smoothRatio(double total, double... d) {
    double minA = 0.0;
    double maxA = bestSmooth(d);
    double smoothMin = smooth(minA, d);
    double smoothMax = smooth(maxA, d);
    if (!ordered(smoothMin, total, smoothMax)) throw new IllegalArgumentException();

    while (true) {
        if (total == smoothMin) return minA;
        if (total == smoothMax) return maxA;
        double mid = minA + (maxA - minA) / 2;
        if (mid == minA) return minA;
        if (mid == maxA) return maxA;
        double smoothMid = smooth(mid, d);
        if (ordered(smoothMid, total, smoothMax)) {
            minA = mid;
            smoothMin = smoothMid;
        } else if (ordered(smoothMid, total, smoothMin)) {
            maxA = mid;
            smoothMax = smoothMid;
        }
    }
}

I performed a test:

System.out.println(smoothRatio(7.078253125000002, 10, 40, 50, 20, 35));

And I had this answer:

0.05

Complete examples of tests (the last three are the ones in the figure):

public static void main(String[] args) {
    testar(0.05, 10, 40, 50, 20, 35);
    testar(0.34, 22, 18);
    testar(0.25, 260, 350, 430, 280, 640, 650, 240, 430, 320, 585, 385, 450, 760, 690, 400);
    testar(null, 128, 180, 96, 108, 130, 150, 165, 139, 140, 165, 290, 190, 210, 240, 235);
    testar(null, 36, 48, 26, 31, 57, 42, 26, 23, 18, 25, 18, 36, 41, 18, 22);
}

private static void testar(Double a, double... d) {
    System.out.println("Valores: " + java.util.Arrays.toString(d));
    if (a != null) {
        double r = smooth(a, d);
        System.out.println("Taxa: " + a + " - resultado: " + r);
        double b = smoothRatio(r, d);
        System.out.println("Taxa (prova real): " + b);
    }
    double p = bestSmooth(d);
    System.out.println("Melhor taxa: " + p + " - resultado: " + smooth(p, d));
    System.out.println();
}

Here's the output:

Valores: [10.0, 40.0, 50.0, 20.0, 35.0]
Taxa: 0.05 - resultado: 7.078253125000002
Taxa (prova real): 0.05
Melhor taxa: 1.0 - resultado: 35.0

Valores: [22.0, 18.0]
Taxa: 0.34 - resultado: 11.056799999999999
Taxa (prova real): 0.33999999999999997
Melhor taxa: 0.9090909212827682 - resultado: 18.18181818181818

Valores: [260.0, 350.0, 430.0, 280.0, 640.0, 650.0, 240.0, 430.0, 320.0, 585.0, 385.0, 450.0, 760.0, 690.0, 400.0]
Taxa: 0.25 - resultado: 514.275442045182
Taxa (prova real): 0.24999999999999967
Melhor taxa: 0.3844731971623787 - resultado: 529.8357007856109

Valores: [128.0, 180.0, 96.0, 108.0, 130.0, 150.0, 165.0, 139.0, 140.0, 165.0, 290.0, 190.0, 210.0, 240.0, 235.0]
Melhor taxa: 0.9200836578384042 - resultado: 235.20144008802336

Valores: [36.0, 48.0, 26.0, 31.0, 57.0, 42.0, 26.0, 23.0, 18.0, 25.0, 18.0, 36.0, 41.0, 18.0, 22.0]
Melhor taxa: 0.21615071594715118 - resultado: 26.222890515272397

In the last three examples (as in the figure), the first one (line 3 of the spreadsheet, marked with C) gives 514.275442045182 (which is the same value as the Q3-S3 cells, if rounded) using a rate of 0.25 (U3 cell). If you used an ideal rate of 0.3844731971623787, the answer would be as much as possible for this data: 529.8357007856109

For all other examples, you do not have a value of a . Different values of a will produce different results. Probably the value of a that matters most is the one that produces the best result, which is calculated using the bestSmooth function. So in the case of your spreadsheet line 5 (marked B), the best possible result is 235.20144008802336 at an ideal rate of 0.9200836578384042. In the case of your spreadsheet line 7 (marked A), the best possible result is 26.222890515272397 at an ideal rate of 0.21615071594715118.

In real life, the best result or ideal rate is not always attainable, but the more the actual rate approaches the ideal rate provided by the bestSmooth function, the higher the predicted value.

See here working on ideone.

    
09.05.2017 / 16:07