dplyr中的列式操作:across()函数详解

dplyr中的列式操作:across()函数详解

dplyr dplyr 项目地址: https://gitcode.com/gh_mirrors/dpl/dplyr

引言

在数据分析过程中,我们经常需要对数据框中的多个列执行相同的操作。传统方法是通过复制粘贴代码来逐个处理每一列,但这不仅效率低下,而且容易出错。dplyr包中的across()函数提供了一种优雅的解决方案,可以同时对多个列执行相同的操作。

across()函数基础

across()函数有两个主要参数:

  1. .cols:选择要操作的列,支持类似select()函数的列选择语法
  2. .fns:要应用于每个列的函数或函数列表

基本用法示例

# 计算所有数值型列的标准差
starwars %>% 
  summarise(across(where(is.numeric), sd))

# 按物种分组后,计算性别、性别认同和母星的唯一值数量
starwars %>% 
  group_by(species) %>% 
  filter(n() > 1) %>% 
  summarise(across(c(sex, gender, homeworld), n_distinct))

across()会自动忽略分组变量,避免意外修改它们。

高级用法

应用多个函数

我们可以通过传递命名函数列表来对每个列应用多个函数:

min_max <- list(
  min = ~min(.x, na.rm = TRUE), 
  max = ~max(.x, na.rm = TRUE)
)

starwars %>% summarise(across(where(is.numeric), min_max))

自定义结果列名

使用.names参数可以控制结果列名的生成方式,它接受一个glue格式的字符串:

starwars %>% summarise(across(where(is.numeric), min_max, .names = "{.fn}.{.col}"))

访问当前列名

在函数内部,可以使用cur_column()获取当前正在处理的列名:

df <- tibble(x = 1:3, y = 3:5, z = 5:7)
mult <- list(x = 1, y = 10, z = 100)

df %>% mutate(across(all_of(names(mult)), ~ .x * mult[[cur_column()]]))

与其他动词结合使用

across()不仅可以与summarise()一起使用,还可以与任何支持数据掩码的dplyr动词配合:

与mutate()结合

# 将所有数值型列缩放到0-1范围
rescale01 <- function(x) {
  rng <- range(x, na.rm = TRUE)
  (x - rng[1]) / (rng[2] - rng[1])
}

df %>% mutate(across(where(is.numeric), rescale01))

与filter()结合

filter()需要特殊处理,因为它需要额外的步骤来组合结果。dplyr提供了两个配套函数:

  • if_any():保留在至少一个选定列中满足条件的行
  • if_all():保留在所有选定列中都满足条件的行
# 保留所有列都不含NA的行
starwars %>% 
  filter(if_all(everything(), ~ !is.na(.x)))

与传统方法的比较

在dplyr的早期版本中,我们使用_if_at_all后缀的函数来处理列式操作。across()提供了更统一和强大的替代方案:

  1. 表达能力更强,可以表达以前无法实现的汇总操作
  2. 减少了需要记忆的函数数量
  3. 统一了选择语义,支持复合选择条件
  4. 不再需要手动引用变量名

代码转换指南

将旧代码转换为使用across()的步骤:

  1. 去掉函数名中的_if_at_all后缀
  2. 使用across()
    • 对于_if,将第二个参数用where()包装
    • 对于_at,去掉vars()
    • 对于_all,使用everything()
# 旧代码
df %>% mutate_if(is.numeric, ~mean(.x, na.rm = TRUE))
# 新代码
df %>% mutate(across(where(is.numeric), ~mean(.x, na.rm = TRUE)))

注意事项

  1. 当组合数值型汇总时,要注意n()等函数的影响
  2. across()mutate()中会一次性应用所有转换,这与旧函数逐个应用的行为不同
  3. 不能直接在select()rename()中使用across(),应改用rename_with()

结语

across()函数是dplyr中处理列式操作的强大工具,它简化了代码,提高了可读性,并提供了更大的灵活性。通过掌握across(),你可以更高效地处理数据操作任务,写出更简洁、更易维护的代码。

dplyr dplyr 项目地址: https://gitcode.com/gh_mirrors/dpl/dplyr

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喻珺闽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值