Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
840 views
in Technique[技术] by (71.8m points)

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

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))
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
...