原文链接 🔗 4 Reproduce Work(opens new window)

📚 合集|社会科学的纯文本指南(opens new window)


# 错误最小化

我们已经看到了合适的工具集如何通过自动高亮代码来节省时间,确保引用的所有内容都在参考文献中,同时找出语法错误,并为常用方法或功能提供模板。这一过程中,你的时间节省了两次:一是不再自我重复,二是犯了更少的错误。在管理正在进行的项目时,错误最小化意味着解决两个相关问题,首先是在你注意不到的情况下,找到进一步减少错误扩大化的方法,在写代码和分析数据时,这一点尤其重要,其次是找到一种方法来回溯你为得到特定结果所做的工作。使用修订控制系统可以使我们更好地完成这件事,但是在特定的报告或论文方面,还有更多的工作要做。

编写代码时,通常会在运行过程中进行一些分析。你有一些想法,有一些想看的东西,事情总会接踵而来。通常,你应该尝试记录你的工作。如果你正在写 R 脚本,那么这通常意味着在代码中添加(简短但有用)的注释,来解释这一段代码的作用,这有利于增强代码的可读性,在这方面,写代码就像写散文一样,Hadley Wickham 的 R 风格指南(opens new window) 提供了一些有关提高代码可读性的指南。R 包 lintr(opens new window) 可以实现上述这些原则,它就像代码的复制编辑器一样,在 Emacs 中,可以通过 flycheck(opens new window) 工具自动使用 lintr。

编写代码过程中也应该尽量不要自我重复。一个有用的建议是,如果你发现自己在复制并粘贴代码块(例如,绘制相同类型的绘图或为一堆不同的变量运行相同类型的模型),那么你应该停下来看看是否可以写一个快速的便利功能,来更有效地实现自动化。这样,你的代码可以更短,并且不容易出现因为多次复制粘贴而导致的错误和不一致。

# 从服务器到数据表

数据分析中的错误,通常远远超过在论文中生成图片或表格和随后使用该输出结果之间存在的差距。在一般的处理方式中,你将数据分析的代码放在一个文件中,将其生成的输出结果放在另一个文件中,将论文的文本放在第三个文件中。进行分析的过程中,你收集数据分析的输出结果并将其复制过来粘贴到论文中,通常还需要手动重新格式化,这些步骤的每一步都增加了出错的几率,特别是表格,很容易从生成它的步骤中分离开。几乎所有撰写量化分析论文的人都面临着阅读包含结果或数字的稿件问题,这些结果或数据需要重新审查或复制(比如同行评审),但缺乏一些有关数据生成过程的信息。

即使你一直在努力工作,学术论文也需要相当长的时间才能完成写作、评审、修订和出版的周期。为了回答包括评审者在内的各种问题,有时候你必须去回顾自己两年前做过的工作,这并不罕见,你当然不希望从头开始做所有事情以获得正确的答案。我这样说并不夸张,不要说在重复别人的定量分析结果时遇到的困难,在相当短的时间内,就算作者自己,都很难复现自己以前的工作。计算机科学家对衰减的不可避免的过程有一个颇为艺术的称呼,仅仅因为它在硬盘上被单独放置了六个月或更长时间就可以取代项目:位腐烂(bit–rot)。

# 使用 RMarkdown 和 knitr

弥补上述写作过程中各个部分割裂的一个重要方法,就是使用 RMarkdown(opens new window) 和 knitr(opens new window) 在 R 中进行定量分析。我们前面已经提到了如何用 Markdown 这种轻量级格式写纯文本文档,而 RMarkdown 允许你将代码合并到这一过程中,旨在集成纯文本文档的写作和数据分析的执行。你可以像平常一样写论文(或者更常见的是记录数据分析的报告),写下将产生你想要的输出结果的 R 代码,每当你编译这个文档,最终结果是生成的表格或图片,而不是从其他地方粘贴过来的图表。这些代码块可以分布在文档的各个部分,通过块的开头和结尾处的特殊分隔符 ``` 与常规文本区分开来。

当准备就绪,「你 knit 文件」(谢益辉,2015)。也就是说,将 .Rmd 文件提供给处理代码块的 R,并生成一个新的 .md 文件,其中的代码块已经被替换为 R 的运算输出结果,然后,再将该 Markdown 文件转换为 PDF 或 HTML 文件,同时,R 中的 rmarkdown 包(opens new window) 提供了一个 render() 函数,只需简单的一步就可以将 .Rmd 转换为 HTML 或 PDF,这就是 RStudio 用于生成文档所做的工作。相反,如果你只想从文本中提取编写的代码,那么你就「tangle」该文件,输出 .R 文件,这在实践中非常简单。这种方法的优势在于可以更加轻松地正确记录你的工作,数据分析和写作在同一个文件中,数据分析的输出是即时动态的,并且输出结果的代码嵌入在论文中。如果你需要对不同的数据进行很多个但相同(或非常相似)的分析,RMarkdown 和 knitr 可以更轻松地生成风格一致且准确无误的分析报告。

RMarkdown 是几种 「文学编程(opens new window) 」格式之一,这种思想最早由计算机科学的先驱理论家 Donald Knuth(opens new window) 提出,他在业余时间开发了 排版系统,虽然他主要关注记录计算机程序,但现在看来,Knuth 预测了许多重要思想,并且开发了几种基础性工具,用于可重复的数据分析。

例如,下方的图片,是本文中包含在 .Rmd 中的源代码块动态生成的。有时我们只想显示代码产生的结果,那么在这种情况下,只输出下方的图片就可以了。但有的时候,我们也希望只显示源代码,那么就是下面这样的代码块。

library(ggplot2)
tea <- rnorm(100)
biscuits <- tea + rnorm(100, 0, 1.3)
data <- data.frame(tea, biscuits)
p <- ggplot(data, aes(x = tea, y = biscuits)) +
    geom_point() +
    geom_smooth(method = "lm") +
    labs(x = "Tea", y = "Biscuits") + theme_bw()
print(p)
1
2
3
4
5
6
7
8
9

example-figure-r-1

R 代码生成的图片

knitr 包和 RMarkdown 可以很方便地输出为 HTML,这使得编辑时易于移植、转换和快速预览。你可以在任何文本编辑器中使用 RMarkdown 文件,并且 Emacs 对其有着很好的支持。RStudio 也原生支持 .Rmd 文件,可以非常简便地输出为 HTML 和 PDF,并通过其 RPubs(opens new window) 服务将你的成果发布到网络上。[1] 同时,knitr 网站(opens new window) 有 大量的例子(opens new window) 展示 knitr 是如何工作的,包括从 基本的设置(opens new window) 到 更高级的示例(opens new window) 。

文学编程有其局限性。对于大型而复杂的分析报告来说,通过多个 .Rmd 文件生成最终结果,而不是在一个 .Rmd 文件中一次性生成最终结果,往往更加合理。这就是使用某种版本控制来管理项目仍然很重要的原因之一,因此,你可以根据需要跟踪你的工作文件,但这可能不太适合单个 .Rmd 文档。


  1. RStudio 的 RMarkdown 支持使用这里提到的所有工具,例如 knitr、Pandoc 等。 用 RStudio 写 RMarkdown 文档是使用纯文本和 R 整理论文和报告的最简单方法。 ↩︎