在 dplyr 0.7.0+ 中正确使用 dplyr::select,使用字符向量选择列
Correct usage of dplyr::select in dplyr 0.7.0+, selecting columns using character vector
假设我们有一个字符向量 cols_to_select
包含我们想要从数据帧 df
中 select 的一些列,例如
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")
假设我们还想使用 dplyr::select
,因为它是使用 %>%
的操作的一部分,因此使用 select
使代码易于阅读。
似乎有多种方法可以实现这一点,但有些方法比其他方法更可靠。请告诉我哪个是 'correct' 版本,为什么?或者也许还有另一种更好的方法?
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](
dplyr::select(df, !!!cols_to_select_syms)
p.s。我意识到这可以在 base R 中简单地使用 df[,cols_to_select]
来实现
https://cran.r-project.org/web/packages/rlang/vignettes/tidy-evaluation.html 中有一个 dplyr::select
的例子,它使用:
dplyr::select(df, !!cols_to_select)
为什么?让我们探讨一下您提到的选项:
选项 1
dplyr::select(df, cols_to_select)
正如你所说,如果 cols_to_select
恰好是 df 中的列名,那么这是错误的。
选项 4
cols_to_select_syms <- rlang::syms(c("b", "d"))
dplyr::select(df, !!!cols_to_select_syms)
这看起来比其他解决方案更复杂。
选项 2 和 3
dplyr::select(df, !!cols_to_select)
dplyr::select(df, !!!cols_to_select)
在这种情况下,这两种解决方案提供了相同的结果。您可以通过执行以下操作查看 !!cols_to_select
和 !!!cols_to_select
的输出:
dput(rlang::`!!`(cols_to_select)) # c("b", "d")
dput(rlang::`!!!`(cols_to_select)) # pairlist("b", "d")
!!
或 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
假设我们有一个字符向量 cols_to_select
包含我们想要从数据帧 df
中 select 的一些列,例如
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")
假设我们还想使用 dplyr::select
,因为它是使用 %>%
的操作的一部分,因此使用 select
使代码易于阅读。
似乎有多种方法可以实现这一点,但有些方法比其他方法更可靠。请告诉我哪个是 'correct' 版本,为什么?或者也许还有另一种更好的方法?
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](
dplyr::select(df, !!!cols_to_select_syms)
p.s。我意识到这可以在 base R 中简单地使用 df[,cols_to_select]
https://cran.r-project.org/web/packages/rlang/vignettes/tidy-evaluation.html 中有一个 dplyr::select
的例子,它使用:
dplyr::select(df, !!cols_to_select)
为什么?让我们探讨一下您提到的选项:
选项 1
dplyr::select(df, cols_to_select)
正如你所说,如果 cols_to_select
恰好是 df 中的列名,那么这是错误的。
选项 4
cols_to_select_syms <- rlang::syms(c("b", "d"))
dplyr::select(df, !!!cols_to_select_syms)
这看起来比其他解决方案更复杂。
选项 2 和 3
dplyr::select(df, !!cols_to_select)
dplyr::select(df, !!!cols_to_select)
在这种情况下,这两种解决方案提供了相同的结果。您可以通过执行以下操作查看 !!cols_to_select
和 !!!cols_to_select
的输出:
dput(rlang::`!!`(cols_to_select)) # c("b", "d")
dput(rlang::`!!!`(cols_to_select)) # pairlist("b", "d")
!!
或 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