Logicals

Logicals are a fundamental tool for using R in a sophisticated way. Logicals allow us to precisely select elements of an R object (e.g., a vector or dataframe) based upon criteria and to selectively perform operations.

R supports all of the typical mathematical comparison operators: Equal to:

1 == 2
## [1] FALSE

Note: Double equals == is a logical test. Single equals = means right-to-left assignment. Greater than:

1 > 2
## [1] FALSE

Greater than or equal to:

1 >= 2
## [1] FALSE

Less than:

1 < 2
## [1] TRUE

Less than or equal to:

1 <= 2
## [1] TRUE

Note: Less than or equal to <= looks like <-, which means right-to-left assignment.

Spacing between the numbers and operators is not important:

1 == 2
## [1] FALSE
1 == 2
## [1] FALSE

But, spacing between multiple operators is! The following:

# 1 > = 2

produces an error!

The results of these comparisons is a logical vector that has values TRUE, FALSE, or NA:

is.logical(TRUE)  #' valid logical
## [1] TRUE
is.logical(FALSE)  #' valid logical
## [1] TRUE
is.logical(NA)  #' valid logical
## [1] TRUE
is.logical(45)  #' invalid
## [1] FALSE
is.logical("hello")  #' invalid
## [1] FALSE

Because logicals only take values of TRUE or FALSE, values of 1 or 0 can be coerced to logical:

as.logical(0)
## [1] FALSE
as.logical(1)
## [1] TRUE
as.logical(c(0, 0, 1, 0, NA))
## [1] FALSE FALSE  TRUE FALSE    NA

And, conversely, logicals can be coerced back to integer using mathematical operators:

TRUE + TRUE + FALSE
## [1] 2
FALSE - TRUE
## [1] -1
FALSE + 5
## [1] 5

Logical comparisons can also be applied to vectors:

a <- 1:10
a > 5
##  [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE

This produces a logical vector. This is often useful for indexing:

a[a > 5]
## [1]  6  7  8  9 10

We can also apply multiple logical conditions using boolean operators (AND and OR):

a > 4 & a < 9
##  [1] FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE
a > 7 | a == 2
##  [1] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE

Complex conditions can also be combined with parentheses to build a logical:

(a > 5 & a < 8) | (a < 3)
##  [1]  TRUE  TRUE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE

There is also a xor function to enforce strict OR (but not AND) logic:

xor(TRUE, FALSE)
## [1] TRUE
xor(TRUE, TRUE)
## [1] FALSE
xor(FALSE, FALSE)
## [1] FALSE

This becomes helpful, for example, if we want to create a new vector based on values of an old vector:

b <- a
b[b > 5] <- 1
b
##  [1] 1 2 3 4 5 1 1 1 1 1

It is also possible to convert a logical vector into a positional vector using which:

a > 5
##  [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
which(a > 5)
## [1]  6  7  8  9 10

Of course, this is only helful in some contexts because:

a[a > 5]
## [1]  6  7  8  9 10
a[which(a > 5)]
## [1]  6  7  8  9 10

produce the same result.

We can also invert a logical (turn TRUE into FALSE, and vice versa) using the exclamaation point (!):

!TRUE
## [1] FALSE
!FALSE
## [1] TRUE
b == 3
##  [1] FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
!b == 3
##  [1]  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE

We can also use an if-else construction to define a new vector conditional on an old vector: For example, we could produce our b vector from above using the ifelse function:

ifelse(a > 5, 1, a)
##  [1] 1 2 3 4 5 1 1 1 1 1

This tests each element of a. If that elements meets the condition, it returns the next value (1), otherwise it returns the value of a. We could modify this slightly to instead return 2 rather than the original value when an element fails the condition:

ifelse(a > 5, 1, 2)
##  [1] 2 2 2 2 2 1 1 1 1 1

This gives us an indicator vector.

Set membership

An especially helpful logical comparator checks of a vector in another vector:

d <- 1:5
e <- 4:7
d %in% e
## [1] FALSE FALSE FALSE  TRUE  TRUE
e %in% d
## [1]  TRUE  TRUE FALSE FALSE

R has several other functions related to sets (e.g., union, intersection) but these produce numeric, not logical output.

Vectorization

Note: The ifelse function demonstrates an R feature called “vectorization.” This means that the function operates on each element in the vector rather than having to test each element separately. Many R functions rely on vectorization, which makes them easy to write and fast for the computer to execute.