使用 For 循环创建多个表

Using a For-loop to create multiple tables

我正在尝试找出是否有一种方法可以使用 for 循环一次性创建多个 table,所有这些都使用相同的数据集 - 我稍后会对此进行说明。我正在使用 R Markdown,因为最后我需要将它编译成 PDF,如果这有什么不同的话。

所以我正在使用一个数据库并尝试根据其中一个变量的值将其分成多个 tables(使用 gt)。假设我的数据集是关于城镇的年度预算。

data <- data.frame(x=1, y=1:15, z=16:30)
colnames(data) <- c("County", "Town", "Budget")
sample.space <- c(1:5)
number.samples <- 15
data$County <- sample(sample.space, number.samples, replace = TRUE)
sample.space2 <- c(2500:5000)
data$Budget <- sample(sample.space2, number.samples, replace = FALSE)

(请原谅我的创作有些笨拙,这些天我不经常处理随机数。)

所以我想做的是创建单独的 tables 来显示 X 县内所有城镇的年度预算。我已经能够通过为每个县,然后从新数据集中制作 table。当你只查看 5 个县时,这很好,但是当它是 50 个时,那就有点麻烦了。

我觉得应该有一些方法可以使用 for 循环来做到这一点。我的直觉是这样做的,但是当我编译时,PDF 上没有打印任何内容。

library(gt)

for (i in 1:5) {
  data[data$County == i, ] %>%
    gt() %>%
    tab_header(
      title = "Annual Budget by County",
    ) 
}

如果我选择一个县并在没有循环的情况下尝试同样的事情,我没有问题。

data[data$County == 1, ] %>%
    gt() %>%
    tab_header(
      title = "Annual Budget for County 1",
    ) 

如果我做不到,那不是世界末日,但我希望比我更精明的人能弄明白!

谢谢:)

只是在for循环中,结果不是根据OP的代码存储的。我们可以创建一个 NULL list of length 5 并使用基于序列 looped

的输出更新 list
lst1 <- vector('list', 5)
for (i in 1:5) {
 lst1[[i]] <- data[data$County == i, ] %>%
    gt() %>%
    tab_header(
      title = "Annual Budget by County",
    ) 
}

如果我们想创建多个对象,可以使用 assign 但不推荐,即最好将其保存在 list


或者另一种选择是 split by 'County' 并使用 lapply 循环转换为 gt

lst1 <- lapply(split(data, data$County), function(x) 
              gt(x) %>%
      tab_header(
      title = "Annual Budget by County",
    ) )

编辑:由于您似乎还想在 Rmarkdown 文档中输出其中的每一个,因此我添加了有关如何执行此操作的说明。但是,此解决方案可能仅适用于使用 gt 包编写 html 文档。编织成 pdf 会引发超出此问题范围的许多其他问题,但总的来说,使用 kables 而不是 gt 编织成 pdf 可能会有更好的体验。

使用 tidyverse 中的 purrr 包进行迭代:

library(gt)
library(htmltools)
library(tidyverse)

counties <- data$County %>% 
  unique() %>%
  sort()

gt_list <- map(.x = counties,  .f = function(x) {
  data %>%
    filter(County == x) %>%
    gt() %>%
    tab_header(
      title = paste("Annual Budget for County", x),
    ) 
})

然后您可以将 gt 表列表包装在 htmltools 包中的 tagList 中,以在您的 Rmarkdown 文档中呈现它们中的每一个:

tagList(gt_list)

如果您绝对需要编织成 pdf,请尝试使用 kables 而不是 gt,将 map 替换为 walk(因为您现在只是为了打印 kable 的副作用而迭代) .另外,确保设置块选项 results = "asis":

```{r, results = "asis"}
walk(.x = counties,  .f = function(x) {
  df <- data %>%
    filter(County == x) 
    
  print(knitr::kable(df, caption = paste("Annual Budget for County", x)))
  cat('\n\n\n\n')
})
```

最后,如果您只想将每个 gt 输出到它自己的 pdf 文件(或类似文件),您可以执行以下操作:

walk(.x = counties,  .f = function(x) {
  data %>%
    filter(County == x) %>%
    gt() %>%
    tab_header(
      title = paste("Annual Budget for County", x),
    ) %>%
    gtsave(paste0("County_", x, ".pdf"))
})

经过一些挖掘,我找到了两个非常有用的链接,它们解决了我在循环中创建 gt 表的 Knit to PDF 问题。 YMMV:

  1. 使用as_latex()
  2. Modify 你的 Rmarkdown yaml

因此,您的整个 Rmarkdown 文件可能如下所示:

---
title: "gt package pdf output"
output:
  pdf_document: default
header-includes:
- \usepackage{caption} # Insert the package used by gt
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```

```{r, include=FALSE}

library(tidyverse)
library(gt)

data <- data.frame(x=1, y=1:15, z=16:30)
colnames(data) <- c("County", "Town", "Budget")
sample.space <- c(1:5)
number.samples <- 15
data$County <- sample(sample.space, number.samples, replace = TRUE)
sample.space2 <- c(2500:5000)
data$Budget <- sample(sample.space2, number.samples, replace = FALSE)

counties <- data$County %>% 
  unique() %>%
  sort()

```

```{r, results="asis"}

walk(.x = counties,  .f = function(x) {
  data %>%
    filter(County == x) %>%
    gt() %>%
    tab_header(
      title = paste("Annual Budget for County", x),
    ) %>%
    as_latex() %>% 
    as.character() %>%
    cat()
})

```