【问题标题】:Using filter_ in dplyr where both field and value are in variables在字段和值都在变量中的 dplyr 中使用 filter_
【发布时间】:2015-10-23 22:58:11
【问题描述】:

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

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 中每个字段的过滤器值向量。

【问题讨论】:

  • 编辑问题以添加示例

标签: r dplyr


【解决方案1】:

您可以尝试使用来自lazyevalinterp

 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 选项更容易。例如,如果我们试图filter 基于 'fld1' 中的 'key' 变量的行与 'sval1' 中的对应值,则一个选项是使用 Map。我们对数据集(df1[fld1])进行子集化,并将 FUN(==)应用于 df1[f1d1] 的每一列,并在 'sval1' 中使用相应的值,然后使用 &amp;Reduce 得到一个逻辑向量习惯了filter'df1'的行。

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

数据

df1 <- cbind(df, Col2= c("A", "B", "B", "C", "A"))
fld1 <- c(fld, 'Col2')
sval1 <- c(sval, 'B')    

【讨论】:

  • 您的answered this before 如下,在此处修改以适合此帖子的名称:df %&gt;% filter(get(fld, envir=as.environment(df))==sval)。我刚刚尝试过,它也有效。
  • @ulfelder 我在 Hadley 的另一篇文章中得到评论说使用 get 不是更好。不过我没有链接。
【解决方案2】:

现在,rlang 0.4.0 为此类用例引入了一种更直观的新方法:

packageVersion("rlang")
# [1] ‘0.4.0’

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

df %>% filter(.data[[fld]]==sval)

#OR
filter_col_val <- function(df, fld, sval) {
  df %>% filter({{fld}}==sval)
}

filter_col_val(df, Unhappy, "Y")

更多信息请访问https://www.tidyverse.org/articles/2019/06/rlang-0-4-0/

上一个答案

使用 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)

更多关于dplyr 语法的信息,请参见http://dplyr.tidyverse.org/articles/programming.htmlrlanghttps://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}'"))

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

      • 与您的代码相比,我看不出df %&gt;% filter_(.dots = paste0(fld, "=='", sval, "'")) 中硬编码的内容。从我所见,它们在程序上是等效的。
      • 是的,抱歉,这听起来不那么刺耳。仅仅是在您的正确响应中,过滤器被直接烘焙到管道中。通过在外部定义点,更改这些点(比如使用循环)会更容易一些,这样管道就可以每次使用不同的过滤器应用于一系列数据。
      【解决方案5】:

      所以我试图做同样的事情,现在 dplyr 似乎有一个内置功能来解决这个问题。

      在此处查看最后一个示例:https://dplyr.tidyverse.org/reference/filter.html

      为了简单起见,我也将其粘贴在这里:

      # To refer to column names that are stored as strings, use the `.data` pronoun:
      vars <- c("mass", "height")
      cond <- c(80, 150)
      starwars %>%
        filter(
          .data[[vars[[1]]]] > cond[[1]],
          .data[[vars[[2]]]] > cond[[2]]
        )
      

      【讨论】:

        猜你喜欢
        • 2021-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-09
        • 1970-01-01
        • 2014-08-25
        • 2016-03-17
        • 1970-01-01
        相关资源
        最近更新 更多