R语言工作流:代码风格

https://wp.me/p80aHo-2ss

Table of Contents

良好的代码风格就像正确的标点:你可以不依赖它来完成事情,但它确实会让事情更容易阅读。即使你还是非常新手程序员,也建议你着手培养自己的代码风格。使用一致的风格能让他人(包括未来的你!)更容易阅读你的作品;如果你需要向别人求助,这一点尤其重要。

给代码做样式设置一开始可能会觉得有点繁琐,但只要你多加练习,很快就会变成自然而然的习惯。此外,还有一些很棒的工具可以让你快速地为已有代码重新设置风格,比如 Lorenz Walthert 开发的 styler 包。你安装完成后(用 install.packages("styler")),使用它的一个简便方法是通过 RStudio 的命令面板。命令面板允许你使用任意内置的 RStudio 命令,以及许多由各个包提供的扩展功能(addins)。按下 Cmd/Ctrl + Shift + P 打开面板,然后输入“styler”就能查看 styler 提供的所有快捷方式。图 4.1 展示了结果。

命名

我们之前简要讨论过命名规则。请记住,变量名(用 <- 创建的,以及用 mutate() 创建的)只能使用小写字母、数字和 _。使用 _ 在名称内部分隔单词。

# Strive for:
short_flights <- flights |> filter(air_time < 60)

一般经验是:最好优先使用较长、描述性强且容易理解的名称,而不是简短但需要快速输入的名称。短名称在编写代码时节省的时间相对不多(尤其是因为自动补全会帮你把字补全),但当你回到旧代码时就可能会花更久的时间:你不得不绞尽脑汁去破解那些令人费解的缩写。

如果你有一堆用于表示相关事物的名称,尽量做到前后一致。当你忘记了先前的命名约定时,不一致很容易出现,所以如果你需要回头去重命名也不要感到难为情。总体而言:如果你有一组变量都围绕同一个主题变化,更适合给它们一个共同的前缀,而不是共同的后缀——因为自动补全在变量名的开头处效果最好。

空格

在数学运算符两侧放置空格(除了 ^;即 +-==<、…),并且在赋值运算符(<-)周围也放置空格。

# Strive for
z <- (a + b)^2 / d

不要在常规函数调用的括号内部或括号外加空格。逗号后面始终要加一个空格,就像标准英语一样。

# Strive for
mean(x, na.rm = TRUE) # mean和()之间不要有空格

如果这样做能提升对齐效果,添加一些额外空格是可以的。例如,如果你在 mutate() 中创建多个变量,你可能希望在它们的等号 = 周围加上空格,以便让所有的 = 能对齐。这样做会让你更容易快速浏览代码。

flights |>
mutate(
speed = distance / air_time,
dep_hour = dep_time %/% 100,
dep_minute = dep_time %% 100
)

管道

|> 前面始终应当有一个空格,并且通常应当放在一行的末尾。这样做能让你更容易添加新的步骤、重新排列已有步骤、修改某个步骤中的元素,并通过在左侧快速浏览动词来获得总体的(约 10,000 英尺高空)视角。

# Strive for
flights |>
filter(!is.na(arr_delay), !is.na(tailnum)) |>
count(dest)

如果你要通过管道(pipe)传入的函数带有命名参数(例如 mutate() 或 summarize()),那么把每个参数都放在新的一行上。如果函数没有命名参数(例如 select() 或 filter()),就把所有内容保持在同一行;除非放不下,在这种情况下你应该把每个参数都放在各自独立的行上。

# Strive for
flights |>
group_by(tailnum) |>
summarize(
delay = mean(arr_delay, na.rm = TRUE),
n = n()
)

在管道的第一步之后,给每一行缩进两个空格。RStudio 会在你于 |> 后换行时自动帮你补上这些空格。如果你把每个参数都各自放在单独的一行上,那么再额外缩进两个空格。确保 ) 单独占一行,并且取消缩进以与函数名的水平位置保持一致。

# Strive for
flights |>
group_by(tailnum) |>
summarize(
delay = mean(arr_delay, na.rm = TRUE),
n = n()
)

如果你的管道(pipeline)能轻松放在一行里,那么你可以在一定程度上放宽对这些规则的遵守。但根据我们的共同经验,短小的片段往往会逐渐变得更长,因此你通常可以通过一开始就预留你所需要的所有垂直空间,反而在长期来看节省时间。

# more variables and more steps in the future
df |>
mutate(
y = x + 1
)

最后,要当心编写过长的管道(pipelines),比如超过 10–15 行。试着把它们拆分成更小的子任务,并给每个任务起一个信息量足够、具有说明性的名字。这些名字能帮助读者快速把握正在发生什么,也让你更容易核对中间结果是否符合预期。只要你有机会给某个东西取一个信息量足够的名字,就应该这么做——例如当你从根本上改变了数据的结构时,比如在 pivot(透视)或 summarizing(汇总)之后。不要指望一开始就写对!如果管道中存在一些中间状态,而这些状态可以很好地被命名,那么就应该把长管道拆开。

ggplot2

适用于管道(pipe)的相同基本规则也同样适用于 ggplot2;只要把 + 当作 |> 来处理就行。

flights |>
group_by(month) |>
summarize(
delay = mean(arr_delay, na.rm = TRUE)
) |>
ggplot(aes(x = month, y = delay)) +
geom_point() +
geom_line()

另外,如果你无法把某个函数的所有参数都放进同一行,那么就把每个参数都放在各自独立的行上:

flights |>
group_by(dest) |>
summarize(
distance = mean(distance),
speed = mean(distance / air_time, na.rm = TRUE)
) |>
ggplot(aes(x = distance, y = speed)) +
geom_smooth(
method = "loess",
span = 0.5,
se = FALSE,
color = "white",
linewidth = 4
) +
geom_point()

注意从 |> 转到 + 的衔接。我们希望这种转换并不需要,但遗憾的是,ggplot2 在发现管道(pipe)之前就已经写好了。

分节注释

随着你的脚本变得更长,你可以使用分区注释(sectioning comments)把文件拆分成便于管理的多个部分:

# Load data --------------------------------------
# Plot data --------------------------------------

RStudio 提供了一个键盘快捷键来创建这些标题(Cmd/Ctrl + Shift + R),并且会在编辑器左下角的代码导航下拉菜单中显示它们,如图 所示。

总结

在本章中,你已经学到了代码风格中最重要的原则。起初,这些可能会让人觉得是一套任意的规则(确实是!),但随着你写更多代码、并把代码分享给更多的人,你就会明白一致的风格有多重要。别忘了 styler 包:它是快速提升格式不够规范的代码质量的好方法。

评论

发表评论

了解 数据控|突破是我们的每一步 的更多信息

立即订阅以继续阅读并访问完整档案。

继续阅读