R4DS项目中的函数编写指南:提升数据科学效率
r4ds R for data science: a book 项目地址: https://gitcode.com/gh_mirrors/r4/r4ds
引言
在数据科学工作中,函数编写是一项核心技能。本文将基于R4DS项目中的函数编写理念,系统介绍如何创建和使用函数来提升数据分析效率。我们将从基础概念出发,逐步深入到实际应用场景。
为什么需要编写函数?
函数是自动化重复任务的强大工具,相比简单的复制粘贴,函数具有四大优势:
- 可读性:通过有意义的函数名称,让代码更易于理解
- 可维护性:需求变更时只需修改一处代码
- 可靠性:避免复制粘贴过程中可能出现的错误
- 可复用性:便于跨项目重用代码,提高长期生产力
经验法则:当同一段代码被复制粘贴超过两次时,就应该考虑将其封装为函数。
函数类型概述
我们将重点介绍三类实用函数:
- 向量函数:输入输出均为向量
- 数据框函数:处理数据框并返回数据框
- 绘图函数:基于数据框生成图形
向量函数开发
基础函数编写
以数据标准化为例,原始代码可能如下:
df <- tibble(
a = rnorm(5),
b = rnorm(5),
c = rnorm(5),
d = rnorm(5)
)
df |> mutate(
a = (a - min(a, na.rm = TRUE)) / (max(a, na.rm = TRUE) - min(a, na.rm = TRUE)),
b = (b - min(b, na.rm = TRUE)) / (max(b, na.rm = TRUE) - min(b, na.rm = TRUE)),
# 类似处理c和d...
)
将其转化为函数需要三个要素:
- 名称(如
rescale01
) - 参数(这里只需
x
) - 函数体
转换结果:
rescale01 <- function(x) {
(x - min(x, na.rm = TRUE)) / (max(x, na.rm = TRUE) - min(x, na.rm = TRUE))
}
函数优化技巧
- 性能优化:使用
range()
替代分开的min()
和max()
- 健壮性增强:处理无限值情况
优化后的版本:
rescale01 <- function(x) {
rng <- range(x, na.rm = TRUE, finite = TRUE)
(x - rng[1]) / (rng[2] - rng[1])
}
实用向量函数示例
- Z-score标准化:
z_score <- function(x) {
(x - mean(x, na.rm = TRUE)) / sd(x, na.rm = TRUE)
}
- 数值截断:
clamp <- function(x, min, max) {
case_when(
x < min ~ min,
x > max ~ max,
.default = x
)
}
- 字符串处理:
first_upper <- function(x) {
str_sub(x, 1, 1) <- str_to_upper(str_sub(x, 1, 1))
x
}
数据框函数开发
间接引用问题
当在函数中使用dplyr动词时,会遇到间接引用问题。例如:
grouped_mean <- function(df, group_var, mean_var) {
df |>
group_by(group_var) |>
summarize(mean(mean_var))
}
这种写法会报错,因为dplyr使用整洁计算(tidy evaluation)。
解决方案:拥抱操作符{{ }}
使用拥抱操作符告诉dplyr使用参数值而非字面变量名:
grouped_mean <- function(df, group_var, mean_var) {
df |>
group_by({{ group_var }}) |>
summarize(mean({{ mean_var }}))
}
何时使用拥抱操作符?
查看函数文档,关注两类整洁计算:
- 数据屏蔽(Data-masking):用于计算类函数如
arrange()
,filter()
,summarize()
- 整洁选择(Tidy-selection):用于选择类函数如
select()
,relocate()
,rename()
实用数据框函数示例
- 探索性分析摘要:
summary6 <- function(data, var) {
data |> summarize(
min = min({{ var }}, na.rm = TRUE),
mean = mean({{ var }}, na.rm = TRUE),
median = median({{ var }}, na.rm = TRUE),
max = max({{ var }}, na.rm = TRUE),
n = n(),
n_miss = sum(is.na({{ var }})),
.groups = "drop"
)
}
- 计数与比例:
count_prop <- function(df, var, sort = FALSE) {
df |>
count({{ var }}, sort = sort) |>
mutate(prop = n / sum(n))
}
- 条件筛选唯一值:
unique_where <- function(df, condition, var) {
df |>
filter({{ condition }}) |>
distinct({{ var }}) |>
arrange({{ var }})
}
开发环境技巧
- 快速查看函数定义:光标置于函数名按
F2
- 快速跳转到函数:
Ctrl + .
打开模糊查找
总结
通过系统地将重复代码封装为函数,我们可以显著提升数据分析工作的效率和质量。从简单的向量处理到复杂的数据框操作,函数化编程是成为高效数据科学家的关键技能。记住:优秀的函数应该具备清晰的名称、良好的文档和稳健的错误处理。
在实践中,建议从小的、具体的函数开始,逐步构建自己的函数库。随着经验的积累,您会发现越来越多的模式可以抽象为函数,从而让您的数据分析工作更加流畅和高效。
r4ds R for data science: a book 项目地址: https://gitcode.com/gh_mirrors/r4/r4ds
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考