前 言
《R统计高级编程和数据模型》介绍如何使用流行的R语言进行数据分析,其目的是为使用R语言进行高级统计分析的科研人员提供实用的资源。《R统计高级编程和数据模型》属于高级图书,我们假设《R统计高级编程和数据模型》的读者已具备R语言的背景知识,并且熟悉一般的数据管理和相关函数的用法。
由于我们首要考虑的是《R统计高级编程和数据模型》的实用性,因此,我们不打算对书中介绍的各种统计模型在理论上或概念上做详细讨论。然而,为了帮助读者更好地理解这些分析方法及其应用,我们也会适当地介绍书中每个分析方法的概念背景。
《R统计高级编程和数据模型》约定
《R统计高级编程和数据模型》为黑白印刷,因此有些图片的彩色效果无法展示,对于此类图片,我们专门做了彩插,所对应的正文图片以星号标识,比如图1-12*就表示彩图,彩色效果可参见在线资源。
包的配置
全书要用到很多不同的R包。这些R包大大简化了我们的工作,并且提供了更加稳健和高级的图形选项及分析选项。
虽然没有必要求读者如此,但我们还是利用checkpoint包以确保《R统计高级编程和数据模型》的程序具有可重复性。如果读者不关心程序的可重复性问题,或者愿意碰碰运气,相信自己的代码在某个版本的R语言中能够正常运行,而且安装的程序包都能在R的任何一个版本中运行,那么读者可以跳过此处的内容。如果读者想保证程序的可重复性,但是不关心它为什么能运行,且不关心它如何运行,那么只需要将每一章的代码保存为R程序,然后在程序的开头运行checkpoint包。如果读者关心并想知道这一切的原理和过程,就请继续阅读前言中的后面几段内容。
有关程序的可重复性
R语言提供了很多额外的程序包,这是它的众多优点之一,但这也带来了一些问题。例如,假设读者今年一月份在自己的计算机里安装了R v3.4.3,并且作为R的一部分还安装了ggplot2包用于图形绘制。默认情况下,所安装的ggplot2包就是该包在1月份的版本。现在,在《R统计高级编程和数据模型》的某一章,作者要求安装ggplot2和cowplot两个包。因为已安装了ggplot2包,所以不再需要安装它。然而,假设你还没有安装cowplot包,因此,当你正好阅读到那一章时,你会想要安装cowplot包,假设时间就在今年4月份。这时候,默认情况下,你将获得与R语言在4月份的版本相匹配的cowplot最新版本。
现在假设另一个读者出现了,他也安装了R v3.4.3,但是还没有安装ggplot2和cowplot这两个包。他也在4月份读到了那一章,并且在4月份同时安装了这两个包,因此他安装了这两个包在4月份的版本。
即使你与其他读者安装了R语言的同一个版本,到最后你们也很可能安装了不同版本的ggplot和cowplot包,而且很可能不同于作者编写《R统计高级编程和数据模型》时使用的版本。
最终结果是:不同的人,即使有同一个版本的R,也很可能使用不同的包;或者即使使用相同的包,也可能是不同的版本。这给可重复性带来一个严重的问题。假设读者正在阅读一本书,但是书中的代码总是不能像书里所说的那样运行,这对于你来说很可能是一次非常沮丧的经历。如果读者正在生产或科研中使用代码,不可重复性将会是一个更严重的问题。
解决办法就是在所有读者之间实现标准化的版本,确保结果完全可重复,即不仅控制R的版本,而且还要控制所有包的版本。这将要求一种不同于默认系统的包安装和管理办法,默认系统总是使用CRAN提供的最新版本。我们设计checkpoint包就是为了解决这个问题。但是,需要做一些额外的准备工作和操作,对此有些读者可能觉得不爽,但这么做带来的好处是,能够保证读者不仅使用同一个版本的R语言,而且全部使用相同版本的程序包。
为了理解checkpoint包的工作过程,我们需要先了解一下有关R语言库和包的工作模式。
现在,主流的R包都是通过CRAN发布的。包的作者可将他们的最新包提交给CRAN,CRAN每天晚上都更新。对于某些操作系统,如Linux,CRAN只保存包的源代码;对于其他操作系统,如Windows,CRAN先编译生成这些包的二进制文件,并为这些二进制文件提供宿主服务。CRAN保存旧的源代码,但是通常不会保存旧的二进制格式的包太久时间。当在本地计算机上执行install.packages命令时,R语言访问一个在线程序库,默认就是CRAN,找到相应的包名,并把它下载到本地计算机,之后再把它安装到本地库。本地库实际上只是硬盘上的一个目录。R语言总是把某个目录当作默认本地库。在默认情况,当某个包安装结束时,它们就被添加到这个默认库中。当某个包安装到本地机器后,就可以使用library()函数装入或打开包了。R语言会自动从默认本地库中找到这个包,然后打开它。
checkpoint包的工作过程如下:我们首先在本地机器上创建一个新的库目录,用来保存某个日期的R包,然后在R的当前工作目录(读者可以通过调用getwd()函数得到当前工作目录)里扫描所有的R脚本文件,识别文件中的library()或require()函数调用。之后检查这些包是否安装在本地库中。如果不是,就找到CRAN的一个快照,此快照是由另一服务器专门创建的,用于支持checkpoint包的工作。这样,checkpoint包就可以安装所有可用程序包在某个特定日期的版本,进而确保读者使用的R语言和其他包的版本都是《R统计高级编程和数据模型》作者在编写此书时使用的同一个版本。如果读者想重新运行一年前编写的分析程序,那么也可以在新机器上安装这些包在一年前的版本。
假设读者已在一个R脚本里包含以下代码,可以使用checkpoint包读取这个R脚本,找到所有类似library(data.table)的语句,并且自动安装data.table包。顺便提一下,data.table是一个可用于数据管理的功能强大的程序包。如果读者不想让checkpoint包扫描当前工作目录,那么可以像《R统计高级编程和数据模型》那样设置另外一个项目路径。读者也可以将checkpoint包的库位置改到另一个文件夹位置,而不是使用默认位置,事实上我们就是这样做的。为此,《R统计高级编程和数据模型》专门设置了两个变量:book_directory和checkpoint_directory。如果读者在自己的计算机中使用checkpoint包,就需要将这两个变量设置为相应的目录,例如把book_directory设置为path/to/your/directory。需要注意的是,不管我们选择哪个文件夹,R程序都必须拥有该文件夹的读写权限。
library(checkpoint)
checkpoint("2018-09-28", R.version = "3.5.1",
project = book_directory,
checkpointLocation = checkpoint_directory,
scanForPackages = FALSE,
scan.rnw.with.knitr = TRUE, use.knitr = TRUE)
library(data.table)
options(
width = 70,
stringsAsFactors = FALSE,
digits = 2)
数据设置
《R统计高级编程和数据模型》用到了许多数据集,其中一个来自一项长期研究:美国生活变迁(Americas’Changing Lives,ACL)研究。数据是公开的,我们可以从http://doi.org/ 10.3886/ICPSR04690.v7网站下载。
美国生活变迁(ACL)是一项长期研究,分为五波数据集,如表Q-1所示。
表Q-1 ACL研究的五波数据集
数据集 年份
W1 1986
W2 1989
W3 1994
W4 2002
W5 2011
我们所需要的是一个R格式的数据文件,它的文件名是04690-0001-Data.rda。如果想详细了解这个研究项目,就有必要下载这个数据集的使用文档(PDF格式)。数据集下载后,需要将它解压到某个文件夹中。
在建立了R语言会话,并且装入所必需的库之后,就可以装入这个数据集。读者可能需要修改路径,改到数据文件解压后所在的文件夹。由于是一个RDA文件,装入这个数据集相当于把一个R对象装入工作区。接着,需要将它转换为数据表,只选择《R统计高级编程和数据模型》将要用到的变量,并把变量名改成比较直观的名字,后缀(如W1)表示了这些变量来自哪一波数据集。最后,需要将某些变量转换为因子类型,并且使用saveRDS()函数将处理后的数据集保存成压缩格式。这样做的好处在于,在后面的几章中,我们将能够很容易把这个经过处理的数据文件重新读回到R中,并把它赋给任何对象名,而非总是使用RDA文件中的对象名。
load("../ICPSR_04690/DS0001/04690-0001-Data.rda")
ls()
## [1] "book_directory" "checkpoint_directory"
## [3] "da04690.0001" "render_apress"
acl <- as.data.table(da04690.0001)
acl <- acl[, .(
V1, V1801, V2101, V2064,
V3007, V2623, V2636, V2640,
V2000,
V2200, V2201, V2202,
V2613, V2614, V2616,
V2618, V2681,
V7007, V6623, V6636, V6640,
V6201, V6202,
V6613, V6614, V6616,
V6618, V6681
)]
setnames(acl, names(acl), c(
"ID", "Sex", "RaceEthnicity", "SESCategory",
"Employment_W1", "BMI_W1", "Smoke_W1", "PhysActCat_W1",
"AGE_W1",
"SWL_W1", "InformalSI_W1", "FormalSI_W1",
"SelfEsteem_W1", "Mastery_W1", "SelfEfficacy_W1",
"CESD11_W1", "NChronic12_W1",
"Employment_W2", "BMI_W2", "Smoke_W2", "PhysActCat_W2",
"InformalSI_W2", "FormalSI_W2",
"SelfEsteem_W2", "Mastery_W2", "SelfEfficacy_W2",
"CESD11_W2", "NChronic12_W2"
))
acl[, ID := factor(ID)]
acl[, SESCategory := factor(SESCategory)]
acl[, SWL_W1 := SWL_W1 * -1]
saveRDS(acl, "advancedr_acl_data.RDS", compress = "xz")