当ページは MultiRMDにおけるエラー処理および条件分岐につぐ シリーズ第5回(最終回)です。
統計ソフトRとmarkdownの組合せによってレポートを生成することが主題です。
自治体の空き地利用に関するアンケート調査を材料にして、
flushおよび #+
によるchunkオプション指定について説明します。
サンプルのファイルは mtest04.zip に同梱してあります。
自治体の空き地利用に関するアンケート調査結果を検証します。
乱数発生により作成した data.csv は、次の列からなる 600人分のデータです。
600人の人に、空き地利用法のうち一つを選択してもらったものですが、
その結果が回答者の居住地区によって違いがあるかどうか、
あるいは、年齢層によって有意な差があるかどうかを検証します。
検証にはカイ2乗検定を用います。
有意差が認められる場合は、どのセルの値が有意に大きいのか(または小さいのか)をみるために調整済み残差を表示します。
また、カイ二乗検定とは別個に対応分析を行い、その結果を表示します。
multirmd.r に関連して、まだ説明できていない eval(call.flush)
と、
chunk定義ファイルにおける #+
で始まる chunkオプション記述について説明します。
flushは、バッファに蓄積されたmarkdownの原稿をファイルに書き出し、それを取り込むものです。
どんな場面で flush が必要になるのかを以降で説明します。
集計と統計検定の手順、また、今回のサンプルのファイルの構成について述べます。
処理の全体的な流れは下のとおり。
以上が「居住地区」に関する流れですが、「年齢層」についても全く同様の処理手順をとります。
カイ2乗検定に関しては、有意性が認められたときは残差分析を行い、そうでなければ行わないという条件分岐がかかわります。
なので、chunk定義ファイルの中で、行頭が #'
で始まるmarkdownテンプレートを複数用意して、条件に応じてテンプレートを使い分けます。
一方、対応分析の方は条件分岐に関係ないので、rmdファイルを一つ用意して、そのファイルを取り込むようにします。
ということを踏まえて、今回の処理にかかわるファイル構成は次のようにしました。
#'
のmarkdownテンプレートも含まれている。上記のほか、素材データの data.csv があります。
それと、factor設定情報を記録した data.mem というファイル(後述)もあります。
mtest04.r の概要について述べたうえで、なぜ flush が必要なのかを説明します。
mtest04.r で定義されているchunkを列記します。
#'
のmarkdownテンプレートあり。
今回のポイントは chisq_flush ですが、このchunkは下の3行からなります。
## @knitr chisq_flush
#+ echo=FALSE, results='asis', include=TRUE
eval(call.flush)
#+
で始まる行は chunkオプションの記述です。
call.flush
は multirmd.r の中で定義されています。
上の3行は、下の7行と同じです。
```{r chisq_flush, echo=FALSE, results='asis', include=TRUE}
if (mrmd.buf != '') {
cat(mrmd.buf, file="$$MrmdTmp.rmd")
cat(knit_child("$$MrmdTmp.rmd", quiet=TRUE), sep='')
mrmd.buf <- ''
dummy <- file.remove("$$MrmdTmp.rmd")}
```
multirmd.rを利用している場合、バッファ(mrmd.buf)に蓄積されたmarkdownの原稿は、通常、全処理過程の最後に書き出し&取り込みが行われます。
なので、chisq_flush というchunkがないと、バッファに記録されたクロス集計とカイ2乗の結果は、correspondence_insert よりも後に配置されてしまいます。
つまり、クロス集計表とカイ2乗検定の結果の表示が対応分析の表示よりも後になってしまいます。
そうならないようにするため、chisq_flush を置いています。
chisq_flush というchunkの中に書かれている eval(call.flush)
を実際のRプログラムに展開すると、別のrmdファイルを取り込むための記述 cat(knit_child( …… )
というのが出てきます。
これを有効なものにするには chunkオプションを
echo=FALSE, results='asis', include=TRUE
にしなければなりません。
つまり、chisq_flush のchunkオプションを上記のものにする必要があります。
chisq_flush の直前に chisq_push というchunkがあります。
わざわざ chisq_flush というchunkを設けなくても、その chisq_push の最後のところに eval(call.flush)
を書けばいいようなものですが、残念ながらそういう訳にいきません。
eval(call.flush)
を含むchunkは、そのオプションを必ず echo=FALSE, results='asis', include=TRUE
にしなければなりません。
rptパッケージを使っている場合は、マイコンピュータ(explorer)でこの mtest04.rmd に焦点を当てて、「送る」メニューから
i386_rmarkdown, x64_rmarkdown, i386_RmdRuby, x64_RmdRuby
のいずれか一つを選択すると、mtest04.html が作られます。
mtest04.rmdは、次の四つの部分から構成されています。
YAMLヘッダおよびmarkdownの原稿については省略し、二つのchunkについて述べます。
まず、対応分析に必要なライブラリを読み込んでいます。library(MASS)
です。
次に、拙作 multirmd.r, tjsf.r を読み込みます。rptパッケージを利用しているときは自動的に読み込まれるのでコメントにしてあります。
それ以降が実際のプログラムです。
まず独立変数と従属変数の名前を xxs, yy に代入しています。
xxs <- c("居住地区", "年齢層")
yy <- "空き地利用法"
第2のchunkで xxs から独立変数を一つずつ取り出して処理します。
次がcsvファイルの読み込みと factor の設定です。
csvファイルには居住地区として「地区A, 地区B, 地区C」と書いてある訳ではありません。単に「a, b, c」と書かれています。
空き地利用法としては「保育介護, スポーツ娯楽, 公園」の代わりに「c, s, p」と書かれています。
アルファベット1文字だけではレポートにしたとき分かりにくいので、ちゃんとした名前に変更します。
どんな名前に変更するかの情報は、data.mem というファイルに書かれています。
−−−− data.mem ここから
居住地区 | a,b,c | 地区A,地区B,地区C
年齢層 | 10,20,30,40,50 | 20歳未満,20代,30代,40代,50歳以上
空き地利用法 | c,s,p | 保育介護,スポーツ娯楽,公園
−−−− data.mem ここまで
この data.mem を基にしてRプログラムの factor() を実行するのが
remake.factor() という関数です。
この関数は tjsf.r の中で定義されています。
tjsf.r については 単純集計に関する覚え書き/まとめ(関数化) を参照してください。
短いので、第2のchunkを全部掲げます。
```{r echo=FALSE, results='asis', include=TRUE}
chunk.def <- "mtest04.r" # chunk定義ファイル名
set.mrmd(chunk.def)
read_chunk(chunk.def)
for (xx in xxs) # 独立変数(説明変数)を一つずつ
cat(knit_child("$$final.rmd", quiet=TRUE), sep='')
dummy <- file.remove("$$final.rmd")
```
set.mrmd(chunk.def)
によって $$final.rmd というファイルが生成されます。
mtest04.r で定義されているchunkを一通り呼び出す(実行する)ものです。
$$final.rmd の中身は次のとおり。
−−−− ここから
```{r chisq_process, include=FALSE}
```
```{r chisq_push, include=FALSE}
```
```{r chisq_flush, echo=FALSE, results='asis', include=TRUE}
```
```{r correspondence_process, include=FALSE}
```
```{r correspondence_insert, echo=FALSE, results='asis', include=TRUE}
```
```{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)}
```
−−−− ここまで
定義されているchunkが順番どおりに呼び出されています。
#+
でchunkオプションが指定されていると、そのオプションが付記されます。
chisq_flush, correspondence_insert の二つのchunkがそれです。
オプションの指定がないものは include=FALSE
というオプションになります。
if (mrmd.buf != '') {
以降は、バッファの書き出し&取り込みです。
今回は chisq_flush によってバッファの書き出し&取り込みが行われ、その段階でバッファが空になるので、この最後の部分は実際には働きません。
$$final.rmd によって処理されるのは、独立変数の一つの値についてだけです。
今回は「居住地区」 「年齢層」の二つがあります。
なので、変数xxに一つの値を代入してから $$final.rmd を取り込み、
次に xxに別の値を代入してから、もう一度 $$final.rmd を取り込みます。
for文でその繰り返し処理を行っています。
カイ2乗検定、対応分析、あるいは、それらに関連するグラフの作成は、Rプログラムの一般的なやり方を用いたつもりです。
独自なのは、クロス集計を行う sa1() という関数でしょうか。
tjsf.r の中で定義されている関数で、欠損値を除く形でクロス集計するものです。
saは、単一回答: single answer のつもりです。
素材データが変数 dtf にデータフレームとして代入されている場合、
zz <- sa1(dtf, "居住地区", "空き地利用法")
上のように用います。
その戻り値 zz には4つの表が入っています。
2つの度数分布表と2つのパーセントの表です。zz$tbl1
とか zz$pct1
のようにして参照します。
その他、tjsf.r ではクラメール係数を求める関数も定義してあり、今回、それを用いています。
カイ2乗検定を行うと、カイ2乗値等が得られます。それを基にクラメール係数を算出します。具体的には次のとおり。
chi <- chisq.test(zz$tbl1) # カイ2乗検定
chi <- append.cramer(chi) # クラメール係数の算出・追加
クラメール係数は chi$cramer
に代入されます。
行項目(居住地区)と列項目(空き地利用法)の連関の度合いを示すのがクラメール係数で、0〜1の範囲の値をとります。
以上で multirmd.r の解説は終了です。
multirmd.r の中身は、set.mrmd(), append.mrmd() という二つの関数を定義し、
あとは eval() に引き渡す set.template, call.flush, call.child などを定義しているだけの簡単なRプログラムです。
rmdファイルに、反復や条件分岐を持ち込むのにもっと良い方法があるような気がしますが、筆者が具体的に提示できるのはこの程度です。
より使いやすいものが出てくることを期待します。