Logical operators: AND acting liking OR

Viewed 291

I'm having a hard time understand how R is treating the AND and OR operators when I'm using filter from dplyr.

Here's an example to illustrate:

library(dplyr)
xy <- data.frame(x=1:6, y=c("a", "b"), z= c(rep("d",3), rep("g",3)))

> xy
  x y z
1 1 a d
2 2 b d
3 3 a d
4 4 b g
5 5 a g
6 6 b g

Using filter I want to eliminate all rows where x==1 and z==d. This would lead me to believe I want to use the AND operator: &

> filter(xy, x != 1 & z != "d")
  x y z
1 4 b g
2 5 a g
3 6 b g

But this removes all rows that have either x==1 or z==d. What's more confusing, is that when I use the OR operator, | I get the desired result:

> filter(xy, x != 1 | z != "d")
  x y z
1 2 b d
2 3 a d
3 4 b g
4 5 a g
5 6 b g

Also, this does work, however not as desirable for if I were stringing together == and != in the same conditional evaluation.

> filter(xy, !(x == 1 & z == "d"))
  x y z
1 2 b d
2 3 a d
3 4 b g
4 5 a g
5 6 b g

Can someone explain what I'm missing?

4 Answers

This is a question of boolean algebra. The logical expression !(x == 1 & z == d) is equivalent to x != 1 | z != d, just the same as -(x + y) is equivalent to -x - y. Eliminating the bracket, you change all == to != and all & to | and vice versa. This leads to the fact that

!(x == 1 & z == "d")

is NOT the same as

x != 1 & z != "d"

but rather

x != 1 | z != "d"

A couple tips that won't fit in a comment:

  1. If you're having trouble understanding how something is working in R, I'd highly recommend running each individual piece of the operation. With dplyr, it's easy to keep track on intermediate steps and display them all:

    mutate(xy,
             A = x != 1,
             B = z != 'd',
             A_and_B = A & B,
             A_or_B = A | B
             )
    #   x y z     A     B A_and_B A_or_B
    # 1 1 a d FALSE FALSE   FALSE  FALSE
    # 2 2 b d  TRUE FALSE   FALSE   TRUE
    # 3 3 a d  TRUE FALSE   FALSE   TRUE
    # 4 4 b g  TRUE  TRUE    TRUE   TRUE
    # 5 5 a g  TRUE  TRUE    TRUE   TRUE
    # 6 6 b g  TRUE  TRUE    TRUE   TRUE
    

    I think that if you look at the definition of each column its values will make perfect sense. Then, after going one step at a time, hopefully the results will make sense too.

  2. As others have stated in various ways, you're setting yourself up for a hard time from the start with

    Using filter I want to eliminate all rows where x==1 and z==d

    Don't think of filter as eliminating rows, think of it as keeping rows. If you mentally invert your goal to "keep all rows where..." you'll set yourself up for a more direct translation of words to code.

The result of filter is the rows where the specified condition is true.

Take for example x != 1 & z != "d". What are the rows where this condition is true? The output you got. The other rows were removed, because the condition was not true for those rows.

In this example, your real intention was to eliminate rows where x == 1 and z == "d". In other words, you want to keep the rows where the condition x == 1 and z == "d" is false. Putting that into code becomes filter(xy, !(x == 1 and z == "d")). It's ironic that this looks much like your intention, and very different from what you actually tried to write.

If you forget this logic of filter, you can remind yourself with a simpler experiment, filter(xy, TRUE) which will return all rows, and filter(xy, FALSE) which will return none.

# x != 1 & z != "d" evaluates to a single TRUE/FALSE vector which subsets the data

# note how & and | behave in isolation:
TRUE & TRUE  # T AND T = T
## [1] TRUE
TRUE & FALSE # T AND F = F
## [1] FALSE
FALSE & FALSE # F AND F = F
## [1] FALSE
TRUE | TRUE   # T OR T = T
## [1] TRUE
TRUE | FALSE  # T OR F = T
## [1] TRUE
FALSE | FALSE # F OR F = F
## [1] FALSE
# Apply over vectors

(x1 <- xy$x != 1)
## [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
(z1 <- xy$z != "d")
## [1] FALSE FALSE FALSE  TRUE  TRUE  TRUE
x1 & z1  # you get last 3 rows
## [1] FALSE FALSE FALSE  TRUE  TRUE  TRUE
x1 | z1 # you get all but 1st row (which contains 1 and d)
## [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
Related