# 2.1.3 Logical Expressions {#chap:LogOp}

## Learning Objectives
By the end of this section, you should understand how to

- Ask specific YES/NO questions of your data, and
- Combine multiple questions in different ways.

Logical expressions allow us to ask specific questions about our data and are a central component of data analysis. They are composed of _relational_ and _logical operators_.

## Relational Operators

Relational operators always ask "yes/no" questions. In place of yes and no, R uses either `TRUE/FALSE`, `T/F`, or `1/0` to provide a positive or negative answer. The most common _relational operators_ are listed in table \@ref(tab:RelOp):

Table: (\#tab:RelOp) A summary of relational operators in R.

| Operator    | Description                      |
|-------------|----------------------------------|
| `<`  | Less than                               |
| `<=` | Less than or equal to                   |
| `>`  | Greater than                            |
| `>=` | Greater than or equal to                |
| `==` | Exactly equal to                        |
| `!=` | Not equal to, i.e. the opposite of `==` |
| `!x` | Not x (logical negation)                |

As an example, we can apply some logical tests to `n` and `p`.

```{r}

n # What is n?
p # What is p?
n > p # Is n greater than p? TRUE
n %% 2 == 0 # Is n even? TRUE
n %% 2 != 0 # Is n odd? FALSE
```


As we've already seen, an important feature is that we can replace an object with an updated version of itself. Be very careful here! If you accidentally change the value of an object, all the following calculations will be affected.


```{r}

n # What is n?
n == p # Is n equal to p?
n <- p # Assign the value of p to n
n # What is the new value of n?
n == p # Is n equal to p?
n <- n+1
n # What is the new n?
n == p # Is n equal to p?
```

## Logical Operators

A collection of logical expressions can be combined using the following _logical operators_.

Table \@ref(tab:LogOp) The most common logical operators. `x \%in\% y` is not a logical operator _per se_, but it is convenient to introduce it at this point. You'll understand why when we see it in action.

Table: (\#tab:LogOp) A summary of logical operators in R. `x` and `y` are logical vectores, e.g. the output from _relational operators_. `a` and `b` are vectors, typcially type `character`.

| Operator            | Description               |
|---------------------|---------------------------|
| `x | y`    | x OR y                    |
| `x & y`    | x AND y                   |
| `b %in% a` | Find each element `a` in `b`. |

## Using logical expressions on different atomic vector types

Enter logical expressions into `filter()` to select values corresponding to `TRUE`. This could be a logical vector, or a logical expression containing a relational operator, which will result in a logical vector^[Remember, anytime we use a relational operator, we'll get a logical vector as output.]^[You will also see that `subset()` Can be used in a similar fashion. Belongs to base package and has fallen out of use.].

```{r}
foo_df %>% 
  filter(healthy == TRUE)

foo_df %>% 
  filter(healthy == TRUE)

foo_df %>% 
  filter(healthy)

```

^[This example already gives us a preview of how we can extract specific pieces of information from a data-set using \emph{relational operators}. This topic will be explored further with \emph{indexing} and \emph{regular expressions}.]

```{r}
# only those observations with
# low-quantity:
foo_df %>% 
  filter(quantity < 10)

# a middle quantity (10-20):
foo_df %>% 
  filter(quantity >= 10 & quantity <= 20)

# Alternatively:
foo_df %>% 
  filter(quantity >= 10 & quantity <= 20)

# all values:
foo_df %>% 
  filter(quantity >= 10 | quantity <= 20)

# tail values:
foo_df %>% 
  filter(quantity < 10 | quantity > 20)

# Impossible
foo_df %>% 
  filter(quantity < 10 & quantity > 20)

```


```{r}
# Heart values -  simple, only 1 value
foo_df %>% 
  filter(tissue == "Heart")

```

So what happens when we have 2 (or many) values we want to search?

```{r}
# Heart and Liver - cheap way
foo_df %>% 
  filter(tissue == "Heart" | tissue == "Liver")

```

You can probably appreciate that when you only have two queries, that is OK, but what happens when you have many? Maybe they are stored in a vector, perhaps the result from sub-setting another data frame. You may be tempted to do the following:

```{r}
# Terrible way - NEVER do this!
foo_df %>% 
  filter(tissue == c("Liver", "Heart"))

```

But you should NEVER do that. You see why when you change the order of the query:

```{r}
# Terrible way - NEVER do this!
foo_df %>% 
  filter(tissue == c("Heart", "Liver"))

```

So how do we search for many elements at the same time? Recall the `\%in\%` operator:

```{r}
# Heart and Liver and Intestine - nice way
foo_df %>% 
  filter(tissue %in% c("Heart", "Liver"))
```

## Summary of Operators

So far we've encountered several operator types. Let's recap:

Table: (\#tab:Operators) A summary of common operators in R.

| Operator type | Example                                        | Description                                    | Example                   |
|---------------|------------------------------------------------|------------------------------------------------|---------------------------|
| Assign        | `<-`                                           | Create an object                               | Section \@ref(sec:assign) |
| Colon         | `:`                                            | Create an series of integers (increments of 1) | Section \@ref(ref:colon)  |
| Arithmetic    | `+`, `-`, `*`, `/`, `^`, `**`, `%/%`, `%%`     | Do math                                        | Table \@ref(tab:syntax) |
| Relational    | `>=`, `>`, `<=`, `<`, `==`, `!=`, `!x`         | Ask TRUE/FALSE questions                       | Table \@ref(tab:RelOp)    |
| Logical       | `&`, `&&`, `|`, `||`, `%in%`                   | Combine questions                              | Table \@ref(tab:LogOp)    |
| Double colon  | `::`                                           | Call a function within a specific package      | Section \@ref(ref:doublecolon) |
| Pipe          | `%>%`                                          | Pipe two lines of code                         | Example \@ref(sec:pipe), \@ref(dplyrpipe)                              |

## Exercises for Logical Expressions

See the chapter on the `diamonds` data set and complete the exercises for logical expressions. 

## The Floating Point Trap {#sec:float}

Real numbers, with decimal places, are type `double` in R (and in computing in general); they are also referred to as "floating point numbers". These names refer to the way numeric values are stored in memory.^[For more information on this and other terrible R problems, see "R Inferno", by Burns Stats]

For example, we know that `0.3/3` equates to `0.1`:

```{r}
0.3 / 3

```

but it turns out that's not true when we check using a relational operator:

```{r}

0.1 == 0.3 / 3 # FALSE
```

That's really bad news if you're basing your answers on this result! Why does this occur?

First off, to check for equivalency, we can use:


```{r}
# To check for floating point numbers:
all.equal(0.1, 0.3 / 3) # TRUE

```


Whenever we execute a command, _without_ assigning the output to an object, we'll see the output in two possible _devices_: the graphical device for plots, and in this case, the console (or in the case of an R markdown or LaTeX document, whatever output document you are generating). This means that under-the-hood, R is calling the `print()` command. If we adjust the number of significant digits it shows, we'll see why the results are not the same:

```{r}
print(0.3 / 3, digits = 16)

```


So that means if we round the result, it should equate to 0.1:


```{r}
0.1 == round(0.3 / 3, 2) # TRUE

```


Let's take a look as some more involved examples. In the following sequence:


```{r}
seq(0, 1, by=.1)

```


There is exactly one 0.3, but when I ask to see it:


```{r}
seq(0, 1, by=.1) == .3

```


I discover that there are none! In another example, all of the following equations equate to `0.3`


```{r}

# All 0.3:
all_0.3 <- c(.3,
             .4 - .1,
             .5 - .2,
             .6 - .3,
             .7 - .4)
all_0.3
```

But when I look for real unique values here, expecting a single `0.3`, I get three `0.3`s. ^[We see why this occurs when we print more digits, e.g. `print(all\_0.3, digits = 17)`.]

```{r}
unique(all_0.3)
```

This is _not_ an R-specific problem - it's a computing problem. If you are going to ask questions like the ones above, you need to be aware that the answer may be affected by the storage method of the data.
