深入理解dplyr中的编程技巧:数据掩码与整洁选择
dplyr dplyr: A grammar of data manipulation 项目地址: https://gitcode.com/gh_mirrors/dp/dplyr
前言
dplyr作为R语言中最受欢迎的数据处理包之一,其强大的数据操作能力很大程度上依赖于两种关键技术:数据掩码(Data Masking)和整洁选择(Tidy Selection)。本文将深入探讨这两种技术的原理、应用场景以及如何在编程中灵活运用它们。
数据掩码(Data Masking)详解
什么是数据掩码
数据掩码是dplyr中一项革命性的技术,它允许我们直接在函数中引用数据框中的列名,而不需要重复输入数据框名称。这种设计极大地简化了数据操作的语法。
# 传统R语法
starwars[starwars$homeworld == "Naboo" & starwars$species == "Human", ]
# 使用dplyr和数据掩码
starwars %>% filter(homeworld == "Naboo", species == "Human")
环境变量与数据变量
理解数据掩码的关键在于区分两种"变量":
- 环境变量(env-variables):编程中的变量,存在于环境中,通常用
<-
创建 - 数据变量(data-variables):数据集中的列,存在于数据框中
df <- data.frame(x = runif(3), y = runif(3)) # df是环境变量,x和y是数据变量
df$x # 从环境变量中提取数据变量
间接引用技术
在实际编程中,我们经常需要间接引用变量,这时需要特殊技术:
- 参数传递时的引用:使用双大括号
{{ }}
进行"拥抱"操作
var_summary <- function(data, var) {
data %>% summarise(n = n(), min = min({{ var }}), max = max({{ var }}))
}
- 字符向量引用:使用
.data
代词和[[ ]]
操作符
for (var in names(mtcars)) {
mtcars %>% count(.data[[var]]) %>% print()
}
动态命名技巧
dplyr支持使用:=
进行动态列命名:
name <- "susan"
tibble("{name}" := 2) # 使用glue语法插入变量名
my_df <- function(x) {
tibble("{{x}}_2" := x * 2) # 使用拥抱语法基于参数命名
}
整洁选择(Tidy Selection)技术
整洁选择DSL
整洁选择提供了一套迷你领域特定语言,用于按名称、位置或类型选择列:
select(df, 1)
选择第一列select(df, starts_with("a"))
选择所有以"a"开头的列select(df, where(is.numeric))
选择所有数值列
间接选择方法
- 参数传递时的选择:使用双大括号
{{ }}
summarise_mean <- function(data, vars) {
data %>% summarise(n = n(), across({{ vars }}, mean))
}
- 字符向量选择:使用
all_of()
或any_of()
vars <- c("mpg", "vs")
mtcars %>% select(all_of(vars))
mtcars %>% select(!all_of(vars))
实用编程模式
用户提供数据
当函数接受用户提供的数据框时,通常不需要特殊处理:
mutate_y <- function(data) {
mutate(data, y = a + x)
}
处理多个表达式
- 单个用户表达式:
my_summarise <- function(data, expr) {
data %>% summarise(
mean = mean({{ expr }}),
sum = sum({{ expr }}),
n = n()
)
}
- 多个用户表达式:
my_summarise3 <- function(data, mean_var, sd_var) {
data %>%
summarise(mean = mean({{ mean_var }}), sd = sd({{ sd_var }}))
}
- 动态列命名:
my_summarise4 <- function(data, expr) {
data %>% summarise(
"mean_{{expr}}" := mean({{ expr }}),
"sum_{{expr}}" := sum({{ expr }}),
"n_{{expr}}" := n()
)
}
任意数量表达式
使用...
接受任意数量的表达式:
my_summarise <- function(.data, ...) {
.data %>%
group_by(...) %>%
summarise(mass = mean(mass, na.rm = TRUE), height = mean(height, na.rm = TRUE))
}
创建多列输出
返回未命名的数据框可以创建多列:
quantile_df <- function(x, probs = c(0.25, 0.5, 0.75)) {
tibble(val = quantile(x, probs), quant = probs)
}
在summarise
中使用时设置.unpack = TRUE
:
df %>%
group_by(grp) %>%
summarise(across(x:y, ~ quantile_df(.x, probs = .5), .unpack = TRUE))
变量转换模式
使用across()
和pick()
转换用户提供的变量:
my_summarise <- function(data, summary_vars) {
data %>% summarise(across({{ summary_vars }}, ~ mean(., na.rm = TRUE)))
}
控制输出列名:
my_summarise <- function(data, group_var, summarise_var) {
data %>%
group_by(pick({{ group_var }})) %>%
summarise(across({{ summarise_var }}, mean, .names = "mean_{.col}"))
}
循环处理技术
- 基本循环:
for (var in names(mtcars)) {
mtcars %>% count(.data[[var]]) %>% print()
}
- 函数式编程:
mtcars %>%
names() %>%
purrr::map(~ count(mtcars, .data[[.x]]))
总结
掌握dplyr中的数据掩码和整洁选择技术可以显著提高数据操作代码的效率和可读性。关键要点包括:
- 理解环境变量和数据变量的区别
- 掌握
{{ }}
拥抱操作和.data
代词的使用场景 - 熟练运用
across()
和pick()
进行多变量操作 - 了解动态列命名和循环处理的技术
这些技术组合使用可以解决绝大多数数据操作编程中的挑战,使你的dplyr代码更加灵活和强大。
dplyr dplyr: A grammar of data manipulation 项目地址: https://gitcode.com/gh_mirrors/dp/dplyr
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考