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

나는 종종 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 코드를 소싱하는 더 우아한 방법이 있습니까?



답변

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

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

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

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


답변

공통 코드를 별도의 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가 포함되어 있으며 소스 파일을 표시 / 숨기기 위해 아코디언 스타일을 사용하도록 문서를 설정합니다. 진행중인 작업이지만 자신의 용도에 맞게 자유롭게 조정하십시오.

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


답변

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

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

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


답변

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

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

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


답변

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

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


답변

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

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

source_rmd("munge_script.Rmd")


답변

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

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