在嵌套字段中应用函数时,data.table表现不佳。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在嵌套字段中应用函数时,data.table表现不佳。相关的知识,希望对你有一定的参考价值。

我写了一个函数,将另一个函数应用到data.table的每个嵌套字段中。

n <- 3000
nameslist <- paste0("NAME",1:n)
dt <- data.table(name_var = nameslist
                    , value_var = rnorm(1e7)
                    , car_color = c("B","B","B","G","G","G","G"))
dt <- dt[,.(.(.SD)), by = name_var] # nesting dt and finishing toy data creation

transform_value <- function(x, fun, campo, ...) {  
     x [, match.fun (fun)(get(campo), ...)] }

system.time({
dt[, min_value:=lapply(V1, transform_value, "min", "value_var")
]}) 

这个函数运行得很正确,速度也很快,在我的机器上大约需要0.36秒 n <- 3000.

然而,当我做 n <- 500000 (nameslist长度为500,000长),需要217秒!

因此,似乎data.table没有被我在循环中写的代码有效地优化。dt[, min_value:=lapply(V1, transform_value, "min", "value_var"). 我的看法是,每次data.table进入嵌套循环的每个实例都会有一个开销,但我不确定。

我怎样做才能使它运行得更快?

答案

既然你是通过性能来感兴趣的,你一定要设置一个主键。一旦支付了设置主键的固定成本(这意味着你的行在连续内存插槽中的重新排序),你将体验到显著的收益。

再拿你的例子来说

dt <- data.table(name_var = nameslist
                 , value_var = rnorm(1e7)
                 , car_color = c("B","B","B","G","G","G","G"))
dt2 <- data.table::copy(dt)
setkeyv(dt2, c("name_var"))

microbenchmark::microbenchmark(
  dt[,.(.(.SD)), by = name_var],
  dt2[,.(.(.SD)), by = name_var],
  times = 20L
)

Unit: milliseconds
                            expr       min        lq     mean    median       uq      max neval
  dt[, .(.(.SD)), by = name_var] 658.76452 676.22905 706.3578 699.46644 727.8368 793.1192    20
 dt2[, .(.(.SD)), by = name_var]  91.62276  92.48002 131.2777  99.15238 135.1332 318.3719    20

就这一步,在我的笔记本上(那速度不快),你看计算时间除以7(数量级可能会有很大的差异

以上是关于在嵌套字段中应用函数时,data.table表现不佳。的主要内容,如果未能解决你的问题,请参考以下文章

当data.table:=是最后一个操作时,R函数返回而不返回data.table对象[duplicate]

R:嵌套 data.table 到 JSON

将字符串转换为列表并嵌套在data.table中

在 data.table 中逐行应用返回列表/矩阵的函数

使用带有data.table的滚动功能

警告:将列添加到从函数返回的 data.table 时“检测到无效 .internal.selfref”