With if_else()
we can classify the elements of a
vector
<- c(1, 2, 2, 3)) (x
## [1] 1 2 2 3
by testing a condition on each one of them.
== 1 x
## [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,
<- c(x, NA)) (xNA
## [1] 1 2 2 3 NA
== 1 xNA
## [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.
<- c(1, 8, 9)) (y
## [1] 1 8 9
%in% y xNA
## [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.
<- c("first_is_1", "second_is_1", "third_is_1", "fourth_is_1")
rank_1 <- c("first_is_not1", "second_is_not1", "third_is_not1", "fourth_is_not1")
rank_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.
<- c("Austria", "Belgium", "Channel Islands", "Cyprus", "Denmark", "EIRE", "Finland", "France", "Germany",
EU "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))