使用 mclapply、foreach 或 [r] 中的其他内容并行操作对象?

loc*_*off 3 memory parallel-processing foreach fork r

有没有办法并行操作一个对象R?我了解mclapplyparallelfork 进程中并将工作区内容复制到每个进程。相反,我希望让我的核心在一个对象上执行独立的工作,而不必拆分和组合结果。一个用例是将numericdata.frame 中的所有列更改为factor并行列。另一个用例是对具有大量级别的 data.frame 中的因子进行分箱。我尝试这样做的主要原因是 1) 避免内存不足,2) 提高速度。

下面, object是在 data.frame 中拆分列,然后在应用 后将它们合并b的结果。相反,我想直接对对象进行操作。在串行中,我能够将列转换为类型,作为循环的副作用。同时,作为副作用,我无法将 的列转换为类型,因为(据我所知)在,内部指的是每个生成进程的本地对象。afactoraafactorforeach...%do%afactorforeach...%dopar%a

有一个包R可以让我这样做吗?

a <- data.frame(b=c(1,1,2,2), c=c(2,2,3,3))
str(a)

> str(a)
'data.frame':   4 obs. of  2 variables:
 $ b: num  1 1 2 2
 $ c: num  2 2 3 3

#serial
b <-
  foreach (i = iter(1:ncol(a)), .combine = data.frame) %do% {
    a[,i] <- factor(a[,i])
  }
str(a)
str(b)

> str(a)
'data.frame':   4 obs. of  2 variables:
 $ b: Factor w/ 2 levels "1","2": 1 1 2 2
 $ c: Factor w/ 2 levels "2","3": 1 1 2 2
> str(b)
'data.frame':   4 obs. of  2 variables:
 $ result.1: Factor w/ 2 levels "1","2": 1 1 2 2
 $ result.2: Factor w/ 2 levels "2","3": 1 1 2 2

#parallel
a <- data.frame(b=c(1,1,2,2), c=c(2,2,3,3))
b <-
  foreach (i = iter(1:ncol(a)), .combine = data.frame) %dopar% {
    a[,i] <- factor(a[,i])
  }
str(a)
str(b)

> str(a)
'data.frame':   4 obs. of  2 variables:
 $ b: num  1 1 2 2
 $ c: num  2 2 3 3
> str(b)
'data.frame':   4 obs. of  2 variables:
 $ result.1: Factor w/ 2 levels "1","2": 1 1 2 2
 $ result.2: Factor w/ 2 levels "2","3": 1 1 2 2
Run Code Online (Sandbox Code Playgroud)

Jor*_*eys 5

首先,您必须意识到 R (通常)是call by value,所以无论您做什么,您最终都会得到数据帧的临时副本。这也适用于 apply 系列的普通版本。一旦您更改函数内部的某些内容,首先会复制该对象。

也就是说,mclapply不会将完整的工作区内容复制到子进程。据我了解,这些进程共享相同的内存内容,并且仅在对其进行修改后才复制内容。这或多或少取决于 R 所做的事情。

如果您仍然不相信这一点,您可以使用集群方法并尝试parLapply使用包中的朋友parallel。这不是基于分叉,而是基于节点集群。您可以在此处将核心视为节点。在这种情况下,您必须使用 显式从计算所需的工作区导出变量clusterExport()。我对此不确定,但我怀疑这确实会创建一个副本。对于其余部分,parLapply仅将其作用的元素复制到不同的集群。同样,这与默认情况下的情况相当相同lapply

使用您的数据框a,您可以执行以下操作:

> require(parallel)
> cl <- makeCluster(2)
> b <- parLapply(cl,a,as.factor)
> str(as.data.frame(b))
'data.frame':   4 obs. of  2 variables:
 $ b: Factor w/ 2 levels "1","2": 1 1 2 2
 $ c: Factor w/ 2 levels "2","3": 1 1 2 2
> stopCluster(cl)       
Run Code Online (Sandbox Code Playgroud)