dplyr的filter_中的非标准评估(NSE)和从MySQL中提取数据

Lor*_*ssi 31 r lazy-evaluation dplyr

我想从带有动态过滤器的sql server中提取一些数据.我正在以下列方式使用伟大的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
Run Code Online (Sandbox Code Playgroud)

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

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

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

不幸的是,这种方法没有给出预期的结果.实际上它没有给出任何错误,但是甚至没有将任何结果拉入R.特别是,我看了两个代码生成的SQL查询,并且有一个重要的区别.

第一个工作代码生成表单的查询:

SELECT ... FROM ... WHERE 
`column1` IN ....
Run Code Online (Sandbox Code Playgroud)

(`登录列名),第二个生成表单的查询:

SELECT ... FROM ... WHERE 
'column1' IN ....
Run Code Online (Sandbox Code Playgroud)

('登录列名)

有没有人对如何制定过滤条件以使其有效有任何建议?

Mat*_*hew 42

它与SQL无关.R中的这个例子也不起作用:

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

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

要解决此问题,只需使用引用运算符quo和dequoting运算符!!

library(dplyr)
which_column = quot(v1)
df %>% filter(!!which_column == 1)
Run Code Online (Sandbox Code Playgroud)


LmW*_*mW. 7

使用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
Run Code Online (Sandbox Code Playgroud)

更新 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)
Run Code Online (Sandbox Code Playgroud)

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

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


42-*_*42- 5

这是一个稍微简洁的解决方案,它使用提取函数的典型行为,'['在逐个字符值中选择而不是将其转换为语言元素:

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
Run Code Online (Sandbox Code Playgroud)