高效的移动平均算法<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />你好,
感谢之前在这里发帖的人,我找到了一些有用的答案!
我有几个来自示波器的大数据集(每个 2000 万个点!)。 我想计算移动平均线。 但是,我设计的算法非常慢。 这是我的公式的代码:
“
If(Row() < 100, Empty(), Summation(i = Row() - 99, Row(), :Current[i,Empty()]) / 100)
“

随着平均窗口的宽度(在本例中为 100 个样本)变大(比如 500、1000,甚至 50000 或更多),计算时间变得不合理。 有人有更快的移动平均线方法吗?
谢谢!
丹麦人
回复:高效的移动平均算法我通常发现,如果我能一起避开桌子,速度会更快。 这在我的机器上运行得更快。 您会注意到 My numbers 也不同于 Jeffs。 那只是因为我镜像最后的数字然后从中心开始 x 点(而不是最后 x 点)。 这也有缺失值的权重,所以如果你有任何缺失值,这不是问题。 至少我是这么认为的。 如果你最后不需要一列,它也会更快。 而且因为它基本上只是一个连接的索引矩阵,所以它非常快。
Names Default to here(1);
dt = open("$SAMPLE_DATA\Big Class.jmp");
st1 = HPtime();
mat = :height << Get Values;
//number of rows you want to average
x= 5;
//+- gap
z = (x-1)/2;
//get the rows
rows = 1::nrows(mat);
//mirror the rows on the front and back
mirrored = ((z+1)::2)||rows||((ncol(rows)-1)::(ncol(rows)-z));
big_mat = [];
for(i=0, i<=x-1, i++,
//this is cutting up the longer mirrored vector into x vectors of the same length as the original
big_mat ||= mat[mirrored[rows+i]];
);
//now we can just take a VSum of the transpose /x to get our average
Squasher = !ismissing(big_mat); //everywhere there's a non-missing, make 1
Squasher = VSum(Squasher`); //count real numbers, this is to not weight non-missings
A = Vsum(big_mat`)/x;
New Column("Moving Average", Set Values(A)); //If you don't need this column
//and you're just doing matrix operations this is actually about half the total time
en1 = HPTime()-st1;
// Data Table method
st2 = HPTime();
dt<< New Column("moving sum(x)", formula(If(Row()<=:Moving Avg Window,
If( Row() == 1,
:height,
Lag( :Name( "moving sum(x)" ), 1 ) + :height
),
(Lag( :Name( "moving sum(x)" ), 1 ) + :height) -
Lag( :height, :Moving Avg Window )
)));
dt<< New Column("Moving Avg", Formula(
If(Row()>=:Moving Avg Window,
:Name( "moving sum(x)" ) / :Moving Avg Window,
.
)));
en2 = HPTime()-st2;
show(en1, en2);回复:高效的移动平均算法这是一个很好的解决方案。 请注意,数据列(本例中为“当前”)中的任何缺失值都会在计算数据列中从第一个缺失数据出现的行到下面的所有行创建空白值。 这是一个需要注意的小问题。回复:高效的移动平均算法谢谢,杰夫。 这些比求和法运行得快得多!
回复:高效的移动平均算法我可以在这里提供一些策略。
我认为两者都比您当前使用的 Summation() 运算符更有效。 我不能说它们是最有效的。
1) 在矩阵上使用 Sum() 函数。
If(Row()<:Moving Avg Window,
.,
Sum( :Current[Index( Row() - (:Moving Avg Window - 1), Row() )] ) / :Moving Avg Window
)

这利用了矩阵运算的速度。 的下标当前的此公式中的列是从移动平均窗口开始到当前行号的行号矩阵。 我以这种方式为列下标,JMP 返回一个矩阵,而 Sum 函数在矩阵上相对有效。
不过,一种更快的方法是计算两列的移动平均值。 第一列简单地通过添加值来维护移动总和当前的在一行中将前一行中的滚动总和的值减去,然后从窗口开头的行中减去 Current 的值。
这是移动总和的公式。
If(Row()<=:Moving Avg Window,
If( Row() == 1,
:Current,
Lag( :Name( "moving sum(x)" ), 1 ) + :Current
),
(Lag( :Name( "moving sum(x)" ), 1 ) + :Current) -
Lag( :Current, :Moving Avg Window )
)

然后很容易有一个划分的列移动总和由移动平均窗口.
If(Row()>=:Moving Avg Window,
:Name( "moving sum(x)" ) / :Moving Avg Window,
.
)

我附上了显示这两种方法的数据表。 在数据表中移动平均窗口是一个数据表变量.
要查看此数据表中第二种方法的效率,您可能需要打压评价的的移动平均(x)专栏第一。
-杰夫