【问题标题】:Fast rolling mean + summarize快速滚动均值 + 汇总
【发布时间】:2016-12-19 10:28:46
【问题描述】:

在 R 中,我尝试使用不同的窗口宽度对一个大向量(最多 400k 个元素)进行非常快速的滚动平均,然后为每个窗口宽度汇总每年的最大值。希望下面的例子很清楚。 我已经尝试了几种方法,到目前为止最快的方法似乎是使用 roll_mean 包中的 RcppRoll 来获取运行平均值,并使用 aggregate 来选择最大值。 请注意,内存需求是一个问题:下面的版本需要很少的内存,因为它一次只做一个滚动平均值和聚合;这是首选。

#Example data frame of 10k measurements from 2001 to 2014
n <- 100000
df <- data.frame(rawdata=rnorm(n),
                 year=sort(sample(2001:2014, size=n, replace=TRUE))
                 ) 

ww <- 1:120 #Vector of window widths

dfsumm <- as.data.frame(matrix(nrow=14, ncol=121))
dfsumm[,1] <- 2001:2014
colnames(dfsumm) <- c("year", paste0("D=", ww))

system.time(for (i in 1:length(ww)) {
  #Do the rolling mean for this ww
  df$tmp <- roll_mean(df$rawdata, ww[i], na.rm=TRUE, fill=NA)
  #Aggregate maxima for each year
  dfsumm[,i+1] <- aggregate(data=df, tmp ~ year, max)[,2]
}) #28s on my machine
dfsumm

这给出了所需的输出:data.frame,有 15 行(从 2001 年到 2015 年)和 120 列(窗口宽度),包含每个 ww 和每年的最大值。

但是,计算仍然需要很长时间(因为我必须计算数千个)。我尝试过使用其他选项,即dplyrdata.table,但由于我对这些软件包缺乏了解,我无法更快地找到。

使用单核(代码已经在其他地方并行化)是最快的方法?

【问题讨论】:

    标签: r dataframe data.table aggregate rolling-computation


    【解决方案1】:

    内存管理,即分配和复制,正在用你的方法杀死你。

    这是一个 data.table 方法,它通过引用分配:

    library(data.table)
    setDT(df)
    alloc.col(df, 200) #allocate sufficient columns
    
    #assign rolling means in a loop
    for (i in seq_along(ww)) 
      set(df, j = paste0("D", i),  value = roll_mean(df[["rawdata"]], 
                                            ww[i], na.rm=TRUE, fill=NA))
    
    dfsumm <- df[, lapply(.SD, max, na.rm = TRUE), by = year] #aggregate
    

    【讨论】:

    • 哇!我得到了一个简单的 10 倍加速,再高兴不过了。非常感谢!
    【解决方案2】:

    使用新的frollmean 函数(在 data.table v1.12.0 中添加)您可以执行以下操作

    th = setDTthreads(1L)
    df[, paste0("D",ww) := frollmean(rawdata, ww, na.rm=TRUE)]
    dfsumm <- df[, lapply(.SD, max, na.rm=TRUE), by=year]
    setDTthreads(th)
    

    您应该考虑降低并行度,因为此用例在 frollmean 中得到了很好的并行化。分组操作也使用并行处理。

    【讨论】:

      【解决方案3】:

      您创建的一个性能问题是使用 cbind 动态增长向量。您可以尝试预先分配预期的大小,然后使用dfsumm[x] &lt;- y 填充它。

      【讨论】:

      • 我刚刚尝试按照您的建议(请参阅上面的编辑代码),但并没有真正看到任何改进。使用 100k 个样本,时间仍然是 28 秒。
      猜你喜欢
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      • 2018-07-14
      • 1970-01-01
      • 2011-02-23
      • 1970-01-01
      • 1970-01-01
      • 2018-10-22
      相关资源
      最近更新 更多