`source ( 'myfile.r')`과 같은 R Markdown 파일을 소싱하는 방법은 무엇입니까?


89

나는 종종 source다른 R 파일 (예 : 데이터 처리 용)에 메인 R Markdown 파일이나 knitr LaTeX 파일을 가지고 있습니다. 그러나 어떤 경우에는 이러한 소스 파일을 자신의 재현 가능한 문서 (예 : 데이터 처리 명령을 포함 할뿐만 아니라 데이터 처리 결정을 설명하는 재현 가능한 문서를 생성하는 R Markdown 파일)를 사용하는 것이 유익 할 것이라고 생각했습니다. ).

따라서 source('myfile.rmd')기본 R Markdown 파일 과 같은 명령을 갖고 싶습니다 . .NET의 R 코드 청크 내부의 모든 R 코드를 추출하고 소싱합니다 myfile.rmd. 물론 이것은 오류를 발생시킵니다.

다음 명령이 작동합니다.

```{r message=FALSE, results='hide'}
knit('myfile.rmd', tangle=TRUE)
source('myfile.R')
```

여기서, results='hide'출력이 요구 된 경우에 생략 될 수있다. 즉, knitr는 R 코드 myfile.rmdmyfile.R.

그러나 완벽하지 않은 것 같습니다.

  • 추가 파일이 생성됩니다.
  • 디스플레이에 대한 제어가 필요한 경우 자체 코드 청크에 나타나야합니다.
  • 단순한 것만 큼 우아하지는 않습니다 source(...).

따라서 내 질문 : R Markdown 파일의 R 코드를 소싱하는 더 우아한 방법이 있습니까?


나는 실제로 귀하의 질문을 이해하는 데 정말 어려움을 겪고 있습니다 (여러 번 읽었습니다). 다른 R 스크립트를 Rmd파일 로 쉽게 소싱 할 수 있습니다 . 그러나 다른 markdown파일의 소스를 파일로 만들고 싶 습니까?
마이 아사 우라 (Maiasaura)

4
R Markdown 파일 (예 : * .rmd)의 R 코드 청크 내에서 R 코드를 소싱하고 싶습니다. 좀 더 명확하게하기 위해 질문을 약간 수정했습니다.
제로미 Anglim

include라텍스 의 라인을 따라 뭔가 . 마크 다운이 다른 마크 다운 문서의 포함을 지원하는 경우 이러한 기능을 생성하는 것이 상대적으로 쉬워야합니다.
폴 Hiemstra

@PaulHiemstra 텍스트와 R 코드 청크를 소싱하는 기능도 유용 할 것이라고 생각합니다. 특히 R Markdown 문서의 코드 만 소싱하려고합니다.
Jeromy Anglim 2012 년

답변:


35

한 줄짜리를 찾고 계신 것 같습니다. 이것을 당신의 .Rprofile?

ksource <- function(x, ...) {
  library(knitr)
  source(purl(x, output = tempfile()), ...)
}

그러나 source()Rmd 파일 자체의 코드 를 원하는 이유를 이해할 수 없습니다 . 내 말은 knit()이 문서에서 모든 코드를 실행하고 코드를 추출하고 덩어리에서 실행하는 경우, 모든 코드가 실행됩니다 두 번 때 knit()이 문서 (당신이 자신의 내부에 자신을 실행). 두 작업은 분리되어야합니다.

정말로 모든 코드를 실행하고 싶다면 RStudio가 이것을 상당히 쉽게 만들었습니다 Ctrl + Shift + R. 그것은 기본적으로 호출 purl()하고 source()장면 뒤에.


8
안녕하세요 @Yihui 저는 때때로 분석이 작은 스크립트로 구성 될 수 있기 때문에 유용하다고 생각하지만 보고서에는 전체 파이프 라인에 대한 코드가 있어야합니다.
lucacerone

9
따라서 여기서 사용 사례는 모든 코드를 작성하고 심도있게 문서화하고 설명하고 싶지만 코드는 다른 스크립트에 의해 실행되는 것입니다.
Brash Equilibrium

4
@BrashEquilibrium 코드를 사용 source()하거나 knitr::knit()실행 하는 문제입니다 . 나는 사람들이 후자에 덜 익숙하다는 것을 알고 있지만 purl()신뢰할 수는 없습니다. 경고 : github.com/yihui/knitr/pull/812#issuecomment-53088636
Yihui Xie

5
@Yihui 당신의 관점에서 'source (purl (x, ...))'에 대한 제안 된 대안은 무엇입니까? 중복 청크 레이블과 관련된 오류없이 어떻게 여러 * .Rmd-Files를 소싱 할 수 있습니까? 나는 소스가 될 문서로 돌아가서 그것을 짜고 싶지 않습니다. 나는 잠재적으로 다른 사람들과 내보내고 논의해야하는 많은 파일에 * .Rmd를 사용하므로 모든 분석 단계에 대해 여러 Rmd-Files를 소싱 할 수 있으면 좋을 것입니다.
stats-hb

knitr .rmd 파일을 렌더링 할 때 "오류 : 필수 패키지가 없습니다"라는 오류가 발생합니다. 누락 된 패키지 이름이 포함 된 실제 오류 메시지를 찾으려면 .rmd 파일에서 코드를 실행해야합니다. svm 에는 하나의 케이스가 caret필요합니다 kernlab.
Charles

19

공통 코드를 별도의 R 파일로 추출한 다음 해당 R 파일을 원하는 각 Rmd 파일로 소싱하십시오.

예를 들어 제가 작성해야하는 두 가지 보고서, 독감 발생 및 총기 대 버터 분석이 있다고 가정 해 보겠습니다. 당연히 두 개의 Rmd 문서를 작성하고 완료합니다.

이제 보스가 와서 독감 발발 대 버터 가격 (9mm 탄약 제어)의 차이를보고 싶다고 가정 해 보겠습니다.

  • 보고서를 새 보고서로 분석하기 위해 코드를 복사하고 붙여 넣는 것은 코드 재사용 등을 위해 나쁜 생각입니다.
  • 멋지게 보이길 원합니다.

내 솔루션은 프로젝트를 다음 파일에 포함시키는 것입니다.

  • 독감 Rmd
    • flu_data_import.R
  • Guns_N_Butter.Rmd
    • guns_data_import.R
    • butter_data_import.R

각 Rmd 파일에는 다음과 같은 내용이 있습니다.

```{r include=FALSE}
source('flu_data_import.R')
```

여기서 문제는 우리가 재현성을 잃는다는 것입니다. 이에 대한 나의 해결책은 각 Rmd 파일에 포함 할 공통 자식 문서를 만드는 것입니다. 따라서 내가 만드는 모든 Rmd 파일 끝에 다음을 추가합니다.

```{r autodoc, child='autodoc.Rmd', eval=TRUE}
``` 

그리고 물론 autodoc.Rmd :

Source Data & Code
----------------------------
<div id="accordion-start"></div>

```{r sourcedata, echo=FALSE, results='asis', warnings=FALSE}

if(!exists(autodoc.skip.df)) {
  autodoc.skip.df <- list()
}

#Generate the following table:
for (i in ls(.GlobalEnv)) {
  if(!i %in% autodoc.skip.df) {
    itm <- tryCatch(get(i), error=function(e) NA )
    if(typeof(itm)=="list") {
      if(is.data.frame(itm)) {
        cat(sprintf("### %s\n", i))
        print(xtable(itm), type="html", include.rownames=FALSE, html.table.attributes=sprintf("class='exportable' id='%s'", i))
      }
    }
  }
}
```
### Source Code
```{r allsource, echo=FALSE, results='asis', warning=FALSE, cache=FALSE}
fns <- unique(c(compact(llply(.data=llply(.data=ls(all.names=TRUE), .fun=function(x) {a<-get(x); c(normalizePath(getSrcDirectory(a)),getSrcFilename(a))}), .fun=function(x) { if(length(x)>0) { x } } )), llply(names(sourced), function(x) c(normalizePath(dirname(x)), basename(x)))))

for (itm in fns) {
  cat(sprintf("#### %s\n", itm[2]))
  cat("\n```{r eval=FALSE}\n")
  cat(paste(tryCatch(readLines(file.path(itm[1], itm[2])), error=function(e) sprintf("Could not read source file named %s", file.path(itm[1], itm[2]))), sep="\n", collapse="\n"))
  cat("\n```\n")
}
```
<div id="accordion-stop"></div>
<script type="text/javascript">
```{r jqueryinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(url("http://code.jquery.com/jquery-1.9.1.min.js")), sep="\n")
```
</script>
<script type="text/javascript">
```{r tablesorterinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(url("http://tablesorter.com/__jquery.tablesorter.js")), sep="\n")
```
</script>
<script type="text/javascript">
```{r jqueryuiinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(url("http://code.jquery.com/ui/1.10.2/jquery-ui.min.js")), sep="\n")
```
</script>
<script type="text/javascript">
```{r table2csvinclude, echo=FALSE, results='asis', warning=FALSE}
cat(readLines(file.path(jspath, "table2csv.js")), sep="\n")
```
</script>
<script type="text/javascript">
  $(document).ready(function() {
  $('tr').has('th').wrap('<thead></thead>');
  $('table').each(function() { $('thead', this).prependTo(this); } );
  $('table').addClass('tablesorter');$('table').tablesorter();});
  //need to put this before the accordion stuff because the panels being hidden makes table2csv return null data
  $('table.exportable').each(function() {$(this).after('<a download="' + $(this).attr('id') + '.csv" href="data:application/csv;charset=utf-8,'+encodeURIComponent($(this).table2CSV({delivery:'value'}))+'">Download '+$(this).attr('id')+'</a>')});
  $('#accordion-start').nextUntil('#accordion-stop').wrapAll("<div id='accordion'></div>");
  $('#accordion > h3').each(function() { $(this).nextUntil('h3').wrapAll("<div>"); });
  $( '#accordion' ).accordion({ heightStyle: "content", collapsible: true, active: false });
</script>

NB, 이것은 Rmd-> html 워크 플로우를 위해 설계되었습니다. 라텍스 또는 다른 것을 사용하면 추악한 엉망이 될 것입니다. 이 Rmd 문서는 모든 source () 파일에 대한 전역 환경을 살펴보고 문서 끝에 해당 소스를 포함합니다. 여기에는 jquery ui, tablesorter가 포함되어 있으며 소스 파일을 표시 / 숨기기 위해 아코디언 스타일을 사용하도록 문서를 설정합니다. 진행중인 작업이지만 자신의 용도에 맞게 자유롭게 조정하십시오.

한 줄짜리가 아닙니다. 적어도 몇 가지 아이디어를 제공하기를 바랍니다. :)


4

아마도 다른 생각을 시작해야 할 것입니다. 내 문제는 다음과 같습니다. .R 파일의 .Rmd 청크에 일반적으로 가졌던 모든 코드를 작성하십시오. 그리고 HTML을 짜는 데 사용하는 Rmd 문서의 경우

```{R Chunkname, Chunkoptions}  
source(file.R)  
```

이렇게하면 .R 파일을 많이 만들 수 있고 ctrl + alt + n (또는 + c,하지만 일반적으로 작동하지 않음)을 사용하여 "청크 후 청크"코드를 처리하는 이점을 잃게됩니다. 그러나 저는 Mr. Gandrud의 재현 가능한 연구에 대한 책을 읽고 그가 확실히 knitr 및 .Rmd 파일을 html 파일 생성에만 사용한다는 것을 깨달았습니다. Main Analysis 자체는 .R 파일입니다. 내부에서 전체 분석을 시작하면 .Rmd 문서가 너무 커집니다.


3

코드 바로 뒤에 있다면 다음 줄을 따라 작동해야한다고 생각합니다.

  1. 마크 다운 / R 파일 읽기 readLines
  2. 예를 들어 다음으로 grep시작하는 줄을 검색하여 코드 청크를 찾는 데 사용 합니다.<<<
  3. 코드 만 가져 오기 위해 원래 줄이 포함 된 개체의 하위 집합을 가져옵니다.
  4. 이것을 사용하여 임시 파일에 덤프하십시오. writeLines
  5. 이 파일을 R 세션으로 소싱하십시오.

이것을 함수로 감싸면 필요한 것을 얻을 수 있습니다.


1
고마워요, 그게 효과가있을 것 같아요. 그러나 처음 4 개의 포인트는 Stangle이 이미 Sweave에서 신뢰할 수있는 방식으로 수행하고 knitr에서 수행하는 작업처럼 knit('myfile.rmd', tangle=TRUE)들립니다. 나는 엉킴과 소스를 모두하고 이상적으로 파일을 생성하지 않는 하나의 라이너를 찾고 있다고 생각합니다.
Jeromy Anglim 2012-06-10

함수로 감싸면 oneliner가됩니다.). 당신이 할 수있는 것은 textConnection파일을 모방하는 데 사용 하고 그로부터 소스를 얻는 것입니다. 이렇게하면 파일이 생성되는 것을 방지 할 수 있습니다.
Paul Hiemstra 2012-06-10

예. textConnection볼 곳이 될 수 있습니다.
Jeromy Anglim 2012 년

2

다음 해킹이 잘 작동했습니다.

library(readr)
library(stringr)
source_rmd <- function(file_path) {
  stopifnot(is.character(file_path) && length(file_path) == 1)
  .tmpfile <- tempfile(fileext = ".R")
  .con <- file(.tmpfile) 
  on.exit(close(.con))
  full_rmd <- read_file(file_path)
  codes <- str_match_all(string = full_rmd, pattern = "```(?s)\\{r[^{}]*\\}\\s*\\n(.*?)```")
  stopifnot(length(codes) == 1 && ncol(codes[[1]]) == 2)
  codes <- paste(codes[[1]][, 2], collapse = "\n")
  writeLines(codes, .con)
  flush(.con)
  cat(sprintf("R code extracted to tempfile: %s\nSourcing tempfile...", .tmpfile))
  source(.tmpfile)
}

2

다음 사용자 지정 함수를 사용합니다.

source_rmd <- function(rmd_file){
  knitr::knit(rmd_file, output = tempfile())
}

source_rmd("munge_script.Rmd")

2

knitr에서 purl 기능을 사용해보십시오 :

source(knitr::purl("myfile.rmd", quiet=TRUE))


1

주요 분석 및 계산 코드를 .R 파일에 보관하고 필요에 따라 .Rmd 파일에 청크를 가져 오는 것이 좋습니다. 여기에서 그 과정을 설명했습니다 .


1

sys.source ( "./ your_script_file_name.R", envir = knitr :: knit_global ())

your_script_file_name.R에 포함 된 함수를 호출하기 전에이 명령을 넣으십시오.

이미 프로젝트를 만든 경우 파일에 대한 방향을 표시하기 위해 your_script_file_name.R 앞에 "./"추가.

자세한 내용은이 링크를 참조하십시오 : https://bookdown.org/yihui/rmarkdown-cookbook/source-script.html


0

이것은 나를 위해 일했다

source("myfile.r", echo = TRUE, keep.source = TRUE)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.