Неожиданное поведение с dplyr :: filter () - PullRequest
4 голосов
/ 10 апреля 2019

спасибо за ваше время.

Это, вероятно, очевидная проблема, которую я упускаю из виду, но сегодня утром я столкнулся с неожиданным поведением, используя dplyr::filter().

Использование filter() работает, за исключением случаев, когда имя столбца и имя объекта эквивалентны. Подробности см. В приведенном ниже примере.

Я ожидаю, что data вернет только те строки, где data$year соответствует year или data$month соответствует month, но вместо этого он возвращает все значения.

Я уже проделывал эту операцию много раз, поэтому я не уверен, почему она происходит в этот раз.

При переименовании month в month_by_a_different_name все работает как положено. Есть идеи? Спасибо за ваше время.

library(tidyverse)

# Example data
data <-
  tibble(
    year = c(2019, 2018, 2017),
    month = c("January", "February", "March"),
    value = c(1, 2, 3)
  )


# -----------------------------------------------

# Values to filter by
year <- 2019
month <-  "February"

# Assigning year and month to a different object name
year_by_a_different_name <- year
month_by_a_different_name <- month


# -----------------------------------------------

# Filtering using year and month doesn't work
data %>%
  dplyr::filter(year == year)        # Doesn't work

data %>%
  dplyr::filter(month == month)      # Doesn't work


# -----------------------------------------------

# Filtering using different names works
data %>%
  filter(year == year_by_a_different_name)       # Works

data %>% 
  filter(month == month_by_a_different_name)     # Works


# -----------------------------------------------

# Using str_detect() also doesn't work for month
data %>% 
  dplyr::filter(str_detect(month, month))


# -----------------------------------------------

# Works with base R
data[data$month == month, ]
data[data$year == year, ]


# -----------------------------------------------

# Objects are of same class
class(data$year) == class(year)      # TRUE
class(data$month) == class(month)    # TRUE

Ответы [ 2 ]

4 голосов
/ 10 апреля 2019

TLDR: используйте filter(year == !!year)

Это вызвано нестандартной оценкой dplyr (NSE) - неоднозначно, ссылаетесь ли вы на df$year или на свою внешнюю переменную year.NSE использует так называемые «предложения», чтобы сделать вывод, что когда вы пишете year на LHS, вы ссылаетесь на столбец столбца конвейерного ввода.Этот трюк с кавычками позволяет вам обращаться к именам, определенным в области конвейерного ввода (т. Е. Столбцы фрейма данных) в семействе пакетов tidyverse, и делает вашу жизнь намного проще, (i) избегая необходимости вводить кавычки.помечается везде и (ii) позволяет Rstudio выдавать вам предложения по автозаполнению.

Однако в данном случае year в RHS означает что-то вне входных данных. даже еслиимя также используется там.В этом случае оператор !! ("bangbang") сообщает NSE, что ваша переменная не должна заключаться в кавычки, а должна оцениваться как есть.

Более подробную информацию можно найти здесь: https://dplyr.tidyverse.org/articles/programming.html, особеннораздел «Разные выражения».Из приведенной выше виньетки:

В dplyr (и в tidyeval в целом) вы используете !!чтобы сказать, что вы хотите снять кавычки, чтобы они оценивались, а не заключались в кавычки.Это дает нам функцию, которая фактически делает то, что мы хотим.

3 голосов
/ 10 апреля 2019

Чтобы оценить выражение в его исходной среде, вы можете знать, где оно определено, как показано ниже, что совсем не красиво.

data %>%
  dplyr::filter(year == !!.GlobalEnv$year)

Или вы можете использовать enquo.

data %>%
  dplyr::filter(month == !!enquo(month))

со страницы справки help('enquo').

Захват выражений в выражениях

quo() и enquo() аналогичны их expr аналогам, но захватывают и выражение и его окружение в объекте, называемом quosure. Эта оболочка содержит ссылку на исходную среду, в которой это выражение было захвачено. Отслеживание окружающей среды выражения важны, потому что это где функции и объекты упомянутые в выражении определены.

Quosures - это объекты, которые можно оценивать с помощью eval_tidy() так же, как символы или вызовы функций. Так как они всегда оценивают в своих В оригинальной среде, каверсы можно рассматривать как транспортные средства, которые позволяют выражения для перехода от функции к функции, но этот луч назад сразу же после оценки.

...