如何加快/改善滚动平均功能?

时间:2016-03-14 00:09:47

标签: r dplyr zoo rollapply

我的数据是988,785 obs。 3个变量。我的数据的一个较小的例子如下:

Names <- c("Jack", "Jill", "John")
RawAccelData <- data.frame(
  Sample = as.numeric(rep(1:60000, each = 3)),
  Acceleration = rnorm(6000),
  ID = rep((Names), each = 60000)
)

我的设备采样率为100 Hz。我希望在1到10秒的时间内计算每个Acceleration的{​​{1}}的滚动平均值。我使用以下内容执行此操作:

ID

但是,我现在需要计算1到10分钟的滚动时间。我可以通过使用上面的代码并用以下代码替换:

require(dplyr)
require(zoo)

for (summaryFunction in c("mean")) {
  for ( i in seq(100, 1000, by = 100)) {
    tempColumn <- RawAccelData %>%
      group_by(ID) %>%
      transmute(rollapply(Acceleration,
                          width = i, 
                          FUN = summaryFunction, 
                          align = "right", 
                          fill = NA, 
                          na.rm = T))
    colnames(tempColumn)[2] <- paste("Rolling", summaryFunction, as.character(i), sep = ".")
    RawAccelData <- bind_cols(RawAccelData, tempColumn[2])
  }
}

但是,这需要几个小时来运行我的数据集并导致我的Mac上的RStudio(下面的详细信息)挂起!有没有办法可以a)整理上面的代码或b)使用不同的包/方法来实现更快的结果?

谢谢。

for ( i in seq(6000, 60000, by = 6000)) {

2 个答案:

答案 0 :(得分:3)

它运行缓慢的原因是

  1. 问题中的代码通过将rollapply分配给变量并传递该变量,使mean无法检测到mean被传递的能力。 (对于meanrollapply调用rollmean,其中包含针对该情况的优化代码)。如果问题中的代码直接通过mean或者使用rollmean,那么它的速度会快得多。

  2. filter不会删除NAs,因此对于苹果与苹果的比较,应该 na.rm = TRUE中使用rollapply。如果您确实使用它,那么它也将失败优化。

  3. 例如,在此比较中,rollapply的运行速度是filter的两倍以上:

    library(zoo)
    library(rbenchmark)
    
    set.seed(123)
    r <- rnorm(10000)
    benchmark(filter = stats::filter(r, rep(1/100,100), sides = 1),
              rollapply = rollapplyr(r, 100, mean, fill = NA))[1:4]
    

    ,并提供:

           test replications elapsed relative
    1    filter          100    3.75    2.119
    2 rollapply          100    1.77    1.000
    

    当然,速度可能会根据width,数据长度和输入的其他方面而有所不同,因为这只是一次测试。

答案 1 :(得分:1)

我不确定您是否还有其他摘要功能,但至少在平均值上,您可以使用rollapply来加速filter功能: transmute(stats::filter(Acceleration,rep(1/i,i),sides=1))

(请参阅此处的其他选项:Calculating moving average in R)使用system.time,这会让我从117秒加速到4秒!!

您还可以并行执行一些for循环。 而不是

for ( i in seq(6000, 60000, by = 6000)) {

尝试:

library(parallel)
for (summaryFunction in c("mean")) {
  rollCols = mclapply (seq(100, 1000, by = 100),function(i){
    tempColumn <- RawAccelData %>%
    group_by(ID) %>%
    transmute(stats::filter(Acceleration,rep(1/i,i),sides=1))
    colnames(tempColumn)[2] <- paste("Rolling", summaryFunction, as.character(i), sep = ".")
    return(tempColumn[2])
  })
}

RawAccelData = cbind(RawAccelData,do.call(cbind,rollCols))

这使我从72秒加速到40秒,但这取决于你的计算机有多少核心。