是什么让rollmean比rollapply更快(代码方式)?

ric*_*rdo 6 r zoo

我经常发现时间序列的滚动事件(特别是手段),并且惊讶地发现它rollmean明显快于rollapply,并且align = 'right'方法比rollmeanr包装器更快.

他们是如何实现这种加速的?为什么在使用rollmeanr()包装器时会丢失一些?

一些背景:我一直在使用rollapplyr(x, n, function(X) mean(X)),但最近我发现了一些使用的例子rollmean.文件建议rollapplyr(x, n, mean)(注意没有function参数的部分)使用,rollmean所以我不认为性能会有太大差异,但rbenchmark显示出明显的差异.

require(zoo)
require(rbenchmark)

x <- rnorm(1e4)
r1 <- function() rollapplyr(x, 3, mean) # uses rollmean
r2 <- function() rollapplyr(x, 3, function(x) mean(x))
r3 <- function() rollmean(x, 3, na.pad = TRUE, align = 'right')
r4 <- function() rollmeanr(x, 3, align = "right")

bb <- benchmark(r1(), r2(), r3(), r4(), 
          columns = c('test', 'elapsed', 'relative'), 
          replications = 100, 
          order = 'elapsed')

print(bb)
Run Code Online (Sandbox Code Playgroud)

我惊讶地发现它rollmean(x, n, align = 'right')明显更快 - 比我的rollapply(x, n, function(X) mean(X))方法快40倍.

  test elapsed relative
3 r3()    0.74    1.000
4 r4()    0.86    1.162
1 r1()    0.98    1.324
2 r2()   27.53   37.203
Run Code Online (Sandbox Code Playgroud)

随着数据集大小的增长,差异似乎越来越大.我只更改了上面代码中的x(to rnorm(1e5))大小并重新运行测试,这些函数之间的差异更大.

  test elapsed relative
3 r3()   13.33    1.000
4 r4()   17.43    1.308
1 r1()   19.83    1.488
2 r2()  279.47   20.965 
Run Code Online (Sandbox Code Playgroud)

并为 x <- rnorm(1e6)

  test elapsed relative
3 r3()   44.23    1.000
4 r4()   54.30    1.228
1 r1()   65.30    1.476
2 r2() 2473.35   55.920
Run Code Online (Sandbox Code Playgroud)

他们是怎么做到的?此外,这是最佳解决方案吗?当然,这很快但有更快的方法吗?

(注意:一般来说,我的时间序列几乎都是xts对象 - 这有关系吗?)

edd*_*ddi 7

计算滚动平均值比计算一般滚动函数更快,因为第一个更容易计算.在计算一般滚动功能时,您必须反复计算每个窗口上的功能mean,由于简单的标识,您不必为此执行此操作:

 (a2 + a3 + ... + an)/(n-1) = (a1 + a2 + ... + a(n-1))/(n-1) + (an - a1)/(n-1)
Run Code Online (Sandbox Code Playgroud)

你可以通过观察看看它是如何被利用的getAnywhere(rollmean.zoo).

如果你想要一个更快的滚动平均值,使用runmeanfrom caTools,这在C中实现,使其更快(它也可以更好地扩展,因此随着数据大小的增加会变得更快).

library(microbenchmark)
library(caTools)
library(zoo)

x = rnorm(1e4)
microbenchmark(runmean(x, 3, endrule = 'trim', align = 'right'),
               rollmean(x, 3, align = 'right'))
#Unit: microseconds
#                                             expr      min        lq     median        uq       max neval
# runmean(x, 3, endrule = "trim", align = "right")  631.061  740.0775   847.5915  1020.048  1652.109   100
#                  rollmean(x, 3, align = "right") 7308.947 9155.7155 10627.0210 12760.439 16919.092   100
Run Code Online (Sandbox Code Playgroud)