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
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"
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
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.
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")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")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))