Почему «нейтральные» круглые скобки вызывают ошибки в R (или, может быть, в обратном направлении)? - PullRequest
3 голосов
/ 12 июня 2019

Когда у меня большие сложные куски кода, я часто использую больше наборов скобок, чем требуется.Мой код может выглядеть так:

library(tidyverse)
mtcars %>% 
  mutate(name = rownames(.)) %>% 
  filter((cyl == 4 & grepl("Toyota", name)) | 
           ((cyl == 6 | cyl == 8), grepl("Mazda", name)))

вместо этого:

mtcars %>% 
  mutate(name = rownames(.)) %>% 
  filter(cyl == 4 & grepl("Toyota", name) | 
           (cyl == 6 | cyl == 8, grepl("Mazda", name)))

Что я могу сказать?В моей голове защита от скобок помогает мне легче увидеть законы Де Моргана, проще PEMDAS, порядок вычислений и т. Д.

Такое либеральное использование скобок представляет проблему.Даже если я думаю, что дополнительные круглые скобки должны быть нейтральными в R и Tidyverse, они, кажется, не являются.Посмотрите на ошибку, которую я получаю в фрагменте кода ниже.

mtcars %>% filter((cyl == 4 & am == 1)) %>% .[1, 3]
# [1] 108
mtcars %>% filter((cyl == 4, am == 1)) %>% .[1, 3]
# Error: unexpected ',' in "mtcars %>% filter((cyl == 4,"

Почему первый пример работает непосредственно над, а второй выдает ошибку?Я знаю, что прямой ответ «вы используете слишком много скобок», но почему я не могу?Для меня это просто облегчает жизнь в этих кошмарных гнездах логического оператора.Мне известна функция case_when(), которая помогает в подобных ситуациях.Я все еще хочу знать, почему я не могу использовать дополнительные скобки, хотя.Спасибо.

Ответы [ 2 ]

5 голосов
/ 12 июня 2019

Проблема здесь в том, что вы используете «особенность» фильтра, когда условия, переданные в ... и разделенные запятыми, «автоматически» соединяются с &. Но магия синтаксического анализа, которая делает эту работу, недостаточно умна, чтобы видеть сквозь один набор символов.

Таким образом, он видит только одно условие, cyl == 4, am == 1, которое на самом деле не является синтаксически допустимым как одно булево выражение. Это одна из причин, почему мне не нравится эта функция, и я всегда пишу &.

Я подозреваю, что, поскольку эта функция filter довольно сложна в реализации, нет смысла пытаться заставить ее анализировать условия более рекурсивным способом. Возможно, неудовлетворительный ответ заключается в том, что проходящие условия, разделенные запятыми, хороши, если вы делаете что-то очень простое, но если ваше логическое условие сложно, вы должны быть более явными.

2 голосов
/ 13 июня 2019

То, что прокомментировал MrFlick, является основной причиной вашей проблемы, но в вашем примере все еще есть некоторое несоответствие.Мы можем использовать пакет rlang, чтобы увидеть, что dplyr делает с вашим вводом, что, кстати, на самом деле не волшебно, а просто использует стандартные функции R для нестандартной оценки (R все-таки должен анализировать ваш код).

Сначала выражение, которое было дано filter без лишних скобок:

library(rlang)

exprs(cyl == 4 & grepl("Toyota", name) | 
        (cyl == 6 | cyl == 8), grepl("Mazda", name))
[[1]]
cyl == 4 & grepl("Toyota", name) | (cyl == 6 | cyl == 8)

[[2]]
grepl("Mazda", name)

Так что после объединения всего с & вы получите выражение, которое хотите, но чтоважно отметить, что вы получаете 2 выражения, потому что их разделяет запятая, и filter будет анализировать каждое отдельно, используя стандартные правила R.Вы можете написать это выражение для ясности:

exprs(cyl == 4 & grepl("Toyota", name) | (cyl == 6 | cyl == 8), 
      grepl("Mazda", name))

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

cyl == 4 & grepl("Toyota", name) | (cyl == 6 | cyl == 8), grepl("Mazda", name)

Что, как сказал MrFlick, недопустимо в R.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...