R “ddply”(或类似)能做滑动窗口吗?
差不多R “ddply”(或类似)能做滑动窗口吗?,r,plyr,R,Plyr,差不多 sliding = function(df, n, f) ldply(1:(nrow(df) - n + 1), function(k) f(df[k:(k + n - 1), ]) ) 那会像这样使用 > df n a 1 1 0.8021891 2 2 0.9446330 ... > sliding(df, 2, function(df) with(df, + data.frame(n = n[1], a =
sliding = function(df, n, f)
ldply(1:(nrow(df) - n + 1), function(k)
f(df[k:(k + n - 1), ])
)
那会像这样使用
> df
n a
1 1 0.8021891
2 2 0.9446330
...
> sliding(df, 2, function(df) with(df,
+ data.frame(n = n[1], a = a[1], b = sum(n - a))
+ ))
n a b
1 1 0.8021891 1.253178
...
除了直接的内部ddply
,这样我就可以得到好的语法糖
这就随之而来了?因为这个问题还没有答案,我想我应该提出一个答案来证明,实际上有一个更好的方法来解决这类问题——一个潜在的更快数千倍的。(如果这没有帮助,请让我知道,但我认为这比什么都没有好) 每当我听到“移动平均”或“滑动窗口”时,FFT卷积就立刻浮现在我的脑海中。这是因为它可以以极其高效的方式处理这类问题。由于所有的“滑动”都是在幕后进行的,我认为它也具有你所能要求的所有句法美 (以下代码位于一个文件中) 我们首先模拟一些数据(为了简单起见,我在这里使用整数,但当然不需要)
>df
n a
1 1 8
2 2 9
3 3 8
4 4 9
5 5 5
6 6 2
7 7 4
8 8 6
9 9 8
10 10 10
现在,我们将一次性预计算n-a
n.minus.a = with(df, n - a)
接下来,定义一个内核k
,当与输入进行卷积时,它将对数据进行求和(或平均/平滑/任何其他操作)
k = rep(0, n)
k[1:n.sum] = 1
设置好所有设置后,我们可以定义一个函数,通过fft()
在频域有效地进行卷积
当您在R中使用convolve()
便利功能时,所有这些都会在引擎盖下发生
卷积(n.减号a,k)[1:(长度(n.减号a)-n.sum+1]
[1] -14 -12 -10 -5 4 7 5 3 1
现在,我们将其与手动方法进行比较,以表明结果都是等效的:
滑动(df,2,函数(df)和(df,data.frame(n=n[1],a=a[1],b=sum(n-a)))
n a b
1 1 8 -14
2 2 9 -12
3 3 8 -10
4 4 9 -5
5 5 5 4
6 6 2 7
7 7 4 5
8 8 6 3
9 9 8 1
最后,我们将制作n=10^4
并测试所有这些方法的速度:
>系统时间(myConv(n.减号a,k))
用户系统运行时间
0.002 0.000 0.002
>系统时间(卷积(n.减号a,k,type='circ')[1:(长度(n.减号a)-n.sum+1)])
用户系统运行时间
0.002 0.000 0.002
>系统时间(滑动(df,2,函数(df)和(df,数据帧(n=n[1],a=a[1],b=sum(n-aщ)'))
用户系统运行时间
7.944 0.018 7.962
FFT方法几乎是瞬时返回的,即使在这种粗略计时的情况下,也比手动方法快近4000倍
当然,并不是每一种滑动问题都可以被归入这个范例,但是对于像这样的数值问题,使用
sum()
(也指加权平均值等),它可以完美地工作。无论如何,至少谷歌一点,看看是否有一个过滤器内核可以解决给定的问题,这通常是非常值得的。祝你好运 你的意思是像zoo
软件包中的rollappy
一样吗?没有,但我已经懒散地考虑让ddply和friends使用更通用的迭代器。@hadley:从快速查看的结果来看,似乎只需要允许人们传入他们自己的自定义拆分器(并记录它的假定返回值)就可以了。如果您将其作为一个额外参数提供,并将您自己的splitter\u d作为默认值,我认为它应该可以工作,对吗?而编写“滑动窗口索引”基本上已经由Owen完成了。不,不幸的是,这种方法依赖于FT[a(t)convolve b(t)]===FT(a(t))*FT(b(t))
的恒等式。我很确定在频域中没有直接的方法来找到中值或分位数。
k = rep(0, n)
k[1:n.sum] = 1
myConv <- function(x, k){
Fx = fft(x)
Fk = fft(k)
Fxk = Fx * Fk
xk = fft(Fxk, inverse=T)
(Re(xk) / n)[-(1:(n.sum-1))]
}