web-dev-qa-db-ja.com

knitrでループを使用して複数のPDFレポートを作成する...こぶを乗り越えるには少し助けが必要です

まず第一に、私はknitrと再現性のある分析の概念に非常に慣れていないことを認めなければなりませんが、現在のワークフロー(Wordドキュメントへの多くのコピー貼り付けを含む)を改善する可能性を見ることができます。

私はしばしばグループ(この例では病院)ごとに複数のレポートを作成する必要があり、各病院内には、結果を報告しているさまざまな病棟が存在する可能性があります。以前は、ループを使用してRですべてのプロットと分析を実行し、コピー/貼り付け作業を開始しました。ただし、この投稿を読んだ後( Sweaveは多くのPDFを自動的に生成できますか? )、実際に多くの手順をスキップして、RからRnw/knitrを介してレポートすることができるかもしれないという希望を与えました。

ただし、試してみると、うまく機能していないものがあることがわかります(Rnw内のR環境は、渡そうとしているループ変数を認識していないようです??)。

   ##  make my data
Hospital <- c(rep("A", 20), rep("B", 20))
Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2)
Month <- rep(seq(1:10), 4)
Outcomes <- rnorm(40, 20, 5)
df <- data.frame(Hospital, Ward, Month, Outcomes)


##  Here is my current work flow-- produce all plots, but export as png and cut/paste
for(hosp in unique(df$Hospital)){
  subgroup <- df[ df$Hospital == hosp,]
  for(ward in unique(subgroup$Ward)){
    subgroup2 <- subgroup[subgroup$Ward == ward,]
    savename <- paste(hosp, ward)
    plot(subgroup2$Month, subgroup2$Outcomes, type="o", main=paste("Trend plot for", savename))
  }
}
# followed by much copy/pasting


##  Here is what I'm trying to go for using knitr 
library(knitr)
for (hosp in unique(df$Hospital)){
  knit("C:file.path\\testing_loops.Rnw", output=paste('report_', Hospital, '.tex', sep=""))
}

## With the following *Rnw file
## start *.Rnw Code
\documentclass[10pt]{article}
\usepackage[margin=1.15 in]{geometry}
<<loaddata, echo=FALSE, message=FALSE>>=
  Hospital <- c(rep("A", 20), rep("B", 20))
Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2)
Month <- rep(seq(1:10), 4)
Outcomes <- rnorm(40, 20, 5)
df <- data.frame(Hospital, Ward, Month, Outcomes)
subgroup <- df[ df$Hospital == hosp,]
@

\begin{document}
<<setup, echo=FALSE >>=
  opts_chunk$set(fig.path = paste("test", hosp , sep=""))
@

Some infomative text about hospital \Sexpr{hosp}

<<plots, echo=FALSE >>=
  for(ward in unique(subgroup$Ward)){
    subgroup2 <- subgroup[subgroup$Ward == ward,]
    #     subgroup2 <- subgroup2[ order(subgroup2$Month),]
    savename <- paste(hosp, ward)
    plot(subgroup2$Month, subgroup2$Outcomes, type="o", main=paste("Trend plot for", savename))
  }
@
\end{document}


##  To be then turned into pdf with this
tools::texi2pdf("C:file.path\\report_A.tex", clean = TRUE, quiet = TRUE)

Knit()コードチャンクを実行しようとすると、次のエラーが発生します。

Error in file(con, "w") : invalid 'description' argument

また、*。texファイルが作成されるディレクトリを調べると、病院Aから2つのpdfプロットが作成され(Bの場合はなし)、pdfに編む病院固有の* .texファイルがないことがわかります。あなたが提供できるどんな助けにも前もって感謝します!

33
Chris

.Rnwファイルのデータを再定義する必要はありません。警告は、出力名をHospital(病院の完全なベクトル)と組み合わせているという事実から来ていると思います。 )hosp(ループインデックス)ではなく。

あなたの例に従うと、testingloops.Rnw

\documentclass[10pt]{article}
\usepackage[margin=1.15 in]{geometry}
<<loaddata, echo=FALSE, message=FALSE>>=
subgroup <- df[ df$Hospital == hosp,]
@

\begin{document}
<<setup, echo=FALSE >>=
  opts_chunk$set(fig.path = paste("test", hosp , sep=""))
@

Some infomative text about hospital \Sexpr{hosp}

<<plots, echo=FALSE >>=
  for(ward in unique(subgroup$Ward)){
    subgroup2 <- subgroup[subgroup$Ward == ward,]
    #     subgroup2 <- subgroup2[ order(subgroup2$Month),]
    savename <- paste(hosp, ward)
    plot(subgroup2$Month, subgroup2$Outcomes, type="o", main=paste("Trend plot for", savename))
  }
@
\end{document}

ドライバーのRファイルは

##  make my data
Hospital <- c(rep("A", 20), rep("B", 20))
Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2)
Month <- rep(seq(1:10), 4)
Outcomes <- rnorm(40, 20, 5)
df <- data.frame(Hospital, Ward, Month, Outcomes)

## knitr loop
library("knitr")
for (hosp in unique(df$Hospital)){
  knit2pdf("testingloops.Rnw", output=paste0('report_', hosp, '.tex'))
}
15
Brian Diggs

素晴らしい質問です!これは、あなたがあなたの質問で提供した他のビットで私のために働きます。 hospxだけに置き換えたことに注意してください。私はあなたのRnwファイルをtest.rnwと呼びました

# input data
Hospital <- c(rep("A", 20), rep("B", 20))
Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2)
Month <- rep(seq(1:10), 4)
Outcomes <- rnorm(40, 20, 5)
df <- data.frame(Hospital, Ward, Month, Outcomes)

# generate the tex files, one for each hospital in df
library(knitr)
lapply(unique(df$Hospital), function(x) 
       knit("C:\\emacs\\test.rnw", 
            output=paste('report_', x, '.tex', sep="")))

# generate PDFs from the tex files, one for each hospital in df
lapply(unique(df$Hospital), function(x)
       tools::texi2pdf(paste0("C:\\emacs\\", paste0('report_', x, '.tex')), 
                       clean = TRUE, quiet = TRUE))

ループをlapplyと無名関数に置き換えました。これらは、よりRっぽいと見なされることがよくあります。

ここで、hospファイルのどこでxrnwに置き換えたかを確認できます。

\documentclass[10pt]{article}
\usepackage[margin=1.15 in]{geometry}
<<loaddata, echo=FALSE, message=FALSE>>=
  Hospital <- c(rep("A", 20), rep("B", 20))
Ward <- rep(c(rep("ICU", 10), rep("Medicine", 10)), 2)
Month <- rep(seq(1:10), 4)
Outcomes <- rnorm(40, 20, 5)
df <- data.frame(Hospital, Ward, Month, Outcomes)
subgroup <- df[ df$Hospital == x,]
@

\begin{document}
<<setup, echo=FALSE >>=
  opts_chunk$set(fig.path = paste("test", x , sep=""))
@

Some informative text about hospital \Sexpr{x}

<<plots, echo=FALSE >>=
  for(ward in unique(subgroup$Ward)){
    subgroup2 <- subgroup[subgroup$Ward == ward,]
    #     subgroup2 <- subgroup2[ order(subgroup2$Month),]
    savename <- paste(x, ward)
    plot(subgroup2$Month, subgroup2$Outcomes, type="o", main=paste("Trend plot for", savename))
  }
@
\end{document}

結果は、2つのtexファイル(report_A.tex、report_B.tex)、図用の4つのPDF(A1、A2、B1、B2)、およびレポート用の2つのPDF(report_A.pdf、report_B.pdf)であり、それぞれに図があります。それらの中で。それはあなたが求めていたものですか?

10
Ben

この回答では、特定の例ではなく、「ループを使用して複数のpdfレポートを作成する」というより一般的な質問に回答するつもりです。これは、この傾向を初心者として追跡するのが非常に困難だったためです。最終的には(htmlバージョンで)動作させることができたので、これは私の謙虚な解決策です。ここに公開されているより良いものがいくつかあるかもしれませんが、私はまだそれらを完全に理解することはできません。

  1. デザインを使用してRMDファイルを作成し、working\inputディレクトリ(Rstudio:file-> newfile-> Rマークダウン)に保存します。このファイルには、レポートでプロットを作成するために必要なすべての関数が含まれている必要があります(これらのコードチャンクの1つで宣言するだけです)。このファイルは、今後のすべてのレポートのテンプレートと考えてください。以前にデータをかみ砕いた後、データをその環境に渡すことについて心配する必要はありません。これについては(2)で説明します。理解すべき重要な問題は、すべての計算がパイプラインのさらに下流で行われることです(RMDファイルをレンダリングする時点で)。

  2. 異なるコントロールrファイルで使用する必要のあるループを作成します。私の場合、ディレクトリ内のすべてのファイルを反復処理し、それらをデータフレームに取り込むループがあります。次に、それらをプロットするために、他のデータ変数とともに、それらのデータフレームをRMDに渡します。これはその方法です:

    run_on_all<-function(path_in="path:\\where\\your\\input\\and\\RMD\\is", path_out="path:\\where\\your\\output\\will\\be") setwd(path_in) ibrary(rmarkdown) library(knitr) list_of_file_names=list.files(path = getwd, pattern = "*.csv") #this gets a list of the input files names for (file_name in list_of_file_names) { data=read.csv(file_name) #read file into data frame report_name=paste(some_variable_name,".html",sep="") render("your_template.Rmd",output_file =report_name,output_dir =path_out,list(data,all other parameters you want to input into the RMD))} }

  3. 最も重要なコマンドはrender関数呼び出しです。それはあなたが望むどんなパラメータもRMD環境に投げ込むことを可能にします。また、レポートの名前を変更したり、出力場所を変更したりすることもできます。さらに、それを呼び出すことでレポートも生成されるため、すべてを1行で取得できます(RMDの呼び出しが関数内にある場合、入力した変数が欠落していることに気付く場合がありますが、レポートはまだ正しく公開されています)

概要

必要なファイルは2つあります。RMDファイルは、すべての追加レポートのテンプレートと制御ファイルになります。制御ファイルはデータを取得し、それを噛み砕き、噛んだパラメーターをRMDに渡します(レンダリング関数を介して)。 RMDはデータを取得し、いくつかの計算を実行し、プロットして、新しいファイルに公開します(これもレンダリング関数によって)。私が助けてくれたと思います。

0
amann