if_else() `false` must be type double, not integer - in R

泪湿孤枕 提交于 2019-12-30 17:49:14

问题


The end of a long string of dplyr pipes is

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

which gives this error

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

Which goes away if I do either of these two instead

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

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

I thought it'd be easiest to make a simple reproducible recreation so I did what you see below, but I can't get the error anymore. Any idea what's going on? Why does ifelse work where if_else doesn't, and why does if_else work if I change 3 to 3L? I understand L coerces 3 to be an integer, is that correct?

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:


if_else from dplyr is type-stable, meaning that it checks whether the "true" and "false" conditions are the same type. If they aren't, if_else throws an error. ifelse in Base R does not do that.

When writing:

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

I assume n was originally an integer type, so "false" would be of integer type, n-3 coerces "true" to a double, because 3 is double. "true" and "false" are of different types, so if_else throws an error.

When writing:

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

qty is likely already a double, so dividing a double by 2 (a double) still yields a double. "true" and "false" are the same type. Hence no error.

With that being said, this can easily be checked with the following typeofs:

> typeof(6)
[1] "double"

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

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

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

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

ifelse from Base R does implicit coercing, which converts everything to the same type. This means that it doesn't throw an error when "true" and "false" are of different types. This is both more convenient and dangerous as there might be unexpected results after implicit coercing.

I recommend using ifelse for one-off/adhoc programs, and if_else for when you want to take advantage of the built-in unit test.



来源:https://stackoverflow.com/questions/50708366/if-else-false-must-be-type-double-not-integer-in-r

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!