如果并行化时表条件格式中包含变量,则使用 flextable 的循环 RMarkdown 渲染会失败

问题描述 投票:0回答:1

当我写下标题后,我意识到这个问题对我来说是多么具体。我使用循环从 .rmd 模板呈现 .docx 报告,该模板包含具有条件格式的弹性表格。我终于弄清楚了 R 中的并行化是如何工作的(某种程度上),并且我尝试将 for 循环转换为

foreach () %dopar% {}
表达式。它不起作用。我一直在研究它,我认为问题在于在弹性表条件格式中包含的主脚本中设置了一个变量。这只是
%dopar%
的问题;它与
%do%
配合得很好。在这些特定情况下,我收到一条错误消息,指出未找到该对象。

以下是一些有望重现的最小示例:

主要脚本

library(dplyr)
library(foreach)
library(doParallel)

boolean <- TRUE

tables <- list()

for (n in 1:10) {
  tables[[n]] <- iris %>%
    slice_sample(n = 20)
}

number_of_cores <- parallel::detectCores() - 1
clusters <- parallel::makeCluster(number_of_cores)
doParallel::registerDoParallel(clusters)

foreach (
  x = 1:10,
  .export = c("boolean", "tables"),
  .packages = c("dplyr", "flextable", "officer"),
  .verbose = TRUE
) %dopar%
  {
    rmarkdown::render("Template.rmd", output_file = paste0("Iris Subset ", x))
  }

.rmd 模板,在弹性表之外带有“布尔”变量。这在主脚本中使用

%dopar%
成功运行,并且是所需的输出

---
title: "Iris Data"
output: word_document
date: ""
---

```{r table}
if (boolean) {
flextable(tables[[x]]) %>%
  bg(i = ~ (Species == "setosa"), bg = "yellow", part = "body") %>%
  autofit()
} else {
  flextable(tables[[x]]) %>%
  bg(i = ~ (Species == "versicolor"), bg = "skyblue", part = "body") %>%
  autofit()
}

.rmd 模板,具有弹性条件格式中的“布尔”变量。这可以成功运行,主脚本中的

%do%
会产生与第一个模板相同的输出,但使用
%dopar%
会产生错误:
Error in { : task 1 failed - "object 'boolean' not found"

---
title: "Iris Data"
output: word_document
date: ""
---

```{r table}
flextable(tables[[x]]) %>%
  bg(i = ~ (Species == "setosa" & boolean), bg = "yellow", part = "body") %>%
  bg(i = ~ (Species == "versicolor" & !boolean), bg = "skyblue", part = "body") %>%
  autofit()
```

通过 rmarkdown::render 将值作为参数传递会产生相同的结果。有谁知道我该如何解决这个问题?

r foreach r-markdown flextable doparallel
1个回答
0
投票

我会小心地依赖 Rmarkdown 工作流程中的全局定义的变量。规范的方法是在 YAML 标头中使用参数并将这些参数显式传递给渲染进程。

parallel.Rmd

N.B. 我给了参数一些默认值,以便也能够手动运行它(或 Ctrl-Shift-K),但这是可选的。

---
title: "Iris Data"
output: word_document
date: ""
params:
  boolean: false
  tables: !r list(iris)
  x: 1
---

```{r}
library(flextable)
library(magrittr)
```

```{r table}
if (params$boolean) {
  flextable(params$tables[[params$x]]) %>%
    bg(i = ~ (Species == "setosa"), bg = "yellow", part = "body") %>%
    autofit()
} else {
  flextable(params$tables[[params$x]]) %>%
    bg(i = ~ (Species == "versicolor"), bg = "skyblue", part = "body") %>%
    autofit()
}
```

parallel.R

确保通过使用

R
强制
idx
使用
local
的专用副本(否则所有渲染进程都会收到 x
相同
值):

library(dplyr)
library(foreach)
library(doParallel)

boolean <- TRUE

tables <- list()

for (n in 1:10) {
  tables[[n]] <- iris %>%
    slice_sample(n = 20)
}

number_of_cores <- parallel::detectCores() - 1
clusters <- parallel::makeCluster(number_of_cores)
doParallel::registerDoParallel(clusters)

foreach (
  idx = 1:10,
  .verbose = TRUE
) %dopar%
  {
    local({
      x <- idx 
      rmarkdown::render(here::here("parallel.Rmd"), 
                        output_file = paste0("Iris Subset Sample", x), 
                        params = list(boolean = boolean, tables = tables, x = x))
    })
    
  }
© www.soinside.com 2019 - 2024. All rights reserved.