Подтвердить что ты не робот

Есть ли функция в java для получения скользящей средней

У меня есть ситуация, когда мне нужно обрабатывать 5000 образцов с устройства каждые 0,5 секунды.

Предположим, что размер окна равен 100, тогда будет 50 очков в результате скользящей средней. Я пытаюсь использовать обычный метод, т.е. С циклами. Но это очень неэффективный способ сделать это. Любые предложения?

4b9b3361

Ответ 1

Ознакомьтесь с библиотекой Apache Maths. У этого есть методы для того, чтобы делать именно то, что Вы хотите. См. DescriptiveStatistics и Mean для получения дополнительной информации. Информация.

Ответ 2

Вот один из способов.

public class Rolling {

    private int size;
    private double total = 0d;
    private int index = 0;
    private double samples[];

    public Rolling(int size) {
        this.size = size;
        samples = new double[size];
        for (int i = 0; i < size; i++) samples[i] = 0d;
    }

    public void add(double x) {
        total -= samples[index];
        samples[index] = x;
        total += x;
        if (++index == size) index = 0; // cheaper than modulus
    }

    public double getAverage() {
        return total / size;
    }   
}

public class RollingTest extends TestCase {

    private final static int SIZE = 5;
    private static final double FULL_SUM = 12.5d;

    private Rolling r;

    public void setUp() {
        r = new Rolling(SIZE);
    }

    public void testInitial() {
        assertEquals(0d, r.getAverage());
    }

    public void testOne() {
        r.add(3.5d);
        assertEquals(3.5d / SIZE, r.getAverage());
    }

    public void testFillBuffer() {
        fillBufferAndTest();
    }

    public void testForceOverWrite() {
        fillBufferAndTest();

        double newVal = SIZE + .5d;
        r.add(newVal);
        // get the 'full sum' from fillBufferAndTest(), add the value we just added,
        // and subtract off the value we anticipate overwriting.
        assertEquals((FULL_SUM + newVal - .5d) / SIZE, r.getAverage());
    }

    public void testManyValues() {
        for (int i = 0; i < 1003; i++) r.add((double) i);
        fillBufferAndTest();
    }


    private void fillBufferAndTest() {
        // Don't write a zero value so we don't confuse an initialized
        // buffer element with a data element.
        for (int i = 0; i < SIZE; i++) r.add(i + .5d);
        assertEquals(FULL_SUM / SIZE, r.getAverage());
    }
}

Ответ 3

Вы можете сделать это в O (1): сохранить очередь из последних 50 записей. Когда вы добавляете запись, а очередь меньше 50 элементов, просто обновляйте общее количество и количество. Если оно больше 50 элементов, обновите общее количество и счетчик. Псевдокод:

add(double x) {
    total += x;
    addToQueue(x);
    if (queueSize > 50) {
        total -= removeLastFromQueue();
    } else {
        count++;
    }
}
double getAverage() {
    return total / count;
}

Ответ 4

Здесь хорошая реализация, использующая BigDecimal:

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.LinkedList;
import java.util.Queue;

public class MovingAverage {

    private final Queue<BigDecimal> window = new LinkedList<BigDecimal>();
    private final int period;
    private BigDecimal sum = BigDecimal.ZERO;

    public MovingAverage(int period) {
        assert period > 0 : "Period must be a positive integer";
        this.period = period;
    }

    public void add(BigDecimal num) {
        sum = sum.add(num);
        window.add(num);
        if (window.size() > period) {
            sum = sum.subtract(window.remove());
        }
    }

    public BigDecimal getAverage() {
        if (window.isEmpty()) return BigDecimal.ZERO; // technically the average is undefined
        BigDecimal divisor = BigDecimal.valueOf(window.size());
        return sum.divide(divisor, 2, RoundingMode.HALF_UP);
    }
}

Ответ 5

Насколько я знаю, такой функции (класса) в Java нет. Но вы можете сделать это самостоятельно. Вот простой пример (SMA-Simple Moving Average):

public class MovingAverage {
    private int [] window;
    private int n, insert;
    private long sum;

    public MovingAverage(int size) {
        window = new int[size];
        insert = 0;
        sum = 0;
    }

    public double next(int val) {
        if (n < window.length)  n++;
        sum -= window[insert];
        sum += val;
        window[insert] = val;
        insert = (insert + 1) % window.length;
        return (double)sum / n;
    }
}

Ответ 6

static int[] myIntArray = new int[16];
public static double maf(double number)
{
    double avgnumber=0;
    for(int i=0; i<15; i++)
    {
        myIntArray[i] = myIntArray[i+1];
    }
    myIntArray[15]= (int) number;
    /* Doing Average */
    for(int  i=0; i<16; i++)
    {
        avgnumber=avgnumber+ myIntArray[i];
    }
    return avgnumber/16;

}

этот алгоритм также можно назвать фильтром Moving Average, который хорошо работает для меня... я реализовал этот алгоритм в моем графическом проекте!