dplyr::select()如何选择可能不存在于数据框中的变量?

19

我有一个辅助函数(比如说foo()),将在各种数据框上运行,这些数据框可能包含特定的变量,也可能不包含。假设我有

library(dplyr)
d1 <- data_frame(taxon=1,model=2,z=3)
d2 <- data_frame(taxon=2,pss=4,z=3)

我想要选择的变量是

vars <- intersect(names(data),c("taxon","model","z"))

也就是说,我希望 foo(d1) 返回 taxonmodelz 列,而 foo(d2) 仅返回 taxonz 列。

如果 foo 包含 select(data,c(taxon,model,z)),那么 foo(d2) 将失败(因为 d2 不包含 model)。如果我使用 select(data,-pss),那么 foo(d1) 也会类似地失败。

如果我退离 tidyverse,我知道如何做到这一点(只需返回 data[vars]),但我想知道是否有一种方便的方法来实现这一点,即 (1) 使用某种 select() 辅助程序(如 tidyselect::select_helpers)或者 (2) 使用 tidyeval(我还没有抽出时间去搞清楚!)

3个回答

26

另一个选项是select_if

d2 %>% select_if(names(.) %in% c('taxon', 'model', 'z'))

# # A tibble: 1 x 2
#   taxon     z
#   <dbl> <dbl>
# 1     2     3

select_if已过时,请使用any_of代替:

d2 %>% select(any_of(c('taxon', 'model', 'z')))
# # A tibble: 1 x 2
#   taxon     z
#   <dbl> <dbl>
# 1     2     3

在R中输入?dplyr::select,你会看到以下内容:

这些辅助函数从字符向量中选择变量:

all_of():匹配字符向量中的变量名。所有名称必须存在,否则会抛出越界错误。

any_of():与all_of()相同,只是对于不存在的名称不会抛出错误。


1
所有答案都很好,但这个答案既简洁易读又没有抛出任何警告。(@G.Grothendieck的方法最接近我给出的方法)。 - Ben Bolker
1
d2 %>% select(which(names(.) %in% c('taxon', 'model', 'z'))) - tjebo
2
拥有备选方案总是很好的,但 select_if(...) 似乎比 select(which(...)) 更好。 - Ben Bolker
对于较大的数据框,select_if(names(.)...)非常慢。 - Inferrator

7

您可以使用one_of()函数,该函数在列缺失时会发出警告,但仍然能选择正确的列:

d1 %>%
    select(one_of(c("taxon", "model", "z")))
d2 %>%
    select(one_of(c("taxon", "model", "z")))

one_of()已被弃用,推荐使用any_of()(适用于此处)或all_of()(如果变量不存在则会出错)。 - hplieninger

6

使用内置的anscombe数据框作为示例,注意z不是anscombe中的一列:

anscombe %>% select(intersect(names(.), c("x1", "y1", "z")))

提供:

   x1    y1
1  10  8.04
2   8  6.95
3  13  7.58
4   9  8.81
5  11  8.33
6  14  9.96
7   6  7.24
8   4  4.26
9  12 10.84
10  7  4.82
11  5  5.68

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接