【问题标题】:Loop within RMarkdown code block在 RMarkdown 代码块内循环
【发布时间】:2017-06-18 16:14:54
【问题描述】:

我有一个类似这样的文件:

```{r, include = F}
require(data.table)

dt <- data.table(
  A = c(1, 4, 1, 4, 2, 4, 8),
  B = c(2, 2, 3, 4, 3, 1, 5)
)
```


```{r, echo = F}
col <- "A"

knitr::asis_output(paste0("### Column ", col, "\n"))

knitr::asis_output("Counts\n")

dt[, .(n = .N), by = col]

knitr::asis_output("Statistics\n")

summary(dt[, get(col)])
```


```{r, echo = F}
col <- "B"

knitr::asis_output(paste0("### Column ", col, "\n"))

knitr::asis_output("Counts\n")

dt[, .(n = .N), by = col]

knitr::asis_output("Statistics\n")

summary(dt[, get(col)])
```

虽然这很好用,但显然这是非常重复的。我尝试使用循环而不是复制粘贴,如下所示:

```{r, echo = F}
for (col in c("A", "B")) {
  knitr::asis_output(paste0("### Column ", col, "\n"))

  knitr::asis_output("Counts\n")

  dt[, .(n = .N), by = col]

  knitr::asis_output("Statistics\n")

  summary(dt[, get(col)])
}
```

然而,这根本不打印任何输出。如何在 RMarkdown 文档中循环并生成 Markdown 和 R 输出?

【问题讨论】:

标签: r knitr r-markdown


【解决方案1】:

对于summary 结果,您需要一个print 语句。您的代码将更改为以下内容,其中仅将 print 语句添加到 summary 输出:

```{r, echo = F}
for (col in c("A", "B")) {
  print(knitr::asis_output(paste0("### Column ", col)))

  print(knitr::asis_output("Counts"))

  print(dt[, .(n = .N), by = col])

  print(knitr::asis_output("Statistics"))

  print(summary(dt[, get(col)]))
}
```

这会产生以下结果:

## [1] "### Column A"
## attr(,"class")
## [1] "knit_asis"
## attr(,"knit_cacheable")
## [1] NA
## [1] "Counts"
## attr(,"class")
## [1] "knit_asis"
## attr(,"knit_cacheable")
## [1] NA
##    A n
## 1: 1 2
## 2: 4 3
## 3: 2 1
## 4: 8 1
## [1] "Statistics"
## attr(,"class")
## [1] "knit_asis"
## attr(,"knit_cacheable")
## [1] NA
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.000   1.500   4.000   3.429   4.000   8.000 
## [1] "### Column B"
## attr(,"class")
## [1] "knit_asis"
## attr(,"knit_cacheable")
## [1] NA
## [1] "Counts"
## attr(,"class")
## [1] "knit_asis"
## attr(,"knit_cacheable")
## [1] NA
##    B n
## 1: 2 2
## 2: 3 2
## 3: 4 1
## 4: 1 1
## 5: 5 1
## [1] "Statistics"
## attr(,"class")
## [1] "knit_asis"
## attr(,"knit_cacheable")
## [1] NA
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.000   2.000   3.000   2.857   3.500   5.000

您可能希望在打印时重新格式化和删除属性。

编辑

根据@user2554330 的建议,这里是一个使用knitr::knit_print 的示例:

```{r, echo = F}
for (col in c("A", "B")) {
  knitr::knit_print(paste0("### Column ", col))
  knitr::knit_print("Counts")
  knitr::knit_print(dt[, .(n = .N), by = col])
  knitr::knit_print("Statistics")
  knitr::knit_print(summary(dt[, get(col)]))
}
```

给出以下输出

## [1] "### Column A"
## [1] "Counts"
##    A n
## 1: 1 2
## 2: 4 3
## 3: 2 1
## 4: 8 1
## [1] "Statistics"
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.000   1.500   4.000   3.429   4.000   8.000 
## [1] "### Column B"
## [1] "Counts"
##    B n
## 1: 2 2
## 2: 3 2
## 3: 4 1
## 4: 1 1
## 5: 5 1
## [1] "Statistics"
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.000   2.000   3.000   2.857   3.500   5.000

编辑 2

以下替代解决方案将更准确地打印 SO 要求的内容。它全局删除“##”前缀并将其添加回data.frame(即仅在需要时)。它还使用cat 代替knitr::knit_print 来避免打印数组索引(即[1])。

```{r, echo = F, comment=NA}
for (col in c("A", "B")) {
  cat(paste0("Column ", col), "\n")
  cat("Counts\n")
  ## Add comment prefix
  tdf <- as.data.frame(dt[, .(n = .N), by = col]) ## Convert to data.frame for printing
  rownames(tdf) <- paste("## ", 1:nrow(tdf))      ## Add comments for printing.
  knitr::knit_print(tdf)
  cat("Statistics\n")
  ## Add comment prefix
  knitr::knit_print(summary(dt[, get(col)]))
}
```

下面的输出更多的是 SO 的要求(基于这篇文章的 cmets)。它在data.frame 输出前加上“##”前缀,但摘要输出没有“##”前缀;如果需要,可以添加。

Column A 
Counts
      A n
##  1 1 2
##  2 4 3
##  3 2 1
##  4 8 1
Statistics
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   1.500   4.000   3.429   4.000   8.000 
Column B 
Counts
      B n
##  1 2 2
##  2 3 2
##  3 4 1
##  4 1 1
##  5 5 1
Statistics
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   2.000   3.000   2.857   3.500   5.000 

【讨论】:

  • 您还可以将 knitr::asis_output() 调用和 dt[...] 包装在 print() 中以打印这些部分。
  • @user2554330 感谢您发现还需要为其他行添加打印语句。我还删除了“\n”,因为在这种情况下他们什么都不做。
  • 其实knitr::knit_print()会比print()好。
  • @user2554330 我用knitr::knit_print() 添加了解决方案。这应该更接近您的想法。
  • 感谢@steveb,通过knit_print 调用,我实际上得到了一些输出。然而,它的格式与未循环的版本非常不同。在此处查看 PDF 中的比较:gist.github.com/thomasfedb/f6d8d5dc9ba4558dd1eafa867715a0a5 还有其他提示吗?
猜你喜欢
  • 2017-12-08
  • 2021-12-29
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
  • 2015-09-02
  • 2013-09-03
  • 2022-01-14
  • 1970-01-01
相关资源
最近更新 更多