当ページは MultiRMD利用の予備知識 につぐ シリーズ第2回です。
統計ソフトRとmarkdownの組合せによってレポートを生成することが主題です。
サイコロを10回ふった結果を表示する例を取り上げます。
サンプルのファイルは mtest01.zip に同梱されています。
下のような表示を得るためのプログラムを作ります。
番号付きの箇条書きが10行、
番号なしの箇条書きが2行です。
−−−− 表示ここから
さいころを10回ふった結果は下のとおり。
1. 奇数: 3
2. 奇数: 5
3. 偶数: 4
4. 偶数: 6
5. 奇数: 1
6. 奇数: 5
7. 偶数: 2
8. 偶数: 2
9. 偶数: 2
10. 偶数: 2
----------------
・ 奇数の回数: 4
・ 偶数の回数: 6
−−−− 表示ここまで
サイコロの目は、乱数発生により取得します。
dice.value <- as.integer(runif(10, min=1, max=7))
上のようにすると、一様性の乱数が得られます。
1〜6の整数が10個発生します。
一つのサイコロの目を表示するのに二種類のmarkdownテンプレートを用意します。
奇数の場合のものと偶数の場合のものです。
それぞれ1行だけからなります。次のとおり。
−−−− ここから
1. 奇数: %n%
1. 偶数: %n%
−−−− ここまで
%n%
は、具体的なサイコロの目の数に置き換える必要があります。
先頭の 1.
は、2, 3, 4 …… のような連続する番号にする必要はありません。
rmarkdownとブラウザに任せておけば大丈夫です。
あと、奇数の回数と偶数の回数を表示するためのmarkdownテンプレートが必要です。次のようなものです。
−−−− ここから
- 奇数の回数: %o%
- 偶数の回数: %e%
−−−− ここまで
%o%
と %e%
は、やはり具体的な数に置き換える必要があります。
Rプログラムの実行結果をみながらこれらテンプレートを組み合わせて、
最終的な一つのmarkdownの原稿に仕上げ、
rmarkdownによりhtmlなどに変換するという手順になります。
前述のmarkdownテンプレートが、変数 template に代入されているものとします。
奇数表示用が template[1]
, 偶数表示用が template[2]
,
最後の回数表示用が template[3]
に入っている状態です。
このとき、diceというchunkに書かれているRプログラムは下のとおりです。
−−−− Rプログラムここから
odd.count <- 0 # 奇数の回数
even.count <- 0 # 偶数の回数
dice.value <- as.integer(runif(10, min=1, max=7))
for (n in dice.value) {
if ((n %% 2) != 0) { # 奇数の場合
tpl <- template[1]
odd.count <- odd.count + 1
} else { # 偶数の場合
tpl <- template[2]
even.count <- even.count + 1
}
tpl <- sub("%n%", n, tpl)
append.mrmd(tpl)
}
tpl <- template[3]
tpl <- sub("%o%", odd.count, tpl)
tpl <- sub("%e%", even.count, tpl)
append.mrmd(tpl)
−−−− Rプログラムここまで
append.mrmd()
という関数は、multirmd.r の中で定義されています。
append.mrmd(tpl)
は、最終的なmarkdownの原稿に、変数tplの中身を追加・結合するものです。
内部で定義されている変数 mrmd.buf に蓄積します。
mrmd.buf に記録された文字列は、最後の方で $$MrmdTmp.rmd
というファイルに書き出して、それを取り込んで処理を完成させることになります。
これまで述べてきた markdownテンプレート、Rプログラムの両方を一つのchunk定義ファイルに書き込みます。
mtest01.r というファイルです。
markdownテンプレートは、#'
の2文字から始まる行として書き込みます。
Rプログラムは、素直にそのまま記入する形です。
−−−− ここから
## @knitr dice
#' 1. 奇数: %n%
#' 1. 偶数: %n%
#'
#' --------
#'
#' - 奇数の回数: %o%
#' - 偶数の回数: %e%
#'
eval(set.template)
odd.count <- 0 # 奇数の回数
even.count <- 0 # 偶数の回数
dice.value <- as.integer(runif(10, min=1, max=7)) # 1〜6の数を10個発生
(中略)
append.mrmd(tpl)
−−−− ここまで
#'
で始まる行が連続すると、それが一つのテンプレートになります。
空白行など 行頭が #'
でないものがあると、そこでテンプレートが区切られます。
再度 #'
で始まる行が現れると、それは別のテンプレートということになります。
テンプレート部分の取り込みは、multirmd.r の中で定義されている set.mrmd()
という関数で行います。ライブ来 rmarkdown, knitr の機能は利用しません。
eval(set.template)
は、三つのテンプレートを変数 template
にセットするための記述です。
これを書かないときは、テンプレートを参照するのにちょっと長い記述が必要になります。
chunk名 dice にかかわるテンプレートは下のとおり。
mrmd.template[['dice']][1]
: 奇数表示用mrmd.template[['dice']][2]
: 偶数表示用mrmd.template[['dice']][3]
: 回数表示用どのchunkでも使える汎用的な記述にするなら下のように書きます。
mrmd.template[[opts_current$get('label')]][1] # 奇数表示用
こうした長い記述をRプログラムに書くのは大変なので、変数 template
にセットできるようにしたものです。
chunk定義ファイルを読み込んで、それを実行・処理するrmdファイル mtest01.rmd を掲げます。
−−−− ここから
---
title: "Test Document"
author: "Black Lady"
date: "2017/03/11"
output: html_document
---
さいころを10回ふった結果は下のとおり。
```{r include=FALSE}
# source("multirmd.r")
chunk.def <- "mtest01.r"
set.mrmd(chunk.def)
read_chunk(chunk.def)
```
```{r child="$$final.rmd"}
```
```{r include=FALSE}
file.remove("$$final.rmd")
```
−−−− ここまで
上が multirmd.r を利用する典型例です。
# source("multirmd.r")
というのはコメントなので実行されません。
rptパッケージのバッチコマンドで mtest01.rmd を処理する場合は、
multirmd.r が自動的に読み込まれます。なのでコメントにしてあります。
rptのバッチを使わないときは、行頭の ‘#’ を削除して、multirmd.r を読み込むようにします。
なお、rptの2種類のバッチ i386_rmarkdown.bat, i386_RmdRuby.bat のどちらでも、mtest01.rmdを処理することができます。
64bit版なら x64_rmarkdown.bat, x64_RmdRuby.bat のどちらでもOKです。
set.mrmd("mtest01.r")
とすると、おおよそ下の処理が行われます。
## @knitr ....
の行からchunk名を取得#'
で始まる行からmarkdownテンプレートを取り込む#+
で始まる行から chunkオプションを取得mrmd.buf
などを初期化$$final.rmd
というファイルを生成 $$final.rmd
の中に書き込まれる処理は次のとおり。
$$MrmdTmp.rmd
に書き出して、それをchildで実行処理。$$MrmdTmp.rmd
を消去。 $$final.rmd
の中身は次のようなものになります。
−−−− ここから
```{r dice, include=FALSE}
```
```{r echo=FALSE, results='asis', include=TRUE}
if (mrmd.buf != '') {
cat(mrmd.buf, file=mrmd.tmp)
cat(knit_child(mrmd.tmp, quiet=TRUE), sep='')
mrmd.buf <- ''
dummy <- file.remove(mrmd.tmp)}
```
−−−− ここまで
関数 set.mrmd()
は、あくまで最終的な処理の準備をするものです。
処理を貫徹するには次の手続きが必要です。
read_chunk("mtest01.r")
によるchunk定義の読み込み$$final.rmd
をchildで呼び出して実行$$final.rmd
を消去mtest01.rmd の最後の方でそれを行っています。
以上が「MultiRMDの簡単なサンプル」です。
議会は MultiRMDにおけるテンプレートの反復利用 です。
最後にこんなことを書くのは何ですが、
今回の例は簡単なので、multirmd.r を使わなくても同じ表示を得るのは容易です。
わざわざchunk定義ファイルを別に設けて、それを読み込んだりする手間がかからないぶん、より簡単といえます。
zipファイルに mtest01_2.rmd を同梱しておきます。よかったら覗いてみて下さい。