CoursesR Basics

Logical Vectors and Comparison

Lesson 6 of 8 · 12 min

Comparisons produce logical vectors

The operators >, <, >=, <=, == and != compare, and like arithmetic they are vectorised: a comparison between a vector and a number returns one TRUE or FALSE per element. The result is a third kind of vector, logical, alongside numeric and character.

temps <- c(21.5, 23.1, 19.8, 24.6, 22.0, 20.3, 25.2)
temps > 22
#> [1] FALSE  TRUE FALSE  TRUE FALSE FALSE  TRUE
class(temps > 22)
#> [1] "logical"
sum(temps > 22)
#> [1] 3
mean(temps > 22)
#> [1] 0.4285714

The last two lines use a property that makes logical vectors so useful: in arithmetic, TRUE counts as 1 and FALSE as 0. So sum() of a comparison counts how many elements satisfy it, and mean() gives the proportion. Three of seven days were above 22 degrees, 42.9 percent.

Filtering with a logical vector

Put a logical vector inside the square brackets and R keeps the elements where it is TRUE. This is the second way of indexing, next to positions, and it is the one you will use most, because it expresses a question rather than a location. which() converts a logical vector back to positions when you need to know where the matches are. Both forms select the same elements. The logical form also works on the left of an assignment: temps[temps > 25] <- 25 caps every value above 25 in one line, using the same write-into-the-vector mechanism as positional indexing.

temps[temps > 22]
#> [1] 23.1 24.6 25.2
which(temps > 22)
#> [1] 2 4 7

Combining conditions

& is and, | is or, and ! negates. All three work element by element. any() and all() reduce a logical vector to a single answer.

temps >= 20 & temps <= 23
#> [1]  TRUE FALSE FALSE FALSE  TRUE  TRUE FALSE
temps < 20 | temps > 25
#> [1] FALSE FALSE  TRUE FALSE FALSE FALSE  TRUE
!(temps > 22)
#> [1]  TRUE FALSE  TRUE FALSE  TRUE  TRUE FALSE
any(temps > 25)
#> [1] TRUE
all(temps > 19)
#> [1] TRUE

Comparing text and testing membership

== works on character vectors as well, and the comparison is exact, including case. A logical vector built from one vector can index another of the same length, which is how you select the temperature of a particular day. To test against several values at once, %in% is far cleaner than a chain of |.

day <- c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
day == "Tue"
#> [1] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE
temps[day == "Tue"]
#> [1] 23.1
day %in% c("Sat", "Sun")
#> [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE
temps[day %in% c("Sat", "Sun")]
#> [1] 20.3 25.2

Two traps: = versus ==, and decimals

A single = is assignment, like <-. Writing x = 5 when you meant to test equality silently overwrites x. Equality is always the double sign. The second trap is subtler: computers store decimals in binary, and many decimal fractions have no exact binary form, so arithmetic results can differ from the expected value by a hair. Testing them with == then fails. all.equal() compares with a small tolerance and is the right tool for computed decimals.

0.1 + 0.2 == 0.3
#> [1] FALSE
isTRUE(all.equal(0.1 + 0.2, 0.3))
#> [1] TRUE
💡 Use == on integers, text and logical values. For measured or computed decimals, ask for a range such as x > 21.9 & x < 22.1, or use all.equal().
Knowledge check
With x <- c(3, 8, 1, 9), what does sum(x > 2) return?

Sign in to answer and track your progress.

Sign in