【问题标题】:R dopar foreach on chunks instead of per lineR dopar foreach 块而不是每行
【发布时间】:2019-07-30 18:21:01
【问题描述】:

这个问题专门针对使用 foreach 和 dopar 在 R 中使用并行处理。我创建了一个简单的数据集和一个简单的操作(实际操作更复杂,因此我在这里介绍一个简单的操作)。数据代码和当前代码贴出来供大家参考。

加载包并创建数据

#Creating a mock dataframe
Area =c('XX','YY','ZZ','XX','YY','ZZ','XX','YY','ZZ','YY')
Car_type = c('A','A','B','C','B','C','A','A','B','C')
Variable1=c(.34,.19,.85,.27,.32,.43,.22,.56,.17,.11)
Variable2=c(.76,.3,.16,.24,.47,.23,.87,.27,.43,.59)
Final_data = data.frame(Area,Car_type,Variable1,Variable2)    
#replicate the above 100 times to create a bigger dataset
n =100
Final_data2=do.call("rbind", replicate(n, Final_data, simplify = FALSE))
Final_data2$Final_value = 0
#car_list = unique(Final_data2$Car_type) #have not figured out how to use this

dopar foreach 代码

#Create clusters and load required packages the clusters 
library(doParallel)    
cl=makeCluster(3,type="PSOCK") 
registerDoParallel(cl)


home1 <- function(zz1){
  output <- foreach(x = iter(zz1, by = "row"), .combine = rbind, 
                    .packages = "truncnorm") %dopar% {
    if (x$Car_type=='A'){
      x$Final_value = rtruncnorm(1,a=-1,b=1,mean = x$Variable1,sd=x$Variable2)
    } else if(x$Car_type=='B'){
      x$Final_value = rtruncnorm(1,a=-5,b=5,mean = x$Variable1,sd=1)  
    }  else{
      x$Final_value = rtruncnorm(1,a=-10,b=10,mean = 1,sd=1)
    }
    return(x)
  }
  output
}
Final_data3 <- home1(zz1=Final_data2)
stopCluster(cl) #Stop cluster

在第一部分中,我创建了一个名为 Final_data2 的示例数据框。 在第二部分中,基于“Car_type”列中的汽车类型,我从截断的正态分布中生成一个值,其中截断点以及均值和标准偏差根据 Car_type 变化。此代码以当前格式工作。在使用不同的内核后,它会遍历每一行。

问题

现在我想以这样一种方式扩展它,而不是在单独的核心上的每一行上迭代和运行操作,我想在数据集的块上运行操作。我想做的是在不同的核心上为不同的区域运行 dopar foreach 部分。例如。我想为集群 1 上的 Area = XX、集群 2 上的 Area = YY 和集群 3 上的 Area = ZZ 运行 dopar foreach 循环。不幸的是,我自己无法解决这个问题。有人会帮助我吗?任何帮助将不胜感激。

编辑 正如 Prive 所指出的,最初的问题有点令人困惑。我稍微修改了这个问题。如果现在更清楚一点,请告诉我。

【问题讨论】:

  • 我不确定我理解你想要什么。您能否提供一些您尝试解决问题的代码?
  • 我想先通过 Car_type 创建数据帧的子集,然后再运行函数,而不是通过数据帧的每一行进行迭代。我唯一微弱的尝试是将 iter 函数中的 by = "row" 更改为 by = car_list (数据创建部分代码的最后一行)。 car_list 只是所有独特汽车的列表。不幸的是,当我这样做时,我收到以下消息: match.arg(by) 中的错误:'arg' must be NULL or a character vector
  • 我不确定我是否理解您的问题,但您可能想查看包 {dplyr} 的函数 group_bycase_when
  • @F.Privé 嗨,Prive。我意识到是什么造成了混乱。请您看一下修改后的问题。我有一列区域(XX、YY、ZZ),我想在不同的集群上运行,而不是每行运行代码。这有意义吗。我意识到在以前的版本中,由于我有一列 Car_type 并且该函数本质上是循环遍历汽车类型,所以我的问题有点问题。
  • 您是否能够使用 dopar 方法做到这一点?我有类似的问题

标签: r foreach data-manipulation doparallel


【解决方案1】:

对于您的特定应用程序,我会使用pmap::purrr()

home2 <- function(Car_type, Variable1, Variable2) {
  if (Car_type=='A'){
    truncnorm::rtruncnorm(1,a=-1,b=1,mean = Variable1,sd=Variable2)
  } else if(Car_type=='B'){
    truncnorm::rtruncnorm(1,a=-5,b=5,mean = Variable1,sd=1)  
  }  else{
    truncnorm::rtruncnorm(1,a=-10,b=10,mean = 1,sd=1)
  }
}

Final_data2$Final_value <- 
  purrr::pmap_dbl(Final_data2[c("Car_type", "Variable1", "Variable2")], home2)

如果此操作确实需要很长时间,您可以使用包 {future} 和 {furrr} 轻松地将其并行化:

future::plan(future::multiprocess)
Final_data2$Final_value <- 
  furrr::future_pmap_dbl(Final_data2[c("Car_type", "Variable1", "Variable2")], home2)

【讨论】:

    猜你喜欢
    • 2018-07-13
    • 2016-08-02
    • 1970-01-01
    • 2016-03-11
    • 2015-05-22
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    相关资源
    最近更新 更多