【问题标题】:Why doesn't dplyr filter() work within function (i.e. using variable for column name)?为什么 dplyr filter() 不能在函数内工作(即使用变量作为列名)?
【发布时间】:2017-12-28 21:42:03
【问题描述】:

使用 dplyr 函数过滤、分组和变异数据的函数。基本管道序列在函数之外非常有用,这就是我使用真实列名的地方。将它放在一个函数中,其中列名是一个变量,并且一些函数可以工作,但有些不能,尤其是 dplyr::filter()。例如:

var1 <- c('yes', NA, NA, 'yes', 'yes', NA, NA, NA, 'yes', NA, 'no', 'no', 'no', 'maybe', NA, 'maybe', 'maybe', 'maybe')

var2 <- c(1:18)

df <- data.frame(var1, var2)

这很好用(即过滤 NA):

df%>%filter(!is.na(var1))

...但这不是:

x <- "var1"

df%>%filter(!is.na(x))

...但确实如此:

df%>%select(x)

需要专门过滤掉的是NA。

试过get("x"),不行,切片:

df[!is.na(x),]

...也不好。

关于如何传递变量以在函数内部(或外部)进行过滤以及为什么变量与其他 dplyr 函数一起使用的任何想法?

【问题讨论】:

    标签: r filter dplyr


    【解决方案1】:

    有一个新包seplyr 将标准评估标准传递给 dplyr。试一试。您可以通过它将正常的引用代码传递给 dplyr。它使在 dplyr 中传递参数和编写函数更容易。

    对于您的情况:

    install.packages("seplyr")
    library(seplyr)
    x<-"var1"
    df%>%filter_se(paste0("!is.na(", x , ")"))
    

    【讨论】:

      【解决方案2】:

      这也可以,而且更简单一些 - 只需在方括号之间引用包含列名的变量并使用 (.) 来引用输入 df:

      > df %>% filter(!is.na((.)[x]))
          var1 var2
      1    yes    1
      2    yes    4
      3    yes    5
      4    yes    9
      5     no   11
      6     no   12
      7     no   13
      8  maybe   14
      9  maybe   16
      10 maybe   17
      11 maybe   18
      

      请注意,这也适用于函数:

      myfun <- function(df, var) {
        df %>%  filter(!is.na((.)[var]))
       }
      
       x <- "var1"
       myfun(df, x)
      
          var1 var2
      1    yes    1
      2    yes    4
      3    yes    5
      4    yes    9
      5     no   11
      6     no   12
      7     no   13
      8  maybe   14
      9  maybe   16
      10 maybe   17
      11 maybe   18
      

      【讨论】:

        【解决方案3】:

        由于我的声誉不够高,无法在上面发表评论......我建议在这里看看我的答案:https://stackoverflow.com/a/45265617/6238025

        如果你想用 dplyr 做一个函数,你需要按照这个网页的说明进行操作:https://rpubs.com/hadley/dplyr-programming

        library(tidyverse)
        var1 <- c('yes', NA, NA, 'yes', 
                  'yes', NA, NA, NA, 'yes', NA, 'no', 
                  'no', 'no', 'maybe', NA, 'maybe', 
                  'maybe', 'maybe')
        var2 <- c(1:18)
        
        df <- data_frame(var1, var2)
        
        your_function <- function(df, filter) {
              # Make filter a quosure
              filter = enquo(filter)
        
              df %>% 
                filter(!is.na(!!filter)) -> new_df
        
              return(new_df)
        }
        new_df <- your_function(df = df, filter = var1)
        

        您也可以跳过函数内的filter = enquo(filter),然后您的调用将是:

        your_function(df=df, filter=quo(var1))

        但是,第一种方法更适合进行函数调用。你不需要记住quo()

        应该可以!

        【讨论】:

          【解决方案4】:

          我们可以使用sym 转换为符号,然后用UQ 评估它

          library(rlang)
          library(dplyr)
          df %>%
             filter(!is.na(UQ(sym(x))))
          #     var1 var2
          #1    yes    1
          #2    yes    4
          #3    yes    5
          #4    yes    9
          #5     no   11
          #6     no   12
          #7     no   13
          #8  maybe   14
          #9  maybe   16
          #10 maybe   17
          #11 maybe   18
          

          【讨论】:

          • 为什么只使用 filter 函数而不使用 select()?
          • @ConnerM。 select 接受不带引号和带引号的字符串,即 df %&gt;% select('var1')df %&gt;% select(var1) 这不仅适用于 filter。如果你想要一些总结,那么你必须做同样的步骤
          • sym 是否属于特定的包?
          • @ConnerM。它在rlang,但我认为如果你安装tidyverse 并加载包,它应该被加载。假设你要总结df %&gt;% summarise(count = sum(!is.na(UQ(sym(x)))))
          • 对gather()有什么想法吗?
          猜你喜欢
          • 2018-12-23
          • 2019-03-02
          • 2020-02-22
          • 2021-06-24
          • 2015-04-04
          • 2018-06-21
          相关资源
          最近更新 更多