在dplyr中使用filter_,其中字段和值都在变量中

时间:2015-08-01 09:02:08

标签: r dplyr

我想使用在变量中定义的字段来过滤数据帧,以选择也在变量中的值。说我有

df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"

我想要的值是df[df$Unhappy == "Y", ]

我已阅读nse小插图以尝试使用filter_,但无法理解。我试过了

df %>% filter_(.dots = ~ fld == sval)

没有返回任何内容。

我得到了我想要的东西
df %>% filter_(.dots = ~ Unhappy == sval)

但显然这违背了使用变量来存储字段名称的目的。请问有什么线索吗?最后,我想使用此fld是字段名称的向量,svalfld中每个字段的过滤值向量。

4 个答案:

答案 0 :(得分:16)

您可以尝试使用interp

中的lazyeval
 library(lazyeval)
 library(dplyr)
 df %>%
     filter_(interp(~v==sval, v=as.name(fld)))
 #   V Unhappy
 #1 1       Y
 #2 5       Y
 #3 3       Y

对于多个键/值对,我发现这是有效的,但我认为应该有更好的方法。

  df1 %>% 
    filter_(interp(~v==sval1[1] & y ==sval1[2], 
           .values=list(v=as.name(fld1[1]), y= as.name(fld1[2]))))
 #  V Unhappy Col2
 #1 1       Y    B
 #2 5       Y    B

对于这些情况,我发现base R选项更容易。例如,如果我们根据'fld1'中的'key'变量尝试filter行以及'sval1'中的相应值,则一个选项正在使用Map。我们对数据集(df1[fld1])进行了子集,并将FUN(==)应用于df1[f1d1]的每一列,并在'sval1'中使用相应的值,并将&与{{1}一起使用获取一个逻辑向量,可以用来Reduce'df1'的行。

filter

数据

 df1[Reduce(`&`, Map(`==`, df1[fld1],sval1)),]
 #   V Unhappy Col2
 # 2 1       Y    B
  #3 5       Y    B

答案 1 :(得分:9)

使用dplyr 0.6.0及更高版本,此代码有效:

packageVersion("dplyr")
# [1] ‘0.7.1’

df <- data.frame(V=c(6, 1, 5, 3, 2), Unhappy=c("N", "Y", "Y", "Y", "N"))
fld <- "Unhappy"
sval <- "Y"

df %>% filter(UQ(rlang::sym(fld))==sval)

#OR
df %>% filter((!!rlang::sym(fld))==sval)

#OR
fld <- quo(Unhappy)
sval <- "Y"
df %>% filter(UQ(fld)==sval)

有关http://dplyr.tidyverse.org/articles/programming.html提供的dplyr语法以及rlanghttps://cran.r-project.org/web/packages/rlang/index.html中的quosure用法的更多信息。

如果您发现难以掌握dplyr 0.6+中的非标准评估,Alex Hayes就该主题进行了精彩的撰写:https://www.alexpghayes.com/blog/gentle-tidy-eval-with-examples/

原始答案

使用dplyr 0.5.0及更高版本,可以使用更简单的语法并更接近@Ricky最初想要的语法,我发现它比使用lazyeval::interp

更具可读性
df %>% filter_(.dots = paste0(fld, "=='", sval, "'"))

#  V Unhappy
#1 1       Y
#2 5       Y
#3 3       Y

#OR
df %>% filter_(.dots = glue::glue("{fld}=='{sval}'"))

答案 2 :(得分:8)

这是基础R的替代方案,它可能不是很优雅,但它可能具有易于理解的好处:

df[df[colnames(df)==fld]==sval,]
#  V Unhappy
#2 1       Y
#3 5       Y
#4 3       Y

答案 3 :(得分:0)

来自LmW;我个人更喜欢使用dplyr管道,在管道之前指定点,以便更容易以编程方式使用,比如在过滤器循环中。

dots <-  paste0(fld," == '",sval,"'")
df   %>% filter_(.dots = dots)

LmW的示例是正确的,但值是硬编码