【发布时间】:2016-03-10 21:31:38
【问题描述】:
我必须对大表的每一行(~ 2M 行)应用一个函数。我曾经为此使用plyr,但表格不断增长,当前的解决方案开始接近不可接受的运行时间。我以为我可以切换到data.table 或dplyr,一切都很好,但事实并非如此。
这是一个例子:
library(data.table)
library(plyr)
library(dplyr)
dt = data.table("ID_1" = c(1:1000), # unique ID
"ID_2" = ceiling(runif(1000, 0, 100)), # other ID, duplicates possible
"group" = sample(LETTERS[1:10], 1000, replace = T),
"value" = runif(1000),
"ballast1" = "X", # keeps unchanged in derive_dt
"ballast2" = "Y", # keeps unchanged in derive_dt
"ballast3" = "Z", # keeps unchanged in derive_dt
"value_derived" = 0)
setkey(dt, ID_1)
extra_arg = c("A", "F", "G", "H")
ID_1 保证不包含重复项。现在我定义一个函数应用于每一行/ID_1:
derive = function(tmprow, extra_arg){
if(tmprow$group %in% extra_arg){return(NULL)} # exlude entries occuring in extra_arg
group_index = which(LETTERS == tmprow$group)
group_index = ((group_index + sample(1:26, 1)) %% 25) + 1
new_group = LETTERS[group_index]
if(new_group %in% unique(dt$group)){return(NULL)}
new_value = runif(1)
row_derived = tmprow
row_derived$group = new_group
row_derived$value = runif(1)
row_derived$value_derived = 1
return(row_derived)
}
这个没有做任何有用的事情(实际有)。关键是该函数取一行并计算相同格式的新行。
现在比较一下:
set.seed(42)
system.time(result_dt <- dt[, derive(.SD, extra_arg), by = ID_1])
set.seed(42)
system.time(result_dplyr <- dt %>% group_by(ID_1) %>% do(derive(., extra_arg)))
set.seed(42)
system.time(results_plyr <- x <- ddply(dt, .variable = "ID_1", .fun = derive, extra_arg))
plyr 比 data.table 和 dplyr 快大约 8 倍。显然我在这里做错了什么,但是什么?
编辑
感谢 eddi 的回答,我可以将 data.table 和 dplyr 的运行时间分别减少到 plyr 版本的 ~ 0.6 和 0.8。我将row_derived 初始化为data.frame:row_derived = as.data.frame(tmprow)。这很酷,但我仍然希望这些软件包能带来更高的性能提升......还有什么建议吗?
【问题讨论】:
-
您正在对 data.table 使用 data.frame 语法,因此您不应期望获得 data.table 速度 :) 正如 eddi 指出的那样,您应该寻找矢量化解决方案,目前您基本上是在循环@ 987654335@ 超过
ID_1。 -
@jangorecki:您的意思是一次修改一列?我怀疑这在我的情况下是否可行。
-
我的意思是使用
$<-而不是使用:=
标签: r performance data.table dplyr plyr