在dplyr 0.7.0+中正确使用dplyr :: select,使用字符向量选择列

Rob*_*inL 8 r dplyr tidyverse tidyeval rlang

假设我们有一个cols_to_select包含我们想要从数据帧中选择的列的字符向量df,例如

df <- tibble::data_frame(a=1:3, b=1:3, c=1:3, d=1:3, e=1:3)
cols_to_select <- c("b", "d")
Run Code Online (Sandbox Code Playgroud)

假设我们也想使用dplyr::select它,因为它是使用的操作的一部分,%>%因此使用select使代码易于阅读.

似乎有很多方法可以实现,但有些方法比其他方法更强大.请你告诉我哪个是"正确的"版本,为什么?或许还有另一种更好的方法?

dplyr::select(df, cols_to_select) #Fails if 'cols_to_select' happens to be the name of a column in df 
dplyr::select(df, !!cols_to_select) # i.e. using UQ()
dplyr::select(df, !!!cols_to_select) # i.e. using UQS()

cols_to_select_syms <- rlang::syms(c("b", "d"))  #See [here](https://stackoverflow.com/questions/44656993/how-to-pass-a-named-vector-to-dplyrselect-using-quosures/44657171#44657171)
dplyr::select(df, !!!cols_to_select_syms)
Run Code Online (Sandbox Code Playgroud)

ps我意识到这可以简单地在基础R中实现 df[,cols_to_select]

zee*_*hio 6

有一个示例dplyr::selecthttps://cran.r-project.org/web/packages/rlang/vignettes/tidy-evaluation.html使用:

dplyr::select(df, !!cols_to_select)
Run Code Online (Sandbox Code Playgroud)

为什么?让我们探讨您提到的选项:

选项1

dplyr::select(df, cols_to_select)
Run Code Online (Sandbox Code Playgroud)

如你所说,如果cols_to_select碰巧是df中列的名称,则会失败,所以这是错误的.

选项4

cols_to_select_syms <- rlang::syms(c("b", "d"))  
dplyr::select(df, !!!cols_to_select_syms)
Run Code Online (Sandbox Code Playgroud)

这看起来比其他解决方案更复杂.

选项2和3

dplyr::select(df, !!cols_to_select)
dplyr::select(df, !!!cols_to_select)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,这两种解决方案提供相同的结果.您可以看到输出!!cols_to_select!!!cols_to_select执行:

dput(rlang::`!!`(cols_to_select)) # c("b", "d")
dput(rlang::`!!!`(cols_to_select)) # pairlist("b", "d")
Run Code Online (Sandbox Code Playgroud)

!!UQ()操作员立即评估其说法的背景下,这就是你想要的.

!!!UQS()操作员用于在一次传递多个参数的函数.

对于像示例中的字符列名称,如果将它们作为长度为2(使用!!)的单个向量或作为具有两个长度为1的向量(使用)的列表,则无关紧要!!!.对于更复杂的用例,您需要使用多个参数作为列表:(使用!!!)

a <- quos(contains("c"), dplyr::starts_with("b"))
dplyr::select(df, !!a) # does not work
dplyr::select(df, !!!a) # does work
Run Code Online (Sandbox Code Playgroud)