如何在dplyr中无需逐个指定变量即可灵活排序二进制数据框?
动态变量下的健壮排序方案
你遇到的问题非常典型——当变量数量动态变化时,手动修改arrange里的变量列表既繁琐又容易出错。下面提供两种无需逐个命名变量的解决方案,完美适配任意num_var值:
方法1:使用dplyr::across()(推荐,适用于dplyr 1.0.0+)
across()是dplyr 1.0.0版本引入的工具,专门用来对多列应用同一函数,它支持tidyselect选择器(比如everything())。我们可以用它把desc()应用到除total外的所有列:
library(tidyverse) library(glue) num_var <- 3 rep(list(c(0L, 1L)), num_var) %>% set_names(glue("var_{seq_len(num_var)}")) %>% expand.grid() %>% mutate(total = rowSums(.)) %>% select(total, everything()) %>% arrange(total, across(everything(), desc))
当你把num_var改成4时,代码不需要任何修改,会自动对var_1到var_4执行降序排序。
方法2:使用!!!与syms()(适配旧版dplyr)
如果你使用的是低于1.0.0版本的dplyr,可以通过符号表达式展开的方式实现:
library(tidyverse) library(glue) num_var <- 3 # 先动态生成变量名向量 var_names <- glue("var_{seq_len(num_var)}") rep(list(c(0L, 1L)), num_var) %>% set_names(var_names) %>% expand.grid() %>% mutate(total = rowSums(.)) %>% select(total, everything()) %>% # 把变量名转成符号,逐个套上desc,再用!!!展开 arrange(total, !!!purrr::map(rlang::syms(var_names), desc))
为什么原来的desc(everything())会报错?
desc()本身并不支持tidyselect语法,它无法解析everything()这种选择器——它需要接收具体的变量对象。而across()是dplyr专门设计来处理多列函数应用的接口,能正确识别并处理tidyselect选择器。
内容的提问来源于stack exchange,提问作者Jake Thompson
相关产品推荐
相关产品推荐

