我使用foreach来并行化我的代码.然而,我发现无论我是否在循环末尾添加print语句,结果都是不同的.

下面是print语句的结尾(我得到了我想要的结果):

library(foreach)

grid <- expand.grid(
  lambda=c(1,2),
  mtry=c(1),
  nodsize=c(1)
)

n.cores <- parallel::detectCores() - 1
#https://stackoverflow.com/a/16718078/1979665
my.cluster <- parallel::makeCluster(n.cores, outfile = "")
doParallel::registerDoParallel(cl = my.cluster)
params.all <- foreach (i = 1:nrow(grid), .combine = "rbind") %dopar% {
  params <- grid[i,]
  params$rmse <- "foo"
  print(params)
}
parallel::stopCluster(cl = my.cluster)
params.all

结果是:

  lambda mtry nodsize rmse
1      1    1       1  foo
2      2    1       1  foo

以下是结尾处的print句话:

library(foreach)

grid <- expand.grid(
  lambda=c(1,2),
  mtry=c(1),
  nodsize=c(1)
)

n.cores <- parallel::detectCores() - 1
#https://stackoverflow.com/a/16718078/1979665
my.cluster <- parallel::makeCluster(n.cores, outfile = "")
doParallel::registerDoParallel(cl = my.cluster)
params.all <- foreach (i = 1:nrow(grid), .combine = "rbind") %dopar% {
  params <- grid[i,]
  params$rmse <- "foo"
  # print(params) LINE COMMENTED
}
parallel::stopCluster(cl = my.cluster)
params.all

现在的结果是:

         [,1] 
result.1 "foo"
result.2 "foo"

这是不是很奇怪,还是很正常?

推荐答案

这是预期行为,与并行处理或dopar无关.关键是要问自己"每次迭代dopar的实际输出是什么?"

要回答这个问题,您需要意识到print以不可见的方式返回它正在打印的对象:

x <- 1:3
y <- print(x)
#> [1] 1 2 3

y
#> [1] 1 2 3

而赋值为<-则会默默地返回赋值值:

y <- (x <- "foo")

y
#> [1] "foo"

在您的第一个版本中,print个未注释,每个dopar迭代输出params,因为dopar循环中的最后一个调用是print(params).

当您注释掉行print(params)时,每个迭代的最后一行是params$rmse <- "foo",因此您的迭代实际上并不是输出params.它返回赋值params$rmse <- "foo"的输出,这只是字符串"foo".因此,对于dopar的每次迭代,您只得到一个字符串"foo".

我们可以看到这是仅使用碱基R:的标准行为:

params.all <- do.call('rbind',
  lapply(1:3, function(i) {
      params <- iris[i,]
      params$Species <- 'foo'
      print(params)
}))

params.all
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1          5.1         3.5          1.4         0.2     foo
#> 2          4.9         3.0          1.4         0.2     foo
#> 3          4.7         3.2          1.3         0.2     foo

对战

params.all <- do.call('rbind',
  lapply(1:3, function(i) {
      params <- iris[i,]
      params$Species <- 'foo'
      #print(params)
}))

params.all
#>      [,1] 
#> [1,] "foo"
#> [2,] "foo"
#> [3,] "foo"

解决方案是确保在dopar循环结束时专门返回对象.你可以只做最后一行params,而不是print(params).

换句话说,您的问题可以重写为"只有当我从循环中返回正确的对象时,foreach才能提供预期的输出"

R相关问答推荐

在通过最大似然估计将ODE模型与数据匹配时,为什么要匹配实际参数的转换值?

使用gggrassure减少地块之间的空间

在垂直轴中包含多个ggplot2图中的平均值

通过使用str_detect对具有相似字符串的组进行分组

根据选中三个复选框中的一个或两个来调整绘图

在R中替换函数中的特定符号

如何在R中添加截止点到ROC曲线图?

bslib::card_header中的shine::downloadButton,图标而不是文本

我如何才能找到FAMILY=POISSON(LINK=&Q;LOG&Q;)中的模型预测指定值的日期?

R—将各种CSV数字列转换为日期

多个模拟序列间的一种预测回归关系

将重复项转换为NA

用两种 colored颜色 填充方框图

将多个列值转换为二进制

从R中发出的咕噜声中的BUG?

用多边形替换地块点

如何在使用因子时获得Sankey图的Scale_Fill_Viridis的全范围

在使用ggplot2的情况下,如何在使用coord_trans函数的同时,根据未转换的坐标比来定位geom_瓷砖?

我有2011-2022年的年度数据.如何计算最低年份和最高年份之间的差额?

如何使用ggsurvfit包更改风险表中的标签名称?