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))]
}