R-加速数组维度上的循环

R-加速数组维度上的循环,r,performance,for-loop,multidimensional-array,R,Performance,For Loop,Multidimensional Array,我正在使用具有维度的数组 [1] 290 259 55 4 对于最后三个维度的每次重复,我想对第一维度的290个元素执行滚动平均,将元素数量减少到289个。最后,我需要用更新的值创建一个数据帧 下面的代码实现了我需要的功能,但运行起来需要很长时间(实际上,我必须在结束之前中断它) 图书馆(动物园) #生成与我的维度相同的随机数据 my.array在前面,您正遭受R的地狱()的第二个循环:不断增长的对象。每次调用rbind,它都会生成帧的完整副本,进行r绑定,然后覆盖原始变量名上的完整副本

我正在使用具有维度的数组

[1] 290 259  55   4
对于最后三个维度的每次重复,我想对第一维度的290个元素执行滚动平均,将元素数量减少到289个。最后,我需要用更新的值创建一个数据帧

下面的代码实现了我需要的功能,但运行起来需要很长时间(实际上,我必须在结束之前中断它)

图书馆(动物园)
#生成与我的维度相同的随机数据

my.array在前面,您正遭受R的地狱()的第二个循环:不断增长的对象。每次调用
rbind
,它都会生成帧的完整副本,进行r绑定,然后覆盖原始变量名上的完整副本。因此,虽然它可能在前几十个阶段不会明显减速,但它会在100多个阶段减速。。。你做了56980次

通常最好将事情处理成一个
列表
,然后在整个列表的末尾执行一次
rbind
,如
do.call(rbind,框架列表)
。当然,你仍然可能面临计算上的挑战,做一些可能很难的事情。。。幸运的是,
zoo
几乎是窗口操作所能达到的效率,而这并不是不可能的困难

我将在一个显著减少的问题集上进行演示(因为我认为如果我们考虑16M或150万次迭代,这并不重要)

my.array
apply()
适用于任意数量的维度,因此使用以下包装在
中的.data.frame.table()
可以更快地实现相同的结果,从而有效地将数组的输出转换为数据帧:

library(zoo)
df <- as.data.frame.table(apply(my.array, c(2,3,4), rollmean, 2))
使用
data.table
计算滚动平均值之前的另一个选项

library(data.table)
system.time({
    ans <- setDT(as.data.frame.table(my.array))[
        , .(wind=((Freq + shift(Freq)) / 2)[-1L]), 
        .(time=Var4, level=Var3, lat=Var2)]
    cols <- c("time", "level", "lat")
    ans[, (cols) := lapply(.SD, function(x) match(x, unique(x))), .SDcols=cols]
})
ans
时间:

   user  system elapsed 
   4.90    1.16    5.66 
作为比较:

library(zoo)
system.time({
    as.data.frame.table(apply(my.array, c(2,3,4), rollmean, 2))  
})
#   user  system elapsed 
#  21.89    0.63   22.51 

永远不要迭代地构建data.frames。每次调用
rbind
,它都会将整个帧复制到一个新对象中,并重写
df2
。它可能会工作几十次,但是(如您所见)这是一个可怕的规模。@r2evans这是有道理的,但是…还有什么替代方案呢?一般来说,
是我忘记的
as.data.frame.table
,它在加速方面做得非常好(在初始测试中超过了2倍)。谢谢,我忘记了
数据表的速度有多快了!我将此标记为正式答案,因为我的数据可能比我给出的示例大10倍,使用此答案将节省大量时间。我正在努力将生成的数据表转换为具有维度
289 259 55 4
(类似于原来的一个)。你对此有什么提示吗?我猜它在使用数组?可能会发布另一个问题?我现在没有电脑
library(data.table)
system.time({
    ans <- setDT(as.data.frame.table(my.array))[
        , .(wind=((Freq + shift(Freq)) / 2)[-1L]), 
        .(time=Var4, level=Var3, lat=Var2)]
    cols <- c("time", "level", "lat")
    ans[, (cols) := lapply(.SD, function(x) match(x, unique(x))), .SDcols=cols]
})
ans
          time level lat       wind
       1:    1     1   1        1.5
       2:    1     1   1        2.5
       3:    1     1   1        3.5
       4:    1     1   1        4.5
       5:    1     1   1        5.5
      ---                          
16467216:    4    55 259 16524195.5
16467217:    4    55 259 16524196.5
16467218:    4    55 259 16524197.5
16467219:    4    55 259 16524198.5
16467220:    4    55 259 16524199.5
   user  system elapsed 
   4.90    1.16    5.66 
library(zoo)
system.time({
    as.data.frame.table(apply(my.array, c(2,3,4), rollmean, 2))  
})
#   user  system elapsed 
#  21.89    0.63   22.51