Как использовать переменную в dplyr:: filter?

У меня есть переменная с тем же именем, что и столбец в dataframe:

df <- data.frame(a=c(1,2,3), b=c(4,5,6))
b <- 5

Я хочу получить строки, где df$b == b, но dplyr интерпретирует это как df$b == df$b:

df %>% filter(b == b) # interpreted as df$b == df$b
#   a b
# 1 1 4
# 2 2 5
# 3 3 6

Если я изменяю имя переменной, она работает:

B <- 5
df %>% filter(b == B) # interpreted as df$b == B
#   a b
# 1 2 5

Мне интересно, есть ли лучший способ сказать filter, что b относится к внешней переменной.

Ответ 1

Вы можете использовать функцию get для извлечения значения переменной из среды.

df %>% filter(b == get("b")) # Note the "" around b

Ответ 2

В качестве общего решения вы можете использовать версию SE (стандартная оценка) filter, которая равна filter_. В этом случае все становится немного запутанным, потому что вы смешиваете переменную и "внешнюю" константу в одном выражении. Вот как вы это делаете с помощью функции interp:

library(lazyeval)
df %>% filter_(interp(~ b == x, x = b))

Если вы хотите использовать больше значений в b, вы можете написать:

df %>% filter_(interp(~ b == x, .values = list(x = b)))

Ответ 3

Недавно я нашел, что это изящное решение этой проблемы, хотя я только начинаю обнимать ее, как это работает.

df %>% filter(b == !!b)

который является синтаксическим сахаром для

df %>% filter(b == UQ(b))

Мой высокий уровень этого заключается в том, что операция UQ (без кавычек) приводит к тому, что ее содержимое оценивается до операции фильтра, поэтому оно не оценивается внутри data.frame.

Это описано в article в разделе 'quasi-quotation'. Я хотел бы отметить, что эта статья также включает несколько решений аналогичных проблем, связанных с NSE.

Одно предостережение выше - я склонен положить !! в конце моих выражений, как указано выше. Если вы поместите это в начале:

df %>% filter(!!b == b)

то он будет оцениваться как df %>% filter(!!(b == b))

что эквивалентно записи df %>% filter(5 == 5):

> quo(filter(df, !!b == b))
<quosure: global>
~filter(df, TRUE) 

В приведенной выше опции UQ() этой проблемы нет.