在R:子集或dplyr :: filter中,带有来自vector的变量

use*_*672 5 r subset dplyr

df <- 
  data.frame(a=LETTERS[1:4],
             b=rnorm(4)
             )

vals <- c("B","D")
Run Code Online (Sandbox Code Playgroud)

我可以df使用以下值过滤/子集val:

dplyr::filter(df, a %in% vals)
subset(df, a %in% vals)
Run Code Online (Sandbox Code Playgroud)

两者都给出:

  a         b
2 B 0.4481627
4 D 0.2916513
Run Code Online (Sandbox Code Playgroud)

如果我在向量中有变量名称,例如:

> names(df)[1]
[1] "a"
Run Code Online (Sandbox Code Playgroud)

然后它不起作用 - 我猜因为它的引用

dplyr::filter(df, names(df)[1] %in% vals)
[1] a b
<0 rows> (or 0-length row.names)
Run Code Online (Sandbox Code Playgroud)

你怎么做到这一点 ?

更新(如果它的dplyr :: tbl_df(df))

下面的答案适用于data.frames,但不适用于dplyr :: tbl_df包装数据:

df<-dplyr::tbl_df(df)
dplyr::filter(df, df[,names(df)[1]] %in% vals)
Run Code Online (Sandbox Code Playgroud)

不起作用(我认为tbl_df在df之上是一个简单的包装?)

这确实有效:

dplyr::filter(df, as.data.frame(df)[,names(df)[1]] %in% vals)
Run Code Online (Sandbox Code Playgroud)

最终更新:使用lazyeval :: interp与tbl_df()一起使用

请参阅下面的AndreyAkinshin的解决方案.

And*_*hin 7

你可以使用df[,"a"]df[,1]:

df <- data.frame(a = LETTERS[1:4], b = rnorm(4))
vals <- c("B","D")

dplyr::filter(df, df[,1] %in% vals)
#  a         b
# 2 B 0.4481627
# 4 D 0.2916513

subset(df, df[,1] %in% vals)
#  a         b
# 2 B 0.4481627
# 4 D 0.2916513

dplyr::filter(df, df[,"a"] %in% vals)
#  a         b
# 2 B 0.4481627
# 4 D 0.2916513

subset(df, df[,"a"] %in% vals)
#  a         b
# 2 B 0.4481627
# 4 D 0.2916513
Run Code Online (Sandbox Code Playgroud)

使用dplyr :: tbl_df(df)

一些神奇的lazyeval::interp帮助我们!

df <- dplyr::tbl_df(df)
expr <- lazyeval::interp(quote(x %in% y), x = as.name(names(df)[1]), y = vals)

df %>% filter_(expr)
# Source: local data frame [2 x 2]
#
#   a        b
# 1 B 0.4481627
# 2 D 0.2916513
Run Code Online (Sandbox Code Playgroud)