java中是否有一个函数可以获得移动平均值

我有一种情况,我需要每0.5秒从一个设备处理5000个样本。

假设窗口大小为100,那么移动平均线将产生50个点。 我正在尝试使用传统方法,即使用循环。 但这是一种非常低效的方法。 有什么建议么 ?

查看Apache Maths库。 这有方法可以准确地做你想要的。 有关详细信息,请参阅DescriptiveStatistics和Mean 。

这是一种方式。

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()); } } 

您可以在O(1)中执行此操作:保留最近50个条目的队列。 添加条目并且队列短50个元素时,只需更新总计和计数。 如果它超过50个元素,也要更新总数和计数。 伪代码:

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

据我所知,Java中没有这样的函数(类)。 但你可以自己做一个。 这是一个简单的例子(SMA-简单移动平均线):

 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; } } 

这是一个很好的实现,使用BigDecimal:

 import java.math.BigDecimal; import java.math.RoundingMode; import java.util.LinkedList; import java.util.Queue; public class MovingAverage { private final Queue window = new LinkedList(); 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); } } 
 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; } 

这个算法也可以称为移动平均滤波器,对我来说效果很好......我在我的图形项目中实现了这个算法!

Java 8添加了java.util.IntSummaryStatisticsDoubleLong也有类似的类。 相当简单易用:

 IntSummaryStatistics stats = new IntSummaryStatistics(); stats.accept(1); stats.accept(3); stats.getAverage(); // Returns 2.0