Chapter 8 If Statements
If statements are a type of control flow structure. Control structures help us control how many times code is executed, and when it will be executed. This is helpful because sometime we only want our program to run if certain conditions are met.
8.1 If
In R we can also execute commands only if certain conditions are met using the if
operator. This feature in R checks a logical value (<value>
) and if it is TRUE
then a sequence of commands within {}
will be ran. If <value>
is FALSE
, then the commands inside of {}
will not be ran.
Below we have an example. The code will only be executed if x
is a positive number.
## [1] "positive"
In the example above we have a relational operator which returns a logical value. This logical value was equal to TRUE
so the code was executed.
8.2 If Else
We can pair an if
statement with an else
value. After the else
object we can define another sequence of commands inside of {}
. The else
value is paired with the immediate previous if
statement. If this if
statement is FALSE
then the else
code will run. If the if
statement is TRUE
then the else
code will not be executed.
## [1] "number"
8.3 Else If
Sometimes we will want to do a sequence of checks that are all related, and we will only want code to run if the previous if
statements were FALSE
and another criteria is TRUE
. We can use else if
to implement these rules.
x = -3
if (x > 0) {
type = "positive"
} else if (x < 0) {
type = "negative"
} else if (x == 0) {
type = "zero"
} else {
type = "Error"
}
type
## [1] "negative"
The command for the if
statement will only run if x>0
, and the rest of the code will not be implemented.
The first else if
commands will only execute if the first if
statement was FALSE
and x<0
.
The second else if
commands will only execute if the previous else if
and if
statements were FALSE
and x==0
.
If the previous if
statement and all previous else if
statements are FALSE
then the else
code will be executed.
Here is another example with an if else
chain.
Toyfun <- function(X, Y, Do) {
if (Do == "Add") {
Z = X + Y
} else if (Do == "Subtract") {
Z = X - Y
} else if (Do == "Multiply") {
Z = X * Y
} else if (Do == "Penguin") {
Z = c("<('' )")
} else {
Z = c(X, Y)
}
return(Z)
}
Toyfun(2, 4, "Add")
## [1] 6
## [1] -2
## [1] "<('' )"
## [1] 2 4
8.4 Nested If Chains
We can make if-else
chains nested within each other.
x <- 105
if (x > 0) {
if (x > 100) {
type = "large positive number"
} else {
type = "positive number"
}
} else if (x < 0) {
type = "negative number"
} else if (x == 0) {
type = "zero"
} else {
type = "Error"
}
type
## [1] "large positive number"
8.5 Ifelse
One of the critical things about if-statements is that they require that we use only ONE TRUE\FALSE
value inside the condition that is checked. For example, consider the following:
## Warning in if (x > 0) {: the condition has length > 1 and only the first
## element will be used
## [1] "non-negative"
When we run the above line of code we obtain a “Warning” message. Recall that warning messages are given when R compiled an expression, but the program suspects that the result was not the user wanted. A “Error” message is when the expression could not be compiled. In this case the expression x>0
produces a vector of logical values that has length greater than 1, when the condition for an if-statement is expecting a logical vector of length 1. If-statements are one of the few things in base R that are not automatically vectorized.
In R we are used to vectorized functions and operations. We say that a function or operation is vectorized when we can use the function or operation to every element in a vector in an efficient way. We saw a few examples of vectorized operations already in 2.2.2. Below we have an example of using a vectorized approach with a function, and non-vectorized approach.
## [1] 0.0000000 0.6931472 1.0986123
## [1] 0.0000000 0.6931472 1.0986123
In the the second call the function log()
is efficiently applied to each element of the vector that is used as the input. The vectorized approach is efficiently computationally, and it is also efficient in typing. For much larger vectors it would be (human) time consuming to apply the log function to each element.
When we want to do a vectorized approach for if-statements we generally have two options. The first, and simplest, option is the ifelse()
function. The first argument of this function is a logical value, the second and third arguments are what to do if the value is TRUE
or FALSE
, respectively. Be sure to check out the help file for this function!
## [1] "non-positive" "non-positive" "non-positive" "non-positive" "positive"
## [6] "positive" "positive"
Here is another example that we can use to find all cars in the mtcars
data set that have a high horsepower and are fuel efficient, i.e. cars have mpg > 25
and hp > 60
.
fast_efficient <- ifelse(mtcars$mpg > 25 & mtcars$hp > 60, TRUE,
FALSE)
sum(fast_efficient)/length(fast_efficient)
## [1] 0.15625