12.1 可重复研究与文学化编程概述

12.1 可重复研究与文学化编程概述

随着“数据+算法”驱动研究的不断深入,数据的不断扩增,量化分析方法的日趋复杂,研究成果可重复性(Reproducibility)的难度也不断加大。2016年《Nature》杂志对1 576名研究人员的调研结果表明,90%以上的受访者认为目前学术界存在可复现危机,且超过一半的受访者认为问题十分严重,并将其归因为数据封闭、分析缺乏细节等。如何促进他人对数据分析过程和结果的理解、复现和验证,提升研究和数据分析的信度,越来越被各界所重视。同时这也促进了可重复研究(Reproducible Research)及相关软件工具的发展。需要指出的是,可重复研究和可复制研究(Replicable Research)是两个不同的概念。前者指依托原始研究数据集和数据分析代码,复现研究结果(包括但不限于分析图表、分析结论等)的行为,也就是拿到原始数据,并运行对应的分析代码,理论上应该能够得到与原始研究一样的分析结果;后者指在独立于最初研究人员的情形下,不依赖原始研究数据集但采用相同方法,重复整个研究的行为,这个要求更高,如果复现的结果一致,则说明原始研究过程与结论十分可靠。简而言之,可重复研究是可复制研究重要且十分必要的一步。

马威克(Marwick)指出,一项可重复研究应遵循四个基本原则:第一,数据、代码可校验,可共享与归档;第二,计算环境统一,且被广泛使用;第三,分析过程以脚本程序为载体,可查看细节;第四,数据、代码有版本控制,迭代可溯源。因此,要实现研究的可重复,光是数据共享还不够,还需要在计算环境的选择、分析工具的使用和研究版本的控制等方面协同发力,从数据的共享走向分析环境、分析过程以及分析工具的开放、共享。

在此过程中,基于文学化编程(Literate Programming)思想开发的软件相继涌现,为推动可重复研究提供了工具支撑。一般认为,文学化编程是由斯坦福大学的唐纳德·爱尔文·克努特(Donald Ervin Knuth)在1984年率先提出的一种编程范式,目的是提高计算机程序的可读性,替代20世纪70年代提出的结构化编程范式。在结构化编程中,程序代码要严格按照编译或解释器的语法规则依序排列,用户可以通过采用文学化编程工具,将程序任务拆分为若干单元,每个单元中的代码以代码块(Code Chunk)的形式呈现,代码块可以与文字内容自由组合。

长期以来,文学化编程主要在计算机领域的软件编程人员中广泛应用,它与传统的结构化编程最大的不同在于:后者以计算机处理为导向,先按照计算机可理解、可处理的方式和顺序编写代码,然后运行代码输出结果;而前者以用户为导向,更像是在写文章,程序员按照自身思维和逻辑编写代码,并将代码隐藏在文章中,其更加关注的是代码的逻辑结构,而不是语法结构。当需要进行编译的时候,文章中干净、标准的代码文本可以直接运行得到结果。文学化编程既可以用于学术文献撰写,也可用于可重复报告(Reproducible Report)撰写。

R语言环境下开展文学化编程,实现可重复数据分析的主要工具包是Rmarkdown包和Knitr包,两者结合编译报告的流程如图12-1所示。

图12-1 Rmarkdown和Knitr包编译报告流程

图12-1显示,Rmarkdown和Knitr包处理源文件有两个路径:tangle和weave。tangle过程包括:提取源文件中的代码;生成代码文件;代码文件在相对应的编程环境中,从数据库或者本地的电子表格等文件调用数据,并执行输出结果。weave过程是将tangle过程输出的图标和图形等嵌入其他文本,并输出多种格式的文档。在配置好的RStudio环境下的Rmarkdown中,调整输出格式只需要单击“Knit”按钮,然后选择对应格式即可,如图12-2所示。

图12-2 RStudio环境下自动化报告输出按钮选项

Markdown是一种轻量级标记语言,具有简单的纯文本格式化语法,用普通文本编辑器就可以进行编辑,可以使用Pandoc将文本转换成html、pdf、doc等多种格式。相较于Word,Markdown更加方便简洁,尽管Word在编辑文档方面无所不能,但其功能太过复杂(如在输入文字后,需要调整字体、设置行高、设置页眉页脚等),使得大量精力耗费在文章的格式调整上。在Markdown中,创作者集中注意力输出文字,只需在文字前面加上一些简单的标记符号(如“#”“*”等),Markdown就会自动完成对应标记符号代表的格式输出。最为关键的是,Markdown的语法简单,学习成本低,这也是它成为目前网络流行写作语言的一个重要原因。Rmarkdown和Bookdown都是基于RStudio提供的Markdown工具,都是对Markdown功能的进一步拓展。

Knitr包是基于文学化编程思想设计开发的一个工具包,Knitr包的思想是把R代码嵌入报告中,编译报告的时候R代码被执行,源文档中的R代码在输出的时候被替换为相应的图表或计算结果,这些结果和源文件中的文本结合形成自动化报告。这样,只需要维护包含源代码的Rmd文档,输出文档就能自动生成。使用Rmarkdown和Knitr包输出自动化报告的流程如图12-3所示。

图12-3 使用Rmarkdown和Knitr包编写自动化报告流程