if_else () `false` должен иметь тип double, а не integer - в R - PullRequest
0 голосов
/ 05 июня 2018

Конец длинной строки труб dplyr равен

mutate(n = if_else(FiscalYear == "FY2018" & Candy == "SNICKERS", n - 3, n))

, что дает эту ошибку

Error in mutate_impl(.data, dots) : Evaluation error: `false` must be type double, not integer.

, которая исчезнет, ​​если я выполню любой из этихвместо двух

mutate(n = ifelse(FiscalYear == "FY2018" & Candy == "SNICKERS", n - 3, n))

mutate(n = if_else(FiscalYear == "FY2018" & Candy == "SNICKERS", n - 3L, n))

Я подумал, что будет проще сделать простой воспроизводимый отдых, поэтому я сделал то, что вы видите ниже, но я могубольше не получаю ошибку.Есть идеи, что происходит? Почему ifelse работает там, где if_else не работает, и почему if_else работает, если я изменяю 3 на 3L? Я понимаю, L принуждает 3 бытьцелое число, это правильно?

library(tidyverse)
df <- tribble(
  ~name, ~fruit, ~qty,
  "Bob", "apple", 10,
  "Bill", "apple", 10
)

# THIS WORKS AGAIN AS IT SHOULD
df %>% mutate(qty = ifelse(name == "Bob" & fruit == "apple", qty / 2, qty))

# BUT IF_ELSE DOESN'T FAIL THIS TIME, WEIRD
df %>% mutate(qty = if_else(name == "Bob" & fruit == "apple", qty / 2, qty))

1 Ответ

0 голосов
/ 05 июня 2018

if_else из dplyr является типоустойчивым, что означает, что он проверяет, являются ли условия «истина» и «ложь» одним и тем же типом.Если это не так, if_else выдает ошибку.ifelse в Base R этого не делает.

При записи:

mutate(n = if_else(FiscalYear == "FY2018" & Candy == "SNICKERS", n - 3, n))

Я предполагаю, что n изначально был целочисленным типом, поэтому "false" было бы целочисленным типом,n-3 принуждает "true" к двойному, потому что 3 является двойным.«true» и «false» относятся к разным типам, поэтому if_else выдает ошибку.

При записи:

mutate(qty = if_else(name == "Bob" & fruit == "apple", qty / 2, qty))

qty, вероятно, уже является двойным, поэтому делениеудвоение на 2 (удвоение) по-прежнему приводит к удвоению.«true» и «false» относятся к одному типу.Следовательно, нет ошибки.

С учетом вышесказанного это легко проверить с помощью следующих typeof s:

> typeof(6)
[1] "double"

> typeof(6L)
[1] "integer"

> typeof(6L-3)
[1] "double"

> typeof(6L-3L)
[1] "integer"

> typeof(6/2)
[1] "double"

ifelse из Base R выполняет неявное приведение в действие, которое преобразует всек тому же типу.Это означает, что он не выдает ошибку, когда «истина» и «ложь» имеют разные типы.Это и более удобно, и опасно, поскольку после неявного принуждения могут быть непредвиденные результаты.

Я рекомендую использовать ifelse для одноразовых / специальных программ и if_else, если вы хотите воспользоваться преимуществамивстроенный модульный тест.

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