Tokyo.R@36

~knitrパッケージではじめる~『R MarkdownでReproducible Research』の応用編のコード

[Knit HTML]ボタンを押した時に実行されてること(の模擬コード)

library(knitr)
library(markdown)
output <- knit("TokyoR36_Basic.rmd", encoding = "UTF-8")
# 「invalid multibyte string at」
# というエラーが出るので解消するためにロケール変えてる。 Windows 7だけかも?
# ロケール変えなくていいなら knitr::knit2html関数もほぼ同じ挙動
Sys.setlocale(locale = "C")
markdownToHTML(output, output = "sample.html")

markdownToHTML関数のオプション

# デフォルトで設定されているもの
markdownHTMLOptions(default = TRUE)
## [1] "use_xhtml"      "smartypants"    "base64_images"  "mathjax"       
## [5] "highlight_code"
# 設定可能なオプションの全て
markdownHTMLOptions()
##  [1] "skip_html"      "skip_style"     "skip_images"    "skip_links"    
##  [5] "safelink"       "toc"            "escape"         "fragment_only" 
##  [9] "hard_wrap"      "use_xhtml"      "smartypants"    "base64_images" 
## [13] "mathjax"        "highlight_code"

テーブルフォーマットの動的な切り替え

テーブルのフォーマットを動的に切り替えるには テーブルのフォーマット用変数をあらかじめ用意しておいて、 knit関数呼ぶ時の環境に突っ込んでおくといい。chunkオプションを独自に定義するのもありかも。

table.format <- ifelse(exists("table.format"), table.format, "html")
library(knitr)
# テーブル用の変数割り当て
env <- new.env()
assign("table.format", "markdown", env)
# .Rmd --> .mdへ変換
knit("hoge.Rmd", envir = env)

Wordにしたい

pandocをインストールした上で以下のような感じ

library(knitr)
env <- new.env()
assign("table.format", "markdown", env)
output <- knit("TokyoR36_Basic.Rmd", envir = env, encoding = "UTF-8")
pandoc(output, format = "docx")

PDFにしたい

pandocをインストールした上で以下のような感じ。日本語を扱う周りで結構苦労した。

library(knitr)
env <- new.env()
assign("table.format", "markdown", env)
output <- knit("TokyoR36_Basic.Rmd", envir = env, encoding = "UTF-8")
system(sprintf("pandoc -s %s -V documentclass=ltjltxdoc -o hoge.tex", output))
system("lualatex -interaction=nonstopmode hoge.tex")
# ↓こんなんでイケそうだけど、うごかん… pandoc(output, format='pdf')
# documentclass=ltjsarticleはpandocのLaTeX用デフォルトのテンプレートだとコケる模様
# (参考:http://oku.edu.mie-u.ac.jp/tex/mod/forum/discuss.php?d=1005)
# 皆大好き:platex->dvipdfmxもうまくいかん&xelatexはめんどいのでlualatexで
# いちいちtexファイル経由しないでダイレクトにpdfにしようと system('pandoc -s
# TokyoR36_Basic.md -V documentclass=ltjltxdoc --latex-engine=lualatex -o
# hoge.pdf') とやりたいところだが、うまくいかん

Chunkに条件をつけて

まずxに適当な値を代入しておく

x <- 10

xが3より大きい時にだけ評価されるChunk

```{r conditionalchunk_eval, eval=(x>3)}
print("x は3より大きい")
```
print("x は3より大きい")
## [1] "x は3より大きい"

xが奇数のときだけ評価されるChunk。

```{r conditionalchunk_noeval, eval=(x%%2 == 1)}
print("x は奇数")
```
print("x は奇数")

今、xは10であり偶数であるため、 chunkは表示されるものの、評価(eval)はされない。

共有(Rスクリプト)

read_chunk関数で別ファイルのスクリプトが読み込まれる

read_chunk("share/shared_r.R")

shared_r.R内で指定したchunkのラベルを指定するとそれが表示される

```{r plus10r}
```
plus10 <- function(x) {
    x + 10
}
plus10(3)
## [1] 13

複数のチャンクをref.labelとして指定すると一括で表示される

```{r shared_r_all, ref.label=c('plus10r','subset_iris')}
```

外部のR Markdownファイルを読み込むにはchildオプションを使う

```{r child1, child="share/shared_rmd.Rmd"}
```

これは別ファイルに記述されたR Markdownです。

print("これは別ファイルに記述されたR Markdownです")
## [1] "これは別ファイルに記述されたR Markdownです"

他の言語の使用例(Cpp)

engineオプションを設定することで、Rcpp等を.Rmd内で使用する事も可能。 当然、あらかじめ各種言語等の設定はしておかなければならない。

```{r engine_rcpp, engine='Rcpp'}
#include<Rcpp.h>
// [[Rcpp::export]]
int fibCpp(const int x){
  if(x==0 || x==1){return(x);}
  return(fibCpp(x-1) + fibCpp(x-2));
}
```
#include<Rcpp.h>
// [[Rcpp::export]]
int fibCpp(const int x){
  if(x==0 || x==1){return(x);}
  return(fibCpp(x-1) + fibCpp(x-2));
}

Rcppを使って作成した関数は、以降のチャンクで使用可能。

# Rcppで作成した関数を使用
fibCpp(10)
## [1] 55

engineとしてpythonを指定すると、pythonコードの 実行結果を埋め込むこともできる。ただしengine内だけで使用可能。

def fibPy(n):
    if n == 0 or n == 1 : 
        return n
    else:
        return fibPy(n-1) + fibPy(n-2)
print fibPy(10)
## 55

chunkエイリアス

chunkはエイリアス(別名)をつけることが可能

set_alias(w = "fig.width", h = "fig.height")

以下、チャンクオプションとしてh・wと書く事が可能。

```{r w=7, h=6}
plot(cars)
```
plot(cars)

plot of chunk unnamed-chunk-3

コードはAppendixへ

echoオプションをFALSEにし、最後にevalするようにする。

Aという手法を用いると、以下のような結果が算出される。
```{r AppA, echo=FALSE}
1 + 1
```
一方、手法Bを用いると、以下のような結果となった。
```{r AppB, echo=FALSE}
2 + 3
```
~Appendix~

手法Aのコード
```{r AppA, eval=FALSE}
```
手法Bのコード
```{r ref.label=c('AppB'), eval=FALSE}
```

Aという手法を用いると、以下のような結果が算出される。

## [1] 2

一方、手法Bを用いると、以下のような結果となった。

## [1] 5

~Appendix~

手法Aのコード

1 + 1

手法Bのコード

2 + 3

ちなみに全コードのチャンクを取得するにはall_labels関数を使う。

# 全チャンクのラベルを取得
all_labels()
##  [1] "mock_knit_html_button"                  
##  [2] "markdown_to_html_option"                
##  [3] "table_format"                           
##  [4] "convert_to_markdown_with_markdown_table"
##  [5] "convert_to_docx"                        
##  [6] "convert_to_pdf"                         
##  [7] "x10"                                    
##  [8] "conditionalchunk_eval"                  
##  [9] "conditionalchunk_noeval"                
## [10] "read_shared_r"                          
## [11] "engine_rcpp"                            
## [12] "use_rcpp"                               
## [13] "unnamed-chunk-1"                        
## [14] "unnamed-chunk-2"                        
## [15] "unnamed-chunk-3"                        
## [16] "AppA"                                   
## [17] "AppB"                                   
## [18] "all_chunk_labels"                       
## [19] "unnamed-chunk-5"                        
## [20] "unnamed-chunk-6"                        
## [21] "unnamed-chunk-7"                        
## [22] "unnamed-chunk-8"                        
## [23] "session_info"                           
## [24] "plus10r"                                
## [25] "subset_iris"                            
## [26] "child_rmd"

Chunkオプションのhook(フック)による拡張

# デフォルトで設定されているhook(output hook)
# これがrender_XXX関数内で書き変えられており、複数の出力形式に対応できる形になっている
names(knit_hooks$get(default = TRUE))
## [1] "source"   "output"   "warning"  "message"  "error"    "plot"    
## [7] "inline"   "chunk"    "document"

独自なchunk optionとしてmarginを作成してみる

knit_hooks$set(margin = function(before, options, envir) {
    if (before) {
        par(mar = c(0.1, 0.1, 0.1, 0.1))
    } else {
        NULL
    }
})

マージンを指定しない通常の描画

```{r fig.width=3, fig.height=3}
plot(cars)
```
plot(cars)

plot of chunk unnamed-chunk-7

マージンを指定

```{r fig.width=3, fig.height=3, margin=TRUE}
plot(cars)
```
plot(cars)

plot of chunk unnamed-chunk-8

一応のセッションインフォ

sessionInfo()
## R version 3.0.1 (2013-05-16)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## 
## locale:
## [1] LC_COLLATE=Japanese_Japan.932  LC_CTYPE=Japanese_Japan.932   
## [3] LC_MONETARY=Japanese_Japan.932 LC_NUMERIC=C                  
## [5] LC_TIME=Japanese_Japan.932    
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] markdown_0.6.4 knitr_1.5     
## 
## loaded via a namespace (and not attached):
## [1] evaluate_0.5.1 formatR_0.10   Rcpp_0.11.0    stringr_0.6.2 
## [5] tools_3.0.1