R开发
这个技能提供了全面的现代R开发指导,强调当前最佳实践,包括tidyverse、性能优化和专业包开发。
核心原则
- 使用现代tidyverse模式 - 优先使用dplyr 1.1+特性、原生管道和当前API
- 优化前先分析 - 使用profvis和bench来识别真正的瓶颈
- 先写可读代码 - 仅在必要时优化,并且在分析后进行
- 遵循tidyverse风格指南 - 一致的命名、空格和结构
现代Tidyverse精华
原生管道(|>而不是%>%)
总是使用原生管道|>而不是magrittr%>%(R 4.1+):
# 现代
data |>
filter(year >= 2020) |>
summarise(mean_value = mean(value))
# 避免遗留管道
data %>% filter(year >= 2020)
Join语法(dplyr 1.1+)
使用join_by()进行所有连接:
# 现代连接语法与等式
transactions |>
inner_join(companies, by = join_by(company == id))
# 不等连接
transactions |>
inner_join(companies, join_by(company == id, year >= since))
# 滚动连接(最近匹配)
transactions |>
inner_join(companies, join_by(company == id, closest(year >= since)))
控制匹配行为:
# 期望1:1匹配
inner_join(x, y, by = join_by(id), multiple = "error")
# 确保所有行匹配
inner_join(x, y, by = join_by(id), unmatched = "error")
每操作分组.by
使用.by而不是group_by() |> ... |> ungroup():
# 现代方法(总是返回未分组)
data |>
summarise(mean_value = mean(value), .by = category)
# 多个分组变量
data |>
summarise(total = sum(revenue), .by = c(company, year))
列操作
使用现代列选择和转换函数:
# pick()用于数据掩蔽上下文中的列选择
data |>
summarise(
n_x_cols = ncol(pick(starts_with("x"))),
n_y_cols = ncol(pick(starts_with("y")))
)
# across()用于将函数应用于多个列
data |>
summarise(across(where(is.numeric), mean, .names = "mean_{.col}"), .by = group)
# reframe()用于每组多行结果
data |>
reframe(quantiles = quantile(x, c(0.25, 0.5, 0.75)), .by = group)
rlang元编程
有关全面的rlang模式,请参阅references/rlang-patterns.md。
快速参考
{{}}- 将函数参数转发给数据掩蔽函数!!- 注入单个表达式或值!!!- 从列表中注入多个参数.data[[]]- 按名称(字符向量)访问列pick()- 在数据掩蔽函数中选择列
带拥抱的示例函数:
my_summary <- function(data, group_var, summary_var) {
data |>
summarise(mean_val = mean({{ summary_var }}), .by = {{ group_var }})
}
性能优化
有关详细的性能指导,请参阅references/performance.md。
关键策略
- 先分析: 使用
profvis::profvis()和bench::mark() - 向量化操作: 当存在向量化替代方案时避免循环
- 使用dtplyr: 对于大型数据操作(lazy evaluation with data.table backend)
- 并行处理: 使用
furrr::future_map()进行可并行化的工作 - 内存效率: 预分配,使用适当的数据类型
快速示例:
# 分析代码
profvis::profvis({
result <- data |>
complex_operation() |>
another_operation()
})
# 基准测试替代方案
bench::mark(
approach_1 = method1(data),
approach_2 = method2(data),
check = FALSE
)
包开发
有关完整的包开发指导,请参阅references/package-development.md。
快速指南
API设计:
- 使用
.by参数进行每操作分组 - 使用
{{}}用于列参数 - 一致返回tibbles
- 彻底验证用户面向函数的输入
依赖关系:
- 为显著的功能增益添加依赖
- 核心tidyverse包通常值得包括:dplyr, purrr, stringr, tidyr
- 为广泛使用的包最小化依赖
测试:
- 为单个函数编写单元测试
- 为工作流程编写集成测试
- 测试边缘情况和错误条件
文档:
- 文档化所有导出的函数
- 提供使用示例
- 解释非明显的参数交互
常见迁移模式
基础R → Tidyverse
# 数据操作
subset(data, condition) → filter(data, condition)
data[order(data$x), ] → arrange(data, x)
aggregate(x ~ y, data, mean) → summarise(data, mean(x), .by = y)
# 函数式编程
sapply(x, f) → map(x, f) # 类型稳定
lapply(x, f) → map(x, f)
# 字符串
grepl("pattern", text) → str_detect(text, "pattern")
gsub("old", "new", text) → str_replace_all(text, "old", "new")
旧 → 新Tidyverse
# 管道
%>% → |>
# 分组
group_by() |> ... |> ungroup() → summarise(..., .by = x)
# 连接
by = c("a" = "b") → by = join_by(a == b)
# 重塑
gather()/spread() → pivot_longer()/pivot_wider()
额外资源
- rlang模式: 请参阅references/rlang-patterns.md以获得全面的数据掩蔽和元编程指导
- 性能优化: 请参阅references/performance.md以获得分析、基准测试和优化策略
- 包开发: 请参阅references/package-development.md以获得完整的包创建指导
- 对象系统: 请参阅references/object-systems.md以获得S3、S4、S7、R6和vctrs指导