【问题标题】:Non-standard evaluation (NSE) in dplyr's filter_ & pulling data from MySQLdplyr 的 filter_ 中的非标准评估 (NSE) & 从 MySQL 中提取数据
【发布时间】:2014-12-17 00:10:36
【问题描述】:

我想从带有动态过滤器的 sql 服务器中提取一些数据。我正在通过以下方式使用出色的 R 包 dplyr:

#Create the filter
filter_criteria = ~ column1 %in% some_vector
#Connect to the database
connection <- src_mysql(dbname <- "mydbname", 
             user <- "myusername", 
             password <- "mypwd", 
             host <- "myhost") 
#Get data
data <- connection %>%
 tbl("mytable") %>% #Specify which table
 filter_(.dots = filter_criteria) %>% #non standard evaluation filter
 collect() #Pull data

这段代码工作正常,但现在我想以某种方式在我表的所有列上循环它,因此我想将过滤器编写为:

#Dynamic filter
i <- 2 #With a loop on this i for instance
which_column <- paste0("column",i)
filter_criteria <- ~ which_column %in% some_vector

然后使用更新的过滤器重新应用第一个代码。

不幸的是,这种方法没有给出预期的结果。事实上,它没有给出任何错误,甚至没有将任何结果拉入 R。 特别是,我稍微研究了一下这两段代码生成的 SQL 查询,有一个重要的区别。

虽然第一个有效的代码会生成如下形式的查询:

SELECT ... FROM ... WHERE 
`column1` IN ....

(`签入列名),第二个生成查询形式:

SELECT ... FROM ... WHERE 
'column1' IN ....

('签入列名)

有人对如何制定过滤条件以使其发挥作用有任何建议吗?

【问题讨论】:

    标签: r lazy-evaluation dplyr


    【解决方案1】:

    另一种解决方案,使用 dplyr 版本 0.5.0(可能在此之前实现),可以将组合字符串作为 .dots 参数传递,我发现它比lazyeval::interp 解决方案更具可读性:

    df <- data.frame(
         v1 = sample(5, 10, replace = TRUE),
         v2 = sample(5,10, replace = TRUE)
    )
    
    which_col <- "v1"
    which_val <- 1
    df %>% filter_(.dots= paste0(which_col, "== ", which_val))
    
      v1 v2
    1  1  1
    2  1  2
    3  1  4
    

    更新适用于 dplyr 0.6 及更高版本:

    packageVersion("dplyr")
    # [1] ‘0.5.0.9004’
    
    df %>% filter(UQ(rlang::sym(which_col))==which_val)
    #OR
    df %>% filter((!!rlang::sym(which_col))==which_val)
    

    (类似于@Matthew 对 dplyr 0.6 的响应,但我假设 which_col 是一个字符串变量。)

    第二次更新:Edwin Thoen 为整洁的评估创建了一个不错的备忘单:https://edwinth.github.io/blog/dplyr-recipes/

    【讨论】:

      【解决方案2】:

      它实际上与 SQL 无关。 R中的这个例子也不起作用:

      df <- data.frame(
           v1 = sample(5, 10, replace = TRUE),
           v2 = sample(5,10, replace = TRUE)
      )
      df %>% filter_(~ "v1" == 1)
      

      它不起作用,因为您需要将表达式 ~ v1 == 1 而不是表达式 ~ "v1" == 1 传递给 filter_

      要解决这个问题,只需使用引用运算符quo 和反引号运算符!!

      library(dplyr)
      which_column = quot(v1)
      df %>% filter(!!which_column == 1)
      

      【讨论】:

      • 嗨,马修,非常感谢您的回答。您提出的第一种方法解决了我的问题,谢谢!我确实阅读了 nse 小插图并且自己非常接近这个解决方案,但是我忘记了 as.name/as.symbol 调用。您建议的第二种方法在我正在编写的代码中不可行,因为 R 中还没有数据框,过滤器必须充当生成的 sql 查询中的 WHERE 子句,然后提取数据。这就是我在标题和问题文本中提及 SQL 的原因。再次感谢您的回答!
      • 您能否解释一下如果 1 也是另一个变量可以做什么?类似于 filter_criteria
      • filter_criteria
      【解决方案3】:

      这是一个稍微不那么冗长的解决方案,它使用提取函数的典型行为 '[' 按字符值选择列而不是将其转换为语言元素:

      df %>% filter(., '['(., which_column)==1 )
      
      set.seed(123)
      df <- data.frame(
            v1 = sample(5, 10, replace = TRUE),
            v2 = sample(5,10, replace = TRUE)
       )
      which_column <- "v1"
      df %>% filter(., '['(., which_column)==1)
      #  v1 v2
      #1  1  5
      

      【讨论】:

      • 这也有效:filter(df, '['(df, which_column) == 1)
      猜你喜欢
      • 1970-01-01
      • 2015-03-10
      • 1970-01-01
      • 2019-03-23
      • 2019-11-29
      • 1970-01-01
      • 1970-01-01
      • 2017-10-27
      • 1970-01-01
      相关资源
      最近更新 更多