将列并行分配给 data.table

Posted

技术标签:

【中文标题】将列并行分配给 data.table【英文标题】:Assigning columns in parallel to a data.table 【发布时间】:2017-06-13 19:41:01 【问题描述】:

我想将许多(最多 2000+)列分配给 data.table;这个过程让我印象深刻,因为它具有出色的可并行性,但似乎通过将相同的 data.table 分发给许多工作人员来处理这个过程并没有得到很好的处理。

我希望以下工作:

library(data.table)
library(parallel)

NN = 100
JJ = 100

cl = makeCluster(2)
DT = data.table(seq_len(NN))
alloc.col(DT, 1.5*JJ)

clusterExport(cl, c("DT", "NN", "JJ"))
clusterEvalQ(cl, library(data.table))

parLapply(cl, seq_len(JJ), function(jj) 
  set(DT, , paste0("V", jj), rnorm(NN))
)

stopCluster(cl)

但是,这会产生一个模糊的错误:

checkForRemoteErrors(val) 中的错误: 2个节点产生错误;第一个错误:内部错误,请报告(包括sessionInfo()的结果)到datatable-help:oldtncol(0)

我想这是由于引用分配的工作原理。分配发生在每个线程上,但这不会在全局环境中传回DT

有没有办法将列并行添加到data.table

【问题讨论】:

嗯,有 DT[, paste0("v", seq_len(JJ)) := parLapply(cl, seq_len(JJ), function(jj) rnorm(NN)) ],虽然这并不比 DT2[, paste0("v", seq_len(JJ)) := replicate(JJ, rnorm(NN), simplify = FALSE) ] 快,你的 vars 有 1e5 和 2e3。 一个可行的解决方案的好主意,并解决分配给工人的问题。我想知道为什么它没有更快... 【参考方案1】:

以下内容适用于 Linux (Ubuntu 16.04)。 (注意:mcapply 不适用于 Windows) 我有兴趣了解这是否更快

> DT <- do.call("cbind",
               mclapply(seq_len(JJ), function(jj) 
  set(DT, , paste0("V", jj), rnorm(NN))
, mc.cores = detectCores()))

性能

在 12 核上运行

NN = 100000 JJ = 100

用户系统已过 1.172 2.756 41.707

NN = 100 JJ = 2000

用户系统已过 4.060 11.152 24.101

NN = 1000 JJ = 2000

用户系统已过 6.580 15.712 139.967

建议

我使用这样的东西来获得 2M 列和 600 行 (仍然不是最佳),希望它符合您的要求

system.time(
  DT2 <- as.data.table(matrix(rnorm(NN*JJ), ncol = JJ))
)

【讨论】:

以上是关于将列并行分配给 data.table的主要内容,如果未能解决你的问题,请参考以下文章

将列值分配给熊猫数据框中的唯一行[重复]

使用 Scala 将列分配给 Spark Dataframe 中的另一列

包含 data.table 名称的变量已就地更改? [复制]

data.table 中的内存泄漏按引用分组分配

data.table 连接然后将列添加到现有的 data.frame 而无需重新复制

Shiny:根据 selectInput 选择动态分配 var 名称