将变量名称的向量传递给 dplyr 中的arrange()
Posted
技术标签:
【中文标题】将变量名称的向量传递给 dplyr 中的arrange()【英文标题】:Pass a vector of variable names to arrange() in dplyr 【发布时间】:2014-12-17 07:55:38 【问题描述】:我想传递arrange()
dplyr 一个变量名向量来进行排序。通常我只是输入我想要的变量,但我正在尝试创建一个函数,其中排序变量可以作为函数参数输入。
df <- structure(list(var1 = c(1L, 2L, 2L, 3L, 1L, 1L, 3L, 2L, 4L, 4L
), var2 = structure(c(10L, 1L, 8L, 3L, 5L, 4L, 7L, 9L, 2L, 6L
), .Label = c("b", "c", "f", "h", "i", "o", "s", "t", "w", "x"
), class = "factor"), var3 = c(7L, 5L, 5L, 8L, 5L, 8L, 6L, 7L,
5L, 8L), var4 = structure(c(8L, 5L, 1L, 4L, 7L, 4L, 3L, 6L, 9L,
2L), .Label = c("b", "c", "d", "e", "f", "h", "i", "w", "y"),
class = "factor")), .Names = c("var1", "var2", "var3", "var4"),
row.names = c(NA, -10L), class = "data.frame")
# this is the normal way to arrange df with dplyr
df %>% arrange(var3, var4)
# but none of these (below) work for passing a vector of variables
vector_of_vars <- c("var3", "var4")
df %>% arrange(vector_of_vars)
df %>% arrange(get(vector_of_vars))
df %>% arrange(eval(parse(text = paste(vector_of_vars, collapse = ", "))))
【问题讨论】:
Imo,应该保存使用 %>% 以进行链接,因为它非常丑陋...(对于单个操作 【参考方案1】:Hadley 没有在帮助文件中明确说明这一点——仅在他的 NSE 小插图中。后跟下划线的函数版本使用标准评估,因此您将它们传递给字符串向量等。
如果我正确理解您的问题,您只需将arrange()
替换为arrange_()
即可。
具体来说,在执行此操作时将字符串向量作为.dots
参数传递。
> df %>% arrange_(.dots=c("var1","var3"))
var1 var2 var3 var4
1 1 i 5 i
2 1 x 7 w
3 1 h 8 e
4 2 b 5 f
5 2 t 5 b
6 2 w 7 h
7 3 s 6 d
8 3 f 8 e
9 4 c 5 y
10 4 o 8 c
========== 2018 年 3 月更新 ==============
在 dplyr 中使用标准评估版本,正如我在此处显示的那样现在被认为已弃用。您可以阅读Hadley's programming vignette 了解新方法。基本上,您将使用!!
取消引用一个变量或使用!!!
取消引用arrange()
内的变量向量。
当您传递这些列时,如果它们是空的,请使用 quo()
引用它们作为一个变量或使用 quos()
引用它们作为向量。不要使用引号。请参阅 Akrun 的答案。
如果您的列已经是字符串,则使用rlang::sym()
为单个列命名,或使用rlang::syms()
为向量命名。请参阅克里斯托斯的答案。您还可以将as.name()
用于单个列。不幸的是,在撰写本文时,有关如何使用 rlang::sym()
的信息尚未包含在我上面链接到的小插图中(根据他的草稿,最终它将在“可变参数准引用”部分中)。
【讨论】:
我也是这么想的,但是如果你这样做df %>% arrange_(vector_of_vars)
,它似乎会忽略第二个元素并且只对第一个元素进行排序。但是,如果您执行df %>% arrange_(vector_of_vars[1], vector_of_vars[2])
,那么它会根据这两个值进行排序。我认为有一种比第二种方法更优雅的方法,但我不确定它是什么。
arrange_()
似乎确实忽略了第二列。 @eipi10 你的解决方案可以工作,但问题是vector_of_vars
中可以有任意数量的元素。
啊,这行得通:df %>% arrange_(.dots = vector_of_vars)
。 farnsy,如果你做出这个改变,我会给你答案
@farnsy 如果你想按降序排序怎么办?如何传递 desc 参数?我还没想通!
vector_of_vars <- c("desc(var3)", "var4");df %>% arrange_(.dots=vector_of_vars)
【参考方案2】:
在新版本中(即将发布0.6.0
的dplyr
)我们可以使用quosures
library(dplyr)
vector_of_vars <- quos(var1, var3)
df %>%
arrange(!!! vector_of_vars)
# var1 var2 var3 var4
#1 1 i 5 i
#2 1 x 7 w
#3 1 h 8 e
#4 2 b 5 f
#5 2 t 5 b
#6 2 w 7 h
#7 3 s 6 d
#8 3 f 8 e
#9 4 c 5 y
#10 4 o 8 c
当有多个变量时,我们使用quos
,对于单个变量,我们使用quo
。 quos
将返回引用变量的 list
,在 arrange
内部,我们使用 !!!
取消引用 list
进行评估
【讨论】:
...现在又被弃用了...1: Unquoting language objects with '!!!' is soft-deprecated as of rlang 0.3.0. Please use '!!' instead.
令人兴奋(保持礼貌)在 tidyverse 中有多少功能不断被弃用...我会回到 Base R对于我的长期代码,我认为...【参考方案3】:
本着 quosures 精神:
df %>% arrange(!!! rlang::syms(c("var1", "var3")))
对于单个变量,它看起来像:
df %>% arrange(!! rlang::sym(c("var1")))
【讨论】:
【参考方案4】:我认为现在你可以使用dplyr::arrange_at()
。
library(dplyr)
### original
head(iris)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 5.1 3.5 1.4 0.2 setosa
# 2 4.9 3.0 1.4 0.2 setosa
# 3 4.7 3.2 1.3 0.2 setosa
# 4 4.6 3.1 1.5 0.2 setosa
# 5 5.0 3.6 1.4 0.2 setosa
# 6 5.4 3.9 1.7 0.4 setosa
### arranged
iris %>%
arrange_at(c("Sepal.Length", "Sepal.Width")) %>%
head()
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 4.3 3.0 1.1 0.1 setosa
# 2 4.4 2.9 1.4 0.2 setosa
# 3 4.4 3.0 1.3 0.2 setosa
# 4 4.4 3.2 1.3 0.2 setosa
# 5 4.5 2.3 1.3 0.3 setosa
# 6 4.6 3.1 1.5 0.2 setosa
【讨论】:
【参考方案5】:试试这个:
df %>% do(do.call(arrange_, . %>% list(.dots = vector_of_vars)))
实际上这可以更简单地写成:
df %>% arrange_(.dots = vector_of_vars)
虽然在这一点上我认为它与 farnsy 的隐含解决方案相同。
【讨论】:
这对我不起作用,请参阅my post。 arrange_ 已弃用,quosures 方式似乎是要走的路【参考方案6】:它有点密集,但我认为现在最好的方法是使用 across()
以及 tidyselect 函数,例如all_of()
:
df <- structure(list(var1 = c(1L, 2L, 2L, 3L, 1L, 1L, 3L, 2L, 4L, 4L
), var2 = structure(c(10L, 1L, 8L, 3L, 5L, 4L, 7L, 9L, 2L, 6L
), .Label = c("b", "c", "f", "h", "i", "o", "s", "t", "w", "x"
), class = "factor"), var3 = c(7L, 5L, 5L, 8L, 5L, 8L, 6L, 7L,
5L, 8L), var4 = structure(c(8L, 5L, 1L, 4L, 7L, 4L, 3L, 6L, 9L,
2L), .Label = c("b", "c", "d", "e", "f", "h", "i", "w", "y"),
class = "factor")), .Names = c("var1", "var2", "var3", "var4"),
row.names = c(NA, -10L), class = "data.frame")
vector_of_vars <- c("var3", "var4")
df %>% arrange(across(all_of(vector_of_vars)))
【讨论】:
以上是关于将变量名称的向量传递给 dplyr 中的arrange()的主要内容,如果未能解决你的问题,请参考以下文章
根据向量new_varname,old_varname重命名dplyr中的变量名[重复]
将字符串传递给 R 函数参数,但稍后用作另一个函数的参数名称