- fundamentals

With if_else() we can classify the elements of a vector

(x <- c(1, 2, 2, 3))
## [1] 1 2 2 3

by testing a condition on each one of them.

x == 1
## [1]  TRUE FALSE FALSE FALSE

The first argument is the test, then we need to input the classes that satisfy the TRUE and FALSE outputs.

if_else(x == 1, "1", "not1")
## [1] "1"    "not1" "not1" "not1"

The type of these two classes must be the same.

if_else(x == 1, 1, "not1")
## Error in `if_else()`:
## ! Can't combine `true` <double> and `false` <character>.

If an element of the vector doesn’t satisfy neither class,

(xNA <- c(x, NA))
## [1]  1  2  2  3 NA
xNA == 1
## [1]  TRUE FALSE FALSE FALSE    NA

the function returns NA.

if_else(xNA == 1, "1", "not1")
## [1] "1"    "not1" "not1" "not1" NA

- missing

We can change that with the missing argument, whose value must be of the same type of the other two classes.

if_else(xNA == 1, "1", "not1", missing = "other")
## [1] "1"     "not1"  "not1"  "not1"  "other"

It is important to pay attention to NAs, as they can be evaluated to one of the two classes.

(y <- c(1, 8, 9))
## [1] 1 8 9
xNA %in% y
## [1]  TRUE FALSE FALSE FALSE FALSE
if_else(xNA %in% y, TRUE, FALSE)
## [1]  TRUE FALSE FALSE FALSE FALSE

If we want to keep them as they are we can nest two if_else()s and use is.na().

if_else(is.na(xNA), NA, 
        if_else(xNA %in% y, TRUE, FALSE))
## [1]  TRUE FALSE FALSE FALSE    NA

Even when nested, the classes must be of the same type.

if_else(is.na(xNA), TRUE, 
        if_else(xNA %in% y, "Yes", "No"))
## Error in `if_else()`:
## ! Can't combine `true` <logical> and `false` <character>.

The classes can be of the same length of the output of the test, not solely of length 1.

rank_1 <- c("first_is_1", "second_is_1", "third_is_1", "fourth_is_1")
rank_not1 <- c("first_is_not1", "second_is_not1", "third_is_not1", "fourth_is_not1")
if_else(x == 1, rank_1, rank_not1)
## [1] "first_is_1"     "second_is_not1" "third_is_not1"  "fourth_is_not1"

- ptype

With the ptype argument we can change the type of the output.

if_else(x == 1, TRUE, FALSE, ptype = integer())
## [1] 1 0 0 0

- size

And with the size one its length, but I don’t understand how it is supposed to function.

if_else(x == 1, TRUE, FALSE, size = 2)
## Error in `if_else()`:
## ! `condition` must have size 2, not size 4.
if_else(x == 1, TRUE, FALSE, size = 8)
## Error in `if_else()`:
## ! `condition` must have size 8, not size 4.
if_else(x[1] == 1, TRUE, FALSE, size = 4)
## Error in `if_else()`:
## ! `condition` must have size 4, not size 1.

- usage with a data frame

With a data frame, if_else() is useful to create new columns.

EU <-  c("Austria", "Belgium", "Channel Islands", "Cyprus", "Denmark", "EIRE", "Finland", "France", "Germany", 
         "Greece", "Iceland", "Italy", "Lithuania", "Malta", "Netherlands", "Norway", "Poland", "Portugal", 
         "Spain", "Sweden", "Switzerland")
df %>%
  mutate(in_EU = if_else(Country %in% EU, TRUE, FALSE), .keep = "used")
A tibble: 525461 x 2

It is important that the output of if_else() is either of length 1 or of the same size as the number of rows of the data frame, otherwise we would get an error.

df %>%
  mutate(is_EU = if_else(EU %in% Country, TRUE, FALSE))
Error in `mutate()`:
ℹ In argument: `is_EU = if_else(EU %in% Country, TRUE, FALSE)`.
Caused by error:
! `is_EU` must be size 525461 or 1, not 21.

The test can be specified with expressions.

df %>%
  mutate(High_Rank_Price = if_else(min_rank(Price) < 4, TRUE, FALSE), .keep = "used")
A tibble: 525461 x 2

- with group_by()

When the data frame is grouped the tests are performed group-wise, so with specific ones the output may vary between groups.

For instance a Price of 4.25 is in the following example labeled as “Expensive” for Germany (row 32) but not for United Kingdom.

df %>%
  group_by(Country) %>%
  mutate(Local_Avg_Price = mean(Price),
         Exp_Item = if_else(Price > mean(Price), "Expensive", "Not Expensive"), .keep = "used") %>%
  filter(between(Price, 4.189418, 4.543470))
A tibble: 20476 x 4
Groups: Country [35]