knitr&谢益辉

对于自动化报告的开场白,我希望引用谢老大(原名:谢益辉,p.s.混迹COS论坛的人应该很经常见到此人,没听说过此人的童鞋也应该没怎么用过RStudio,是R的一位高级忍者)对于knitr的一些介绍。

人类和计算机有各自擅长的东西,人擅长下指令,计算机擅长执行指令,而且对计算机来说,一个任务做一遍或是做一百遍可能只有时间上的区别,但一个人要是同一个任务重复做一百遍可能就抓狂了,而且容易出错。另一方面,人还有最大的一个特征就是懒惰;懒没什么错,看怎么个懒法。有人纯粹是混日子的懒,有人是为了更高效率工作而走捷径。用R做自动化报告就是为了提高效率和保证结果可重复。

我想knitr最重要的两点是:

  1. 提高报告撰写效率:通过knitr我们可以直接撰写研究报告,避免每次需要把实验结果保存图片再放到doc文档中,尤其是一些统计性质的结果,反复粘贴只会让人对工作产生厌烦情绪;

  2. 保证结果可重复:其实在我们做研究的过程中,总会遇到无法复现出别人的实验结果,无法获得跟原文作者或者实验室师兄师姐的实验效果,产生这种问题的情况有很多,最普遍的是学术不端,为了防止此类事情的发生,自动化报告就可以派上用场了。

knitr历史

对于knitr的创立,还是源于对sweave复杂使用的改进,这些编程范式最主要的目的是把实验代码和论文正文放到一起,编译的时候可以直接执行代码,并将结果保存在正文所需要的位置。这种方法统称为文学化编程(Literate Programming),这个名字很有文艺范,让我突然有种想成为一个仰望云端的文艺男青年的赶脚~

这种设计方式的优势显而易见:代码和文档在一起,方便互相更新和照应。比如修改了代码之后可以很快也更新相应的文档段落,而不必像传统方式那样,从源代码文件跳到文档文件中去更新。

对于knitr名字的来源,谢老大是这样描述link的:

knitr这个包的名字是怎么来的呢?Sweave实际上是由S(代表S语言,也就是R语言它娘亲)和weave(编织)组成的,Weave是文学化编程的概念,就是把文字和代码编织到一起。我在考虑包的名字的时候,由于满心要对Sweave的各种不利索吐槽,所以我决定给我的新包一个利索的名字,英语里说利索通常用neat这个词,而同时编织还有另一个词叫knit,二者发音相近,用它取名可谓一石二鸟,音意两全。knit后面加上字母r也有几重考虑:

1.R代表R语言,为什么小写?因为小写对用户来说输入方便,不用按Shift;

2.knitr看起来和读起来像knitter,谐音neater,充分表达了某种要凌驾于对手之上的情绪,说得不好听就是自恋;

3.knitr不是一个正常的英文单词,所以Google搜索的第一条确定一定以及肯定会是我的网站,方便用户搜到文档,在各种社交网络上它也可以作为标签。

knitr语法

1. Markdown

knitr可以很方便的生成报告是因为采用markdown的编程范式,对于markdown的使用可以参考我之前的文档link,也可参考另一篇中文的MarkDown语法说明link。knitr已经包含代码高亮,所以就不需要采用我介绍的那种代码高亮的方式。

2. Latex

同样,knitr支持Latex,如果你试过一次Latex,你就会爱上她,很简单,比word输入公式简单好几条街。对于Latex的使用说明可以自行学习,参考Latex数学公式对照表以及Mathjax公式简介。我们可以在实验报告中输入类似以下的公式,并使公式左对齐:

\[ \begin{align} MISE & = E[ISE]\\\ & = E[\int(\hat{f}(x)-f(x))^2dx] \\\ & = \int E[(\hat{f}(x)-f(x))^2]dx \\\ & = \int MSE(\hat{f}(x)) \\\ & := IMSE \end{align} \]

HTML

我们还可以通过直接写HTML代码控制字体大小或者颜色等样式,也可将格式封装到CSS中。例如输入drafly是谁?:

<p>
  <font size="5" face="Verdana" color="color-value">
    drafly是谁?
  </font>
</p>

drafly是谁?

knitr入门

knitr的配置很简单,具体参考knitr的主页。主要步骤如下:

  1. 安装knitr包;

  2. 配置knitr:将Preference -> Sweave -> Weave Rnw files using 改为 knitr;

  3. 新建文件 -> New File -> R Markdown,选择要生成文件格式HTML;

  4. 点击Knit HTML按键即可生成对应的研究报告。

knitr高级篇

在Rmd文件中添加代码段(Insert Chunks),如下:

## ----cool, results='asis'------------------------------------------------
library(knitr)
summary(head(mtcars))
##       mpg             cyl         disp             hp       
##  Min.   :18.10   Min.   :4   Min.   :108.0   Min.   : 93.0  
##  1st Qu.:19.27   1st Qu.:6   1st Qu.:160.0   1st Qu.:106.2  
##  Median :21.00   Median :6   Median :192.5   Median :110.0  
##  Mean   :20.50   Mean   :6   Mean   :211.8   Mean   :117.2  
##  3rd Qu.:21.30   3rd Qu.:6   3rd Qu.:249.8   3rd Qu.:110.0  
##  Max.   :22.80   Max.   :8   Max.   :360.0   Max.   :175.0  
##       drat             wt             qsec             vs     
##  Min.   :2.760   Min.   :2.320   Min.   :16.46   Min.   :0.0  
##  1st Qu.:3.098   1st Qu.:2.684   1st Qu.:17.02   1st Qu.:0.0  
##  Median :3.500   Median :3.045   Median :17.82   Median :0.5  
##  Mean   :3.440   Mean   :2.988   Mean   :18.13   Mean   :0.5  
##  3rd Qu.:3.888   3rd Qu.:3.384   3rd Qu.:19.23   3rd Qu.:1.0  
##  Max.   :3.900   Max.   :3.460   Max.   :20.22   Max.   :1.0  
##        am           gear          carb      
##  Min.   :0.0   Min.   :3.0   Min.   :1.000  
##  1st Qu.:0.0   1st Qu.:3.0   1st Qu.:1.000  
##  Median :0.5   Median :3.5   Median :1.500  
##  Mean   :0.5   Mean   :3.5   Mean   :2.167  
##  3rd Qu.:1.0   3rd Qu.:4.0   3rd Qu.:3.500  
##  Max.   :1.0   Max.   :4.0   Max.   :4.000
plot(cars)

可以看到knitr可以执行上述的代码段,并绘制图表。在代码段中我们还可以通过参数控制代码段。例如:

  1. 代码高亮(highlight=TRUE),增强可读性,有无数的高亮主题可选,仅适用于LaTeX和HTML输出,MD文档在转为HTML文档之后可以用专门的JavaScript库去高亮代码;

  2. 代码重排(tidy=TRUE),对那些不注意代码格式的人来说很有用,再乱的代码,到了这里也会变得相对整齐,本功能由formatR包支持;

  3. 执行或不执行代码(eval=TRUE/FALSE),不执行的代码段将被跳过,原样输出源代码;

  4. 显示/隐藏源代码(echo=TRUE/FALSE),甚至精确控制显示哪几段代码(echo取数值);

  5. 显示/隐藏普通文本输出或将文本输出以原样形式输出(results=‘markup’, ‘hide’, ‘asis’);

  6. 显示/隐藏警告文本(warning=TRUE/FALSE)、错误消息(error)和普通消息(message);

  7. 显示/隐藏整个代码段的输出(include=TRUE/FALSE),比如我们可能想运行代码,但不把结果写入输出中。

但是从上面的结果可以看出R的表格不太美观,这里可以采用ktable封装knitr的表格。

## ----cool, results='asis'------------------------------------------------
library(knitr)
kable(head(mtcars))
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

或者采用JQuery的dataTable来封装表格,dataTable功能相对更强大一些。有很多参数可供选择,比如,搜索、排序、翻页等。具体参考DataTables官网

## ----cool, results='asis'------------------------------------------------
library(knitr)
kable(head(mtcars), 'html', table.attr='id="mtcars_table"')
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1