【问题标题】:Improve rolling mean usage in data.table改进 data.table 中的滚动平均使用率
【发布时间】:2018-12-09 08:05:19
【问题描述】:

我正在尝试组合一个函数来复制以下内容

library(tidyverse)
library(magrittr)
library(data.table)
library(parallel)
library(RcppRoll)

windows <- (1:10)*600

df2 <- setDT(df_1, key=c("Match","Name"))[
  ,by=.(Match, Name), paste0("Period_", 1:10)
  := mclapply((1:10)*600, function(x) roll_mean(Dist, x))][]

它根据分配给windows 的值创建滚动平均值 我有一个可以复制它的工作函数,但是,我觉得有更好的方法可以做到这一点,因为函数版本需要将近 30 倍的时间来处理数据

dt_rolling <- function(df, the.keys, x, y, z, window){
  df <- data.table(df)
  setkeyv(df, the.keys) 
  df[,by=.(x,y), paste0("Period_", window) := mclapply(window, function(a) roll_mean(z, a))][]
}


df2 <- dt_rolling(df_1, the.keys=c('Match', 'Name'), df_1$Match, df_1$Name, df_1$Dist, windows)

有问题的数据是这样的

> dput(head(df_1, 5))
structure(list(Match = c("BathH", "BathH", "BathH", "BathH", 
"BathH"), Name = c("Alafoti Faosiliva", "Alafoti Faosiliva", 
"Alafoti Faosiliva", "Alafoti Faosiliva", "Alafoti Faosiliva"
), Dist = c(0, 0, 0, 0, 0), Period_1 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_2 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_3 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_4 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_5 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_6 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_7 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_8 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_9 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_10 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_600 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_1200 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_1800 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_2400 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_3000 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_3600 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_4200 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_4800 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_5400 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_), Period_6000 = c(NA_real_, NA_real_, 
NA_real_, NA_real_, NA_real_)), sorted = c("Match", "Name"), class =     c("data.table", 
"data.frame"), row.names = c(NA, -5L), .internal.selfref = <pointer:   0x10280cae0>)

它可以扩展到超过 2000 万行,这就是为什么我在这里使用 data.table 方法并研究将其更改为函数

编辑:

根据@jangorecki 关于添加data.table::frollmean() 的回答,我将frollmean 与基于Rcpp 的滚动平均函数进行了比较,该函数在具有1,500,000 行的数据集上使用microbenchmark

Unit: seconds
       expr      min       lq     mean   median       uq      max neval cld
       rcpp 1.056967 1.224827 1.374116 1.304310 1.467108 5.855003  1000  a 
 data.table 1.096122 1.306993 1.466128 1.389878 1.549299 9.287606  1000   b

【问题讨论】:

  • roll_mean() 的来源不包含在您的问题中,也不包含run_sum_v2()。很难理解你到底需要什么。您能否提供一个完整的最小可重现示例? THX :-)
  • roll_mean() 来自 RcppRoll 包。我用同样来自RcppRoll 包的类似功能替换了run_sum_v2()。在我的脚本中,我有基于 Rcpp 的 C++ 函数来加速滚动总和/平均值
  • 我编辑了标题,因为原来的标题毫无意义
  • 问题不在于分析速度,而是我必须在我的脚本中多次使用它,并寻找一种方法将其转换为自定义函数,而不会损失性能我对自定义函数的尝试

标签: r data.table


【解决方案1】:

从 v1.12.0 版本开始,data.table 中提供了快速滚动平均值。
以下查询将解决您的问题。

df_1[, paste0("Period_", windows) := frollmean(Dist, windows)]

【讨论】:

  • ** libs clang -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I/usr/local/include -fopenmp -fPIC -Wall -g -O2 -c assign.c -o assign.o clang: error: unsupported option '-fopenmp' make: *** [assign.o] Error 1 ERROR: compilation failed for package ‘data.table’ * removing ‘/Library/Frameworks/R.framework/Versions/3.5/Resources/library/data.table’ clang -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I/usr/local/include -fopenmp -fPIC -Wall -g -O2 -c assign.c -o assign.o clang: error: unsupported option '-fopenmp' make: *** [assign.o] Error 1
  • roll 分支不会为我安装上述错误
  • @NColl openmp on mac 是已知问题,您可以关注devel data.table installation wiki
  • data.table::frollmean 与添加到原始问题的基于 Rcpp 的滚动平均函数的比较。
  • @NColl 感谢您的基准测试,请包含微基准调用和代码以生成数据,以便其他人可以重新运行您的基准测试。
猜你喜欢
  • 1970-01-01
  • 2019-09-22
  • 2017-12-26
  • 2020-08-13
  • 1970-01-01
  • 2015-10-07
  • 2021-07-10
  • 1970-01-01
  • 2016-06-28
相关资源
最近更新 更多