R/MarkDown

[R Markdown] for loop로 chunk 여러개 만들기

슈퍼짱짱 2020. 7. 31. 14:37
반응형

R에서 마크다운으로 작업을 하다보면 컬럼만 다른 똑같은 그래프 혹은 테이블을 여러개 만들어야 하는 경우가 있다.

한 두개라면 그냥 복사 + 붙여넣기로 chunk를 새로 만들면 되지만, 그 수가 많아지면 일일이 만들기가 번거롭다. 이럴 때 하나의 chunk 안에 for 문으로 여러 chunk를 생성하는 방법을 소개하고자 한다.


1. Create multi Headers using for loop in one chunk

예제 데이터는 iris를 사용한다.

 

1
data < -iris
cs

 

한 번에 for loop로 여러개의 Header를 만드는 방법은 다음과 같다.

 

1. chunk 생성시 results = 'asis'  option 지정하기

2. for loop안에 cat() 으로 내용 입력하기

 

다음은 data의 컬럼명을 헤더로 출력하는 코드이다.

 

1
2
3
4
5
6
7
8
9
10
# header 
 
```{r, results='asis'}
 
for (i in 1:ncol(data)) {
cat("\n\n## ",names(data)[i], "\n\n")
cat("contens", i) ## contens
cat("\n\n")
}
```
cs

 

결과는 다음과 같다.

 

여기서 중요한 것은 chunk를 정의할 때 results = 'asis' option을 설정해 주는 것이다.

results = 'asis' option은 chunk의 output으로 출력되는 값들을 테두리 없이 출력해주는 옵션이다.(chunk 내의 output이 아니라 chunk 밖에 직접 쓴 효과)

 

참고) 해당 옵션을 지정해 주지 않으면 다음과 같은 결과가 생성된다.

 


2. Create multi Plots using for loop in one chunk

2-1. Create multi plots using for loop in one chunk

for loop로 한 번에 plot 그리는 방법은 다음과 같다.

 

1. chunk 생성시 results = 'asis'  option 지정하기

2. for loop 안에 plot 입력하기

 

다음은 data에서  numerical 변수인 Sepal.Length, Sepal.Width, Petal.Length, Petal.Width 에 대해서 Trend plot을 출력하는 코드이다.

 

1
2
3
4
5
6
7
8
9
10
# header + plot
 
```{r, results='asis'}
for (i in 1:4) {
  
  cat("\n\n## ",names(data)[i], "\n\n")
  plot(data[,i])
  cat("\n\n")
}
```
cs

 

결과는 다음과 같다.

 

 

Petal.Length, Petal.Width 변수에 대한 그래프도 생성되었지만 캡처의 한계로 생략한다.


기본 plot은 특별한 문법없이 기존에 사용하던데로 for loop안에 입력해주면 된다.

하지만, ggplot 같은 경우는 print() 혹은 grid.arrange() 로 그래프를 출력해주어야 한다.

 

참고) print() or grid.arrange() 없이 그냥 실행하면 다음과 같이 그래프는 출력되지 않는다.

 

1
2
3
4
5
6
7
8
# header + ggplot
 
```{r, results='asis'}
for (i in 1:4) {
  cat("\n\n## ",names(data)[i], "\n\n")
  ggplot(data,aes(x = 1:nrow(data), y = data[,i])) + geom_point()
}
```
cs

 


2-2. Create multi Header + ggplotly using for loop in one chunk

ggplotly처럼 인터랙티브한 그래프는 다음과 같이 출력한다.

* 인터랙티브 그래프란? 마우스 움직임에 반응하며 실시간으로 형태가 바뀌는 그래프

 

1. results = 'asis'

2. 그래프를 list 형태로 저장

3. HTML Tag 형태로 생성 (renderTags(x)$html)

4. 만들어진 Tag(Dependencies)를 HTML File에 Attach

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# header + ggplotly
 
```{r, results='asis'}
output <- list()
 
for (i in 1:4) {
  fig1 <- ggplot(data,aes(x = 1:nrow(data), y = data[,i])) + geom_point()
  output[[i]] <- ggplotly(fig1)
}
 
for (i in 1:4) {
  cat("\n\n## ",names(data)[i], "\n\n")
 
  x <- output[[i]]
  cat(renderTags(x)$html)
 
  cat("\n\n")
}
 
deps <- lapply(
  Filter(function(x){inherits(x,"htmlwidget")},output),
  function(hw){
    renderTags(hw)$dependencies
  }
)
 
attachDependencies(
  tagList(),
  unlist(deps,recursive=FALSE)
)
```
cs

 

 

결과는 다음과 같다.

 

 

캡처 이미지라서 다이나믹함이 보이지 않지만, 마우스를 가져다 대면 값이 보이고 확대, 축소도 가능한 인터랙티브 그래프이다.

 

HTML에서 Tag는 hyperlink를 의미한다. 아마 R에서 생성되는 테이블이나 그래프들을 하이퍼링크로서 입력시키는 듯 하다.


2-3. Create multi Header + dygraph using for loop in one chunk

ggplotly처럼 인터랙티브하지만 훨신 가벼운 dygraph 역시 같은 방법으로 출력할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# dygraph
 
```{r, results='asis'}
library(dygraphs)
 
output <- list()
 
for (i in 1:4) {
  plot.dat <- data.frame(idx = 1:nrow(data), dat = data[,i])
  p <- dygraph(plot.dat) %>%
    dyRangeSelector()
  output[[length(output) + 1]] <- p
}
 
for (i in 1:4) {
  cat("\n\n## ",names(data)[i], "\n\n")
 
  x <- output[[i]]
  cat(renderTags(x)$html)
 
  cat("\n\n")
}
 
deps <- lapply(
  Filter(function(x){inherits(x,"htmlwidget")},output),
  function(hw){
    renderTags(hw)$dependencies
  }
)
 
attachDependencies(
  tagList(),
  unlist(deps,recursive=FALSE)
)
 
```
cs

 

 

* 개인적으로 plotly보다는 dygraph를 더 선호한다.

데이터의 크기가 작을 때는 ggplotly와 dygraph 중 무엇을 쓰던 상관없지만, 데이터 크기가 클 때는 dygraph가 훨씬 가볍다는걸 느낄 수 있다.

 y축도 왼쪽, 오른쪽을 따로 지정할 수 있어 Scale을 해주지 않아도 두 변수에 대한 Trend를 바로 비교할 수 있는 등 여러 옵션이 많다. 

 

 


3. Create multi Tables using for loop in one chunk

이번에는 그래프가 아닌 테이블을 for loop로 출력하는 방법이다.

 

3-1. kable

R Markdown에서 table을 출력하는데 대표적으로 사용하는 funcion 이다. knitr 패키지에 있으며 이를 for loop로 출력하는 방법은 다음과 같다.

 

첫번째 컬럼부터 2번째, 3번째, ..., 5번째 컬럼까지의 데이터를 출력하는 코드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# kable {.tabset}
 
 
```{r, results='asis'}
 
for (i in 2:ncol(data)) {
  cat("\n\n## ",names(data)[i], "\n\n")
  
  print(kable(data[,c(1:i)]))
  
  cat("\n\n")
}
 
```
cs

 

위 ggplot처럼 그냥 출력하면 안되고 print() 로 출력해주어야한다.

만약, 작동하지 않는다면 kable() 안에 format = "html" 를 추가해보는 걸 추천한다.

 

* 참고로 {.tabset} 으로 아래 그림과 같이 Tab을 생성할 수 있다. 이렇게 하면 각 결과가 아래로 쭉 붙는 것이 아니라 Tab으로 생성되어 클릭하면 해당 결과를 볼 수 있다.

 

 

 

 


3-2. Summary

데이터에 대한 Summary 결과는 테이블 형태로 떨어지는 것이 아니기 때문에 pander로 출력해주어야 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
# Summary
 
 
```{r, results='asis'}
 
for (i in 1:ncol(data)) {
  cat("\n\n## ",names(data)[i], "\n\n")
  
  cat(summary(data[,i]) %>% pander::pander())
}
 
```
cs

 

 

참고) pander

 

Sepal.Length 에 대해 pander없이 그냥 summary한 결과 cat으로 출력하면 다음과 같다.

 

 

이를 pander로 출력하면 다음과 같이 테이블 형태로 출력된다.

 


3-3. DT::datatable

마크다운에서 테이블을 출력하는 다른 방법은 DT 패키지 안에 있는 datatable function이다.

kable은 row가 몇 개이던 간에 전체 데이터를 아래로 쭉 출력하는 반면, DT::datatable은 10개씩 나누어 보여주고, 컬럼명 클릭시 sorting도 가능하며, 검색기능도 있다.

 

첫번째 컬럼부터 2번째, 3번째, ..., 5번째 컬럼까지의 데이터를 DT 패키지로 출력하는 코드는 다음과 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
# DT
 
```{r, results='asis'}
 
for (i in 2:4) {
  cat("\n\n## ",names(data)[i], "\n\n")
  
  print(htmltools::tagList(DT::datatable(data[,(1:i)])))
  
  cat("\n\n")
}
 
```
cs

 

 

DT 테이블을 tagList안에 넣어주고, print로 출력한다.

 


All in one

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# All in One {.tabset}
 
```{r, results='asis'}
 
## list of graph
ggplotly_list <- list()
dygraph_list <- list()
 
for (i in 1:4) {
  ## col to draw plot
  plot.dat <- data.frame(idx = 1:nrow(data), dat = data[,i])
  
  ## ggplotly
  fig1 <- ggplot(plot.dat,aes(x = idx, y = dat)) + geom_point()
  ggplotly_list[[i]] <- ggplotly(fig1)
  
  ## dygraph
  fig2 <- dygraph(plot.dat) %>%
    dyRangeSelector()
  dygraph_list[[i]] <- fig2
}
 
## print graphs
for (i in 1:4) {
  ## header
  cat("\n\n## ",names(data)[i], "\n\n")
  
  ## print Summary
  cat("<b><font size='3' face='verdana'>[Summary]</font></b>", "<br><br>\n")
  cat(summary(data[,i]) %>% pander::pander())
  cat("\n\n<hr>\n\n") ## horizon line
  
  ## ggplot
  cat("<b><font size='3' face='verdana'>[ggplot]</font></b>", "<br><br>\n")
  print(ggplot(data,aes(x = 1:nrow(data), y = data[,i])) + geom_point())
  cat("\n\n<hr>\n\n") ## horizon line
  
  ## print ggplotly
  cat("<b><font size='3' face='verdana'>[ggplotly]</font></b>", "<br><br>\n")
  cat(renderTags(ggplotly_list[[i]])$html)
  cat("\n\n<hr>\n\n") ## horizon line
  
  ## print dygraph
  cat("<b><font size='3' face='verdana'>[dygraph]</font></b>", "<br><br>\n")
  cat(renderTags(dygraph_list[[i]])$html)
  cat("\n\n<hr>\n\n") ## horizon line
  
  ## DT
  cat("<b><font size='3' face='verdana'>[DT]</font></b>", "<br><br>\n")
  print(htmltools::tagList(DT::datatable(data[,(1:(i+1))])))
  cat("\n\n<hr>\n\n") ## horizon line
  
  cat("\n\n<br><br>\n\n")
}
 
## Attach
deps <- lapply(
  Filter(function(x){inherits(x,"htmlwidget")},ggplotly_list),
  function(hw){
    renderTags(hw)$dependencies
  }
)
 
attachDependencies(
  tagList(),
  unlist(deps,recursive=FALSE)
)
 
##
deps <- lapply(
  Filter(function(x){inherits(x,"htmlwidget")},dygraph_list),
  function(hw){
    renderTags(hw)$dependencies
  }
)
 
attachDependencies(
  tagList(),
  unlist(deps,recursive=FALSE)
)
 
```
cs

 

 

 


참고

 

1.  Markdown 기본 설정값

--- 
title: "Rmarkdown Train" 
author: "by SK C&C 이다경 선임 - 2020/07/31" 
output:  
  rmdformats::readthedown: 
    code_folding: hide 
--- 

<style> 
#TOC { 
  top: 1%; 
  opacity: 0.5; 
} 
#TOC:hover { 
  opacity: 1; 
} 
</style>

 

2. 마크다운 기본 옵션 설정값

knitr::opts_chunk$set(echo=TRUE, warning=FALSE, message=FALSE)

 

3. 사용 Library

library(xtable)
library(magrittr)
library(dlookr)
library(dplyr)
library(ggplot2)
library(gridExtra)
library(moments)
library(knitr)
library(kableExtra)

library(DT)
library(plotly)
library(magrittr)
library(htmltools)
library(pander)

 

4. ggplot 기본 옵션 설정값

old <- theme_set(theme_bw())

반응형