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.2Two 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
== 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().x <- c(3, 8, 1, 9), what does sum(x > 2) return?Sign in to answer and track your progress.
Sign in