【问题标题】:Combinatorial iterator like expand.grid组合迭代器,例如 expand.grid
【发布时间】:2015-07-06 19:52:46
【问题描述】:

有没有一种快速的方法来遍历expand.gridCJ (data.table) 返回的组合。当有足够的组合时,它们会变得太大而无法放入内存。 itertools2 库(Python 的 itertools 的端口)中有 iproduct,但它真的很慢(至少我使用它的方式 - 如下所示)。还有其他选择吗?

这是一个示例,其想法是将函数应用于来自两个 data.frames (previous post) 的行的每个组合。

library(data.table)  # CJ
library(itertools2)  # iproduct iterator
library(doParallel)

## Dimensions of two data
dim1 <- 10
dim2 <- 100
df1 <- data.frame(a = 1:dim1, b = 1:dim1)
df2 <- data.frame(x= 1:dim2, y = 1:dim2, z = 1:dim2)

## function to apply to combinations
f <- function(...) sum(...)

## Too big to expand with bigger dimensions (ie, 1e6, 1e5) -> errors
## test <- expand.grid(seq.int(dim1), seq.int(dim2))
## test <- CJ(indx1 = seq.int(dim1), indx2 = seq.int(dim2))
## Error: cannot allocate vector of size 3.7 Gb

## Create an iterator over the cartesian product of the two dims
it <- iproduct(x=seq.int(dim1), y=seq.int(dim2))

## Setup the parallel backend
cl <- makeCluster(4)
registerDoParallel(cl)

## Run
res <- foreach(i=it, .combine=c, .packages=c("itertools2")) %dopar% {
  f(df1[i$x, ], df2[i$y, ])
}
stopCluster(cl)

## Expand.grid results (different ordering)
expgrid <- expand.grid(x=seq(dim1), y=seq(dim2))
test <- apply(expgrid, 1, function(i) f(df1[i[["x"]],], df2[i[["y"]],]))

all.equal(sort(test), sort(res))  # TRUE

【问题讨论】:

  • 我怀疑您正在尝试解决更一般的情况,但 rowSums 显然是这里的第一步:rs1 &lt;- rowSums(df1); rs2 &lt;- rowSums(df2); res2 &lt;- outer(rs1,rs2,"+") 检查... sum(res-c(t(res2))) # 0 我不认为并行化是当每项任务都很小时非常有用。
  • @Frank 是的,这只是一个简单的例子,我想将索引组传递给核心,因此每个都可以作为一个块处理。
  • 我将最小的data.frame 分割成块,这样最大的data.frame 的expand.grid 结果和另一个块的结果是可管理的。然后,我会遍历所有的块。

标签: r parallel-processing iterator combinations


【解决方案1】:

我认为,如果您给每个工作人员一个数据帧的一部分,让他们各自执行计算,然后合并结果,您将获得更好的性能。这样可以提高计算效率并减少工作人员的内存使用量。

这是一个使用 itertools 包中的 isplitRow 函数的示例:

library(doParallel)
library(itertools)
dim1 <- 10
dim2 <- 100
df1 <- data.frame(a = 1:dim1, b = 1:dim1)
df2 <- data.frame(x= 1:dim2, y = 1:dim2, z = 1:dim2)
f <- function(...) sum(...)

nw <- 4
cl <- makeCluster(nw)
registerDoParallel(cl)

res <- foreach(d2=isplitRows(df2, chunks=nw), .combine=c) %dopar% {
  expgrid <- expand.grid(x=seq(dim1), y=seq(nrow(d2)))
  apply(expgrid, 1, function(i) f(df1[i[["x"]],], d2[i[["y"]],]))
}

我拆分 df2 因为它有更多行,但你可以选择其中一个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-24
    • 2014-02-12
    • 2011-09-24
    • 1970-01-01
    • 2019-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多