【问题标题】:Using a For-loop to create multiple tables使用 For 循环创建多个表
【发布时间】:2021-12-01 06:06:33
【问题描述】:

我试图弄清楚是否有一种方法可以使用 for 循环一次性创建多个表,所有表都使用相同的数据集 - 我会在一秒钟内澄清这一点。我正在使用 R Markdown,因为如果这有什么不同的话,我最终需要将它编译成 PDF。

所以我正在使用一个数据库并尝试根据其中一个变量的值将其分成多个表(使用 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)

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

所以我想做的是创建单独的表格来显示 X 县内所有城镇的年度预算。我已经能够通过为每个县创建新数据集然后制作一个表格来很好地做到这一点来自新数据集。当你只看 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",
    ) 

如果我不能让它工作,这不是世界末日,但我希望比我更精明的人能解决这个问题!

谢谢:)

【问题讨论】:

    标签: r for-loop gt


    【解决方案1】:

    经过一番挖掘,我找到了两个非常有用的链接,它们解决了我在循环中创建的 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()
    })
    
    ```
    

    【讨论】:

      【解决方案2】:

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

      使用来自tidyversepurrr 包进行迭代:

      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"))
      })
      

      【讨论】:

      • 谢谢!这与编译为 PDF 的演示数据完美配合,尽管一旦我回到更复杂的表格,我们将看看它是否仍然成立。感谢您的帮助!
      • 没问题。当在循环中指定时,我努力让gt 表格正确编织到 PDF(并发现其他人也有同样的问题)。不过,我最终确实找到了解决方案,并且由于我之前的答案已经很长了,所以我继续将解决方案发布为另一个答案。如果您遇到任何问题,也许它会有所帮助。
      【解决方案3】:

      只是在for 循环中,结果不是基于OP 的代码存储的。我们可以创建一个 NULL list of length 5 并根据循环的序列使用输出更新 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",
          ) )
      

      【讨论】:

      • 谢谢!!这很有意义。我想知道是否有办法进行拆分,因为我知道这在 SAS 中很容易,但我以前从未在 R 中尝试过。感谢您的帮助!
      猜你喜欢
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 2015-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多