【问题标题】:Speed up row-wise operations in data.table加快 data.table 中的逐行操作
【发布时间】:2013-05-24 06:11:04
【问题描述】:

与数据帧相比,使用data.table 进行类似tapply 的操作在速度方面的提升给我留下了深刻的印象。

例如:

df = data.frame(class = round(runif(1e6,1,1000)), x=rnorm(1e6))
DT = data.table(df)

# takes ages if somefun is complex
res1 = tapply(df$x, df$class, somefun) 

# takes much faster 
setkey(DT, class)
res2 = DT[,somefun(x),by=class] 

但是,在类似apply 的操作(即,需要将函数应用于每一行的情况)中,我并没有设法让它明显快于数据帧。

df = data.frame(x1 = rnorm(1e6), x2=rnorm(1e6))
DT = data.table(df)

# takes ages if somefun is complex
res1 = apply(df, 1, somefun) 

# not much improvement, if at all 
DT[,rowid:=.I] # or: DT$rowid = 1:nrow(DT)
setkey(DT, rowid)
res2 = DT[,somefun1(x1,x2),by=rowid] 

这真的只是意料之中还是有一些技巧?

【问题讨论】:

  • apply 将在内部强制转换为矩阵(复制,列必须全部相同)。 data.table 有很多开销——你真的想矢量化一些乐趣
  • 我希望你能在矢量化 somefun 时玩得开心。
  • 不幸的是,我只能想象通过迭代行号 rowid 然后在 mclapply 中为 df[rowid,] 运行并行计算来“矢量化”它。这可以完成这项工作,但非常耗费资源。
  • 这是不可重现的,但即使显示了什么,我们也可以看到,在帖子的后半部分,这两个代码没有可比性——在 res1 的计算中,一个参数被传递给 @ 987654329@ 和res2 的情况下传递了两个参数。
  • 是的,确实 somefun 在这两种情况下都必须写得有点不同,但我的印象是其他人理解我的意思。在上一个示例中将 somefun 更改为 somefun1 以避免混淆。是的,mnel 通过矢量化为我打开了全新的世界,正如我现在所意识到的 - 非常感谢!

标签: r data.table


【解决方案1】:

如果你不能向量化你的函数(因为递归......)那么你就属于Rcpp 领域。 使用Rcppdata.table 的通常规则是

  1. 相应地塑造你的data.table (setkey...)
  2. 写信给你C?C++ 函数说f 将接受Rcpp::DataFrame 并返回Rcpp::List
  3. 通过引用更新 cppOutList <- f(DT), DT[,names(cppOutList):=cppOutList]

这样做通常会让你节省数量级

【讨论】:

    【解决方案2】:

    使用set 可能会大大提高逐行操作的速度。这里有一个很好的基准:Row operations in data.table using `by = .I`

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-12
      • 1970-01-01
      • 2011-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-12
      • 2020-07-18
      相关资源
      最近更新 更多