工作流程:脚本和项目

工作流程:脚本和项目

本章将介绍两个组织代码的基本工具:脚本和项目。

6.1 脚本

到目前为止,您已经使用控制台来运行代码。这是一个很好的起点,但随着您创建了更复杂的 ggplot2 图形和更长的 dplyr 流水线,您会发现控制台很快就会变得拥挤起来。为了给自己更多的工作空间,请使用脚本编辑器。通过单击“文件”菜单,选择“新建文件”,然后选择“R 脚本”,或使用键盘快捷键 Cmd/Ctrl + Shift + N 打开它。现在您将看到四个窗格,如图一所示。脚本编辑器是实验代码的好地方。当您想要更改某些内容时,您不必重新键入整个代码,您只需编辑脚本并重新运行它。一旦您编写了有效且符合您要求的代码,您可以将其保存为脚本文件,以便以后轻松返回。

RStudio IDE with Editor, Console, and Output highlighted.
Figure 1: 图一:打开脚本编辑器会在 IDE 的左上方添加一个新的窗格。

6.1.1 运行代码

脚本编辑器是构建复杂 ggplot2 图或长序列 dplyr 操作的绝佳地方。有效使用脚本编辑器的关键是记住其中最重要的键盘快捷键之一:Cmd/Ctrl + Enter。这会在控制台中执行当前的 R 表达式。例如,看下面的代码:

library(dplyr)
library(nycflights13)

not_cancelled <- flights |> 
  filter(!is.na(dep_delay)█, !is.na(arr_delay))

not_cancelled |> 
  group_by(year, month, day) |> 
  summarize(mean = mean(dep_delay))

如果你的光标在 █ 处,按下 Cmd/Ctrl + Enter 将运行生成 not_cancelled 的完整命令。它还会将光标移动到以下语句(以 not_cancelled |> 开头)。这样可以轻松地通过反复按下 Cmd/Ctrl + Enter 逐步执行你的完整脚本。

你也可以通过按下 Cmd/Ctrl + Shift + S 一次性执行完整脚本,而不是逐个表达式地运行代码。定期这样做是确保你已经在脚本中捕捉到所有重要部分的好方法。

我们建议你始终从需要的包开始编写你的脚本。这样,如果你与他人分享你的代码,他们可以轻松看到需要安装哪些包。但请注意,永远不要在分享的脚本中包含 install.packages()。如果他们不小心的话,将更改他们的计算机,这是不礼貌的!

在未来的章节中工作时,我们强烈建议你从脚本编辑器开始,并练习你的键盘快捷键。随着时间的推移,通过这种方式将代码发送到控制台将变得如此自然,以至于你甚至不会想到它。

6.1.2 RStudio 排错

在脚本编辑器中,RStudio 会用红色波浪线和侧边栏中的红色叉号突出显示语法错误:

Script editor with the script x y <- 10. A red X indicates that there is syntax error. The syntax error is also highlighted with a red squiggly line.

将光标悬停在叉号上,查看问题所在:

Script editor with the script x y <- 10. A red X indicates that there is syntax error. The syntax error is also highlighted with a red squiggly line. Hovering over the X shows a text box with the text unexpected token y and unexpected token <-.

RStudio还会告诉你可能存在的问题:

Script editor with the script 3 == NA. A yellow exclamation mark indicates that there may be a potential problem. Hovering over the exclamation mark shows a text box with the text use is.na to check whether expression evaluates to NA.

6.1.3 保存与命名

RStudio 在你退出时会自动保存脚本编辑器的内容,并在重新打开时自动重新加载。尽管如此,最好还是避免使用Untitled1、Untitled2、Untitled3等命名,而是保存你的脚本并给它们起一个有意义的名字。

也许你会想把文件命名为 code.R 或者 myscript.R ,但在选择文件名之前,你应该考虑一下。文件命名的三个重要原则如下:

  1. 文件名应该是机器可读的:避免使用空格、符号和特殊字符。不要依赖大小写来区分文件。

  2. 文件名应该是人类可读的:使用文件名来描述文件的内容。

  3. 文件名应该与默认排序相匹配:以数字开头,这样按字母顺序排序时可以按照它们的使用顺序排列。

例如,假设你在项目文件夹中有以下文件。

alternative model.R
code for exploratory analysis.r
finalreport.qmd
FinalReport.qmd
fig 1.png
Figure_02.png
model_first_try.R
run-first.r
temp.txt

这里有各种问题:很难找到应该先运行哪个文件,文件名包含空格,有两个具有相同名称但大小写不同的文件(finalreport和FinalReport1),有些文件名不能描述其内容(run-first和temp)。

以下是以更好的方式命名和组织相同的文件集:

01-load-data.R
02-exploratory-analysis.R
03-model-approach-1.R
04-model-approach-2.R
fig-01.png
fig-02.png
report-2022-03-20.qmd
report-2022-04-02.qmd
report-draft-notes.txt

对关键脚本进行编号使得以正确的顺序运行它们变得很明显,而一致的命名方案使得看到变化变得更容易。此外,图像被以相似的方式标记,报告通过包含在文件名中的日期进行区分,而temp被重命名为report-draft-notes以更好地描述其内容。如果一个目录中有很多文件,可以进一步组织,将不同类型的文件(脚本、图像等)放在不同的目录中是一个好的建议。

6.2 项目

总有一天,你需要退出R,去做其他事情,之后再回来继续你的分析。总有一天,你会同时进行多个分析工作,而你希望将它们分开处理。总有一天,你需要将外部数据导入R,并将R中的数值结果和图表输出到外部。

为了应对这些现实情况,你需要做出两个决定:

  1. 什么是可信的数据来源?你将保存什么作为发生过程的永久记录?
  2. 你的分析工作存放在哪里?

6.2.1 什么是可信的数据来源

作为初学者,依靠当前的运行环境来存储你在分析过程中创建的所有对象是可以的。但是,为了更容易处理大型项目或与他人协作,你的可信数据来源应该是R脚本。有了R脚本(和数据文件),你可以重新创建运行环境。但如果只有运行环境,要重新创建R脚本就困难得多:你要么需要凭记忆重新输入大量代码(在这个过程中不可避免地会出错),要么需要仔细查找R历史记录。

为了帮助保持R脚本作为分析的可信来源,我们强烈建议你设置RStudio在会话之间不保存工作空间。你可以通过运行usethis::use_blank_slate()或者按照图6.2所示的选项来实现这一点。这会给你带来一些短期的不便,因为现在当你重启RStudio时,它将不再记住你上次运行的代码,你创建的对象或读取的数据集也不会立即可用。但这种短期的不便能避免长期的痛苦,因为它迫使你在代码中记录所有重要的程序。没有什么比三个月后发现你只在环境中保存了重要计算的结果,而不是在代码中保存计算过程本身更糟糕的了。

RStudio Global Options window where the option Restore .RData into workspace at startup is not checked. Also, the option Save workspace to .RData on exit is set to Never.
Figure 2: Copy these options in your RStudio options to always start your RStudio session with a clean slate.

有一对很好的键盘快捷键可以配合使用,确保你在编辑器中捕获了代码中的重要部分:

  1. 按 Cmd/Ctrl + Shift + 0/F10 重启R。
  2. 按 Cmd/Ctrl + Shift + S 重新运行当前脚本。

或者,如果你不使用键盘快捷键,你可以通过菜单 Session > Restart R(会话 > 重启R)来重启,然后选中并重新运行你的当前脚本。

6.2.2 你的分析文件存在哪里?

R有一个强大的工作目录概念。当你要求R加载文件时,它会在工作目录中查找;当你要求R保存文件时,它也会将文件保存在这里。RStudio在控制台顶部显示你当前的工作目录:

The Console tab shows the current working directory as ~/Documents/r4ds.

And you can print this out in R code by running getwd():

getwd()
#> [1] "/Users/hadley/Documents/r4ds"

在这个R会话中,当前的工作目录(可以把它想象成”家”)位于hadley的Documents文件夹中的r4ds子文件夹内。当你运行这段代码时会得到不同的结果,因为你的计算机目录结构与Hadley的不同!

作为R初学者,将工作目录设置为你的主目录、文档目录或计算机上的任何其他目录都是可以的。但是你已经学习了这本书的好几章了,你已经不再是初学者了。很快你就应该进化到将项目组织到不同的目录中,并在处理项目时将R的工作目录设置为相应的目录。

虽然你可以在R中设置工作目录,但我们不推荐这样做:

setwd("/path/to/my/CoolProject")

有一个更好的方法,这个方法也能让你像专家一样管理你的R工作。这个方法就是使用RStudio项目(RStudio project)。

6.2.3 RStudio projects

将与特定项目相关的所有文件(输入数据、R脚本、分析结果和图表)都保存在同一个目录中是一个明智且常见的做法,RStudio通过项目功能内置了对这种做法的支持。让我们为你创建一个项目,供你在学习本书剩余部分时使用。点击 File > New Project(文件 > 新建项目),然后按照图6.3所示的步骤操作。

Three screenshots of the New Project menu. In the first screenshot, the Create Project window is shown and New Directory is selected. In the second screenshot, the Project Type window is shown and Empty Project is selected. In the third screenshot, the Create New Project  window is shown and the directory name is given as r4ds and the project is being created as subdirectory of the Desktop.
Figure 3: To create new project: (top) first click New Directory, then (middle) click New Project, then (bottom) fill in the directory (project) name, choose a good subdirectory for its home and click Create Project.

将你的项目命名为r4ds,并仔细考虑将项目放在哪个子目录中。如果存放位置不合适,将来就很难找到它!

完成这个过程后,你会得到一个专门用于学习这本书的新RStudio项目。检查一下你的项目”主目录”是否为当前工作目录:

getwd()
#> [1] /Users/hadley/Documents/r4ds

现在在脚本编辑器中输入以下命令,并保存文件,将其命名为”diamonds.R”。然后,创建一个名为”data”的新文件夹。你可以通过点击RStudio文件窗格中的”New Folder”按钮来完成这个操作。最后,运行完整的脚本,它会在你的项目目录中保存一个PNG图片文件和一个CSV文件。不用担心具体细节,你会在本书后面学到这些内容。

library(tidyverse)

ggplot(diamonds, aes(x = carat, y = price)) + 
  geom_hex()
ggsave("diamonds.png")

write_csv(diamonds, "data/diamonds.csv")

退出RStudio。检查与你的项目关联的文件夹——注意那个.Rproj文件。双击该文件重新打开项目。你会发现一切都回到了你离开时的状态:相同的工作目录和命令历史,所有你之前在处理的文件仍然是打开的。不过,因为你遵循了我们上面的建议,你会得到一个全新的运行环境,确保你是从一个干净的状态开始。

用你熟悉的操作系统方式,在计算机上搜索diamonds.png,你会找到这个PNG文件(这不奇怪),同时也能找到创建它的脚本(diamonds.R)。这是一个巨大的优势!有一天,你可能想要重新制作某个图表,或者只是想了解它是如何生成的。如果你严格地使用R代码保存图表,而不是用鼠标或剪贴板,你就能轻松地重现之前的工作!

6.2.4 绝对路径和相对路径

一旦你在项目中工作,就应该始终使用相对路径而不是绝对路径。它们有什么区别呢?相对路径是相对于工作目录(即项目的主目录)的路径。当Hadley写data/diamonds.csv时,这实际上是/Users/hadley/Documents/r4ds/data/diamonds.csv的简写。但重要的是,如果Mine在她的电脑上运行这段代码,路径会指向/Users/Mine/Documents/r4ds/data/diamonds.csv。这就是为什么相对路径很重要:无论R项目文件夹最终位于何处,它们都能正常工作。

绝对路径无论你的工作目录是什么,都指向同一个位置。它们在不同的操作系统上看起来有些不同。在Windows上,它们以驱动器号(如C:)或两个反斜杠(如\servername)开头;在Mac/Linux上,它们以斜杠”/“(如/users/hadley)开头。你永远不应该在脚本中使用绝对路径,因为这会影响共享:没有人会有和你完全相同的目录配置。

操作系统之间还有另一个重要的区别:如何分隔路径的组成部分。Mac和Linux使用正斜杠(如data/diamonds.csv),而Windows使用反斜杠(如data\diamonds.csv)。R可以处理这两种类型(无论你当前使用的是什么平台),但不幸的是,反斜杠在R中有特殊含义,要在路径中得到一个反斜杠,你需要输入两个反斜杠!这会让人感到困扰,所以我们建议始终使用Linux/Mac风格的正斜杠。

6.3 总结

在本章中,你学习了如何在脚本(文件)和项目(目录)中组织你的R代码。就像代码风格一样,这一开始可能感觉像是额外的工作。但随着你在多个项目中积累更多代码,你会逐渐appreciate前期的一点组织工作如何能在未来为你节省大量时间。

总结一下,脚本和项目为你提供了一个可靠的工作流程,这将在未来对你很有帮助:

  1. 为每个数据分析项目创建一个RStudio项目。

  2. 在项目中保存你的脚本(使用有意义的名称),编辑它们,可以分段运行或整体运行。经常重启R以确保你在脚本中捕获了所有内容。

  3. 只使用相对路径,不要使用绝对路径。

这样,你需要的所有内容都在一个地方,并且与你正在进行的所有其他项目清晰地分开。

到目前为止,我们使用的是R包中自带的数据集。这让你可以更容易地用预准备的数据进行练习,但显然你的数据不会以这种方式提供。因此在下一章中,你将学习如何使用readr包将数据从磁盘加载到R会话中。