Подтвердить что ты не робот

Нестандартная оценка (NSE) в dplyr filter_ и извлечение данных из MySQL

Я хотел бы извлечь некоторые данные с сервера sql с помощью динамического фильтра. Я использую большой пакет R dplr следующим образом:

#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 ....

('знак в имени столбца)

Есть ли у кого-нибудь предложения о том, как сформулировать условие фильтрации, чтобы заставить его работать?

4b9b3361

Ответ 1

Это не связано с SQL. Этот пример в R тоже не работает:

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

Это не работает, потому что вам нужно передать filter_ выражение ~ v1 == 1 - не выражение ~ "v1" == 1.

версия dplyr >= 0,6

Чтобы решить проблему, просто используйте оператор цитирования quo и оператор декатирования !!

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

версия dplyr < 0.6

Чтобы решить проблему, используйте функцию interp из пакета lazyeval.

library(lazyeval)
filter_criteria <- interp(~ which_column == 1, which_column = as.name("v1"))
df %>% filter_(filter_criteria)

Ответ 2

Альтернативное решение с dplyr версией 0.5.0 (возможно, реализовано ранее), можно передать сгенерированную строку как аргумент .dots, который я считаю более читаемым, чем lazyeval:: interp solution:

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

UPDATE для 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 - строковая переменная.)

Ответ 3

Здесь несколько менее подробное решение и одно, которое использует типичное поведение функции extract, '[' при выборе столбца по значению символа, а не преобразовании его в элемент языка:

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