Re-render book for O'Reilly
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<section id="introduction" data-type="sect1">
|
||||
<h1>
|
||||
Introduction</h1>
|
||||
<p>In this chapter, you’ll learn tools for working with logical vectors. Logical vectors are the simplest type of vector because each element can only be one of three possible values: <code>TRUE</code>, <code>FALSE</code>, and <code>NA</code>. It’s relatively rare to find logical vectors in your raw data, but you’ll create and manipulate in the course of almost every analysis.</p>
|
||||
<p>In this chapter, you’ll learn tools for working with logical vectors. Logical vectors are the simplest type of vector because each element can only be one of three possible values: <code>TRUE</code>, <code>FALSE</code>, and <code>NA</code>. It’s relatively rare to find logical vectors in your raw data, but you’ll create and manipulate them in the course of almost every analysis.</p>
|
||||
<p>We’ll begin by discussing the most common way of creating logical vectors: with numeric comparisons. Then you’ll learn about how you can use Boolean algebra to combine different logical vectors, as well as some useful summaries. We’ll finish off with <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code> and <code><a href="https://dplyr.tidyverse.org/reference/case_when.html">case_when()</a></code>, two useful functions for making conditional changes powered by logical vectors.</p>
|
||||
|
||||
<section id="prerequisites" data-type="sect2">
|
||||
@@ -20,7 +20,7 @@ library(nycflights13)</pre>
|
||||
x * 2
|
||||
#> [1] 2 4 6 10 14 22 26</pre>
|
||||
</div>
|
||||
<p>This makes it easier to explain individual functions at the cost of making it harder to see how it might apply to your data problems. Just remember that any manipulation we do to a free-floating vector, you can do to a variable inside data frame with <code><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate()</a></code> and friends.</p>
|
||||
<p>This makes it easier to explain individual functions at the cost of making it harder to see how it might apply to your data problems. Just remember that any manipulation we do to a free-floating vector, you can do to a variable inside a data frame with <code><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate()</a></code> and friends.</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">df <- tibble(x)
|
||||
df |>
|
||||
@@ -47,18 +47,18 @@ Comparisons</h1>
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
filter(dep_time > 600 & dep_time < 2000 & abs(arr_delay) < 20)
|
||||
#> # A tibble: 172,286 × 19
|
||||
#> year month day dep_time sched_…¹ dep_d…² arr_t…³ sched…⁴ arr_d…⁵ carrier
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <chr>
|
||||
#> 1 2013 1 1 601 600 1 844 850 -6 B6
|
||||
#> 2 2013 1 1 602 610 -8 812 820 -8 DL
|
||||
#> 3 2013 1 1 602 605 -3 821 805 16 MQ
|
||||
#> 4 2013 1 1 606 610 -4 858 910 -12 AA
|
||||
#> 5 2013 1 1 606 610 -4 837 845 -8 DL
|
||||
#> 6 2013 1 1 607 607 0 858 915 -17 UA
|
||||
#> # … with 172,280 more rows, 9 more variables: flight <int>, tailnum <chr>,
|
||||
#> # origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
|
||||
#> # minute <dbl>, time_hour <dttm>, and abbreviated variable names
|
||||
#> # ¹sched_dep_time, ²dep_delay, ³arr_time, ⁴sched_arr_time, ⁵arr_delay</pre>
|
||||
#> year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int>
|
||||
#> 1 2013 1 1 601 600 1 844 850
|
||||
#> 2 2013 1 1 602 610 -8 812 820
|
||||
#> 3 2013 1 1 602 605 -3 821 805
|
||||
#> 4 2013 1 1 606 610 -4 858 910
|
||||
#> 5 2013 1 1 606 610 -4 837 845
|
||||
#> 6 2013 1 1 607 607 0 858 915
|
||||
#> # … with 172,280 more rows, and 11 more variables: arr_delay <dbl>,
|
||||
#> # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
|
||||
#> # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
|
||||
#> # time_hour <dttm></pre>
|
||||
</div>
|
||||
<p>It’s useful to know that this is a shortcut and you can explicitly create the underlying logical variables with <code><a href="https://dplyr.tidyverse.org/reference/mutate.html">mutate()</a></code>:</p>
|
||||
<div class="cell">
|
||||
@@ -104,7 +104,7 @@ x
|
||||
<pre data-type="programlisting" data-code-language="r">x == c(1, 2)
|
||||
#> [1] FALSE FALSE</pre>
|
||||
</div>
|
||||
<p>What’s going on? Computers store numbers with a fixed number of decimal places so there’s no way to exactly represent 1/49 or <code>sqrt(2)</code> and subsequent computations will be very slightly off. We can see the exact values by calling <code><a href="https://rdrr.io/r/base/print.html">print()</a></code> with the the <code>digits</code><span data-type="footnote">R normally calls print for you (i.e. <code>x</code> is a shortcut for <code>print(x)</code>), but calling it explicitly is useful if you want to provide other arguments.</span> argument:</p>
|
||||
<p>What’s going on? Computers store numbers with a fixed number of decimal places so there’s no way to exactly represent 1/49 or <code>sqrt(2)</code> and subsequent computations will be very slightly off. We can see the exact values by calling <code><a href="https://rdrr.io/r/base/print.html">print()</a></code> with the <code>digits</code><span data-type="footnote">R normally calls print for you (i.e. <code>x</code> is a shortcut for <code>print(x)</code>), but calling it explicitly is useful if you want to provide other arguments.</span> argument:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">print(x, digits = 16)
|
||||
#> [1] 0.9999999999999999 2.0000000000000004</pre>
|
||||
@@ -145,7 +145,7 @@ x == y
|
||||
#> [1] NA
|
||||
# We don't know!</pre>
|
||||
</div>
|
||||
<p>So if you want to find all flights with <code>dep_time</code> is missing, the following code doesn’t work because <code>dep_time == NA</code> will yield a <code>NA</code> for every single row, and <code><a href="https://dplyr.tidyverse.org/reference/filter.html">filter()</a></code> automatically drops missing values:</p>
|
||||
<p>So if you want to find all flights where <code>dep_time</code> is missing, the following code doesn’t work because <code>dep_time == NA</code> will yield <code>NA</code> for every single row, and <code><a href="https://dplyr.tidyverse.org/reference/filter.html">filter()</a></code> automatically drops missing values:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
filter(dep_time == NA)
|
||||
@@ -177,18 +177,18 @@ is.na(c("a", NA, "b"))
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
filter(is.na(dep_time))
|
||||
#> # A tibble: 8,255 × 19
|
||||
#> year month day dep_time sched_…¹ dep_d…² arr_t…³ sched…⁴ arr_d…⁵ carrier
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <chr>
|
||||
#> 1 2013 1 1 NA 1630 NA NA 1815 NA EV
|
||||
#> 2 2013 1 1 NA 1935 NA NA 2240 NA AA
|
||||
#> 3 2013 1 1 NA 1500 NA NA 1825 NA AA
|
||||
#> 4 2013 1 1 NA 600 NA NA 901 NA B6
|
||||
#> 5 2013 1 2 NA 1540 NA NA 1747 NA EV
|
||||
#> 6 2013 1 2 NA 1620 NA NA 1746 NA EV
|
||||
#> # … with 8,249 more rows, 9 more variables: flight <int>, tailnum <chr>,
|
||||
#> # origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
|
||||
#> # minute <dbl>, time_hour <dttm>, and abbreviated variable names
|
||||
#> # ¹sched_dep_time, ²dep_delay, ³arr_time, ⁴sched_arr_time, ⁵arr_delay</pre>
|
||||
#> year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int>
|
||||
#> 1 2013 1 1 NA 1630 NA NA 1815
|
||||
#> 2 2013 1 1 NA 1935 NA NA 2240
|
||||
#> 3 2013 1 1 NA 1500 NA NA 1825
|
||||
#> 4 2013 1 1 NA 600 NA NA 901
|
||||
#> 5 2013 1 2 NA 1540 NA NA 1747
|
||||
#> 6 2013 1 2 NA 1620 NA NA 1746
|
||||
#> # … with 8,249 more rows, and 11 more variables: arr_delay <dbl>,
|
||||
#> # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
|
||||
#> # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
|
||||
#> # time_hour <dttm></pre>
|
||||
</div>
|
||||
<p><code><a href="https://rdrr.io/r/base/NA.html">is.na()</a></code> can also be useful in <code><a href="https://dplyr.tidyverse.org/reference/arrange.html">arrange()</a></code>. <code><a href="https://dplyr.tidyverse.org/reference/arrange.html">arrange()</a></code> usually puts all the missing values at the end but you can override this default by first sorting by <code><a href="https://rdrr.io/r/base/NA.html">is.na()</a></code>:</p>
|
||||
<div class="cell">
|
||||
@@ -196,35 +196,35 @@ is.na(c("a", NA, "b"))
|
||||
filter(month == 1, day == 1) |>
|
||||
arrange(dep_time)
|
||||
#> # A tibble: 842 × 19
|
||||
#> year month day dep_time sched_…¹ dep_d…² arr_t…³ sched…⁴ arr_d…⁵ carrier
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <chr>
|
||||
#> 1 2013 1 1 517 515 2 830 819 11 UA
|
||||
#> 2 2013 1 1 533 529 4 850 830 20 UA
|
||||
#> 3 2013 1 1 542 540 2 923 850 33 AA
|
||||
#> 4 2013 1 1 544 545 -1 1004 1022 -18 B6
|
||||
#> 5 2013 1 1 554 600 -6 812 837 -25 DL
|
||||
#> 6 2013 1 1 554 558 -4 740 728 12 UA
|
||||
#> # … with 836 more rows, 9 more variables: flight <int>, tailnum <chr>,
|
||||
#> # origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
|
||||
#> # minute <dbl>, time_hour <dttm>, and abbreviated variable names
|
||||
#> # ¹sched_dep_time, ²dep_delay, ³arr_time, ⁴sched_arr_time, ⁵arr_delay
|
||||
#> year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int>
|
||||
#> 1 2013 1 1 517 515 2 830 819
|
||||
#> 2 2013 1 1 533 529 4 850 830
|
||||
#> 3 2013 1 1 542 540 2 923 850
|
||||
#> 4 2013 1 1 544 545 -1 1004 1022
|
||||
#> 5 2013 1 1 554 600 -6 812 837
|
||||
#> 6 2013 1 1 554 558 -4 740 728
|
||||
#> # … with 836 more rows, and 11 more variables: arr_delay <dbl>,
|
||||
#> # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
|
||||
#> # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
|
||||
#> # time_hour <dttm>
|
||||
|
||||
flights |>
|
||||
filter(month == 1, day == 1) |>
|
||||
arrange(desc(is.na(dep_time)), dep_time)
|
||||
#> # A tibble: 842 × 19
|
||||
#> year month day dep_time sched_…¹ dep_d…² arr_t…³ sched…⁴ arr_d…⁵ carrier
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <chr>
|
||||
#> 1 2013 1 1 NA 1630 NA NA 1815 NA EV
|
||||
#> 2 2013 1 1 NA 1935 NA NA 2240 NA AA
|
||||
#> 3 2013 1 1 NA 1500 NA NA 1825 NA AA
|
||||
#> 4 2013 1 1 NA 600 NA NA 901 NA B6
|
||||
#> 5 2013 1 1 517 515 2 830 819 11 UA
|
||||
#> 6 2013 1 1 533 529 4 850 830 20 UA
|
||||
#> # … with 836 more rows, 9 more variables: flight <int>, tailnum <chr>,
|
||||
#> # origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
|
||||
#> # minute <dbl>, time_hour <dttm>, and abbreviated variable names
|
||||
#> # ¹sched_dep_time, ²dep_delay, ³arr_time, ⁴sched_arr_time, ⁵arr_delay</pre>
|
||||
#> year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int>
|
||||
#> 1 2013 1 1 NA 1630 NA NA 1815
|
||||
#> 2 2013 1 1 NA 1935 NA NA 2240
|
||||
#> 3 2013 1 1 NA 1500 NA NA 1825
|
||||
#> 4 2013 1 1 NA 600 NA NA 901
|
||||
#> 5 2013 1 1 517 515 2 830 819
|
||||
#> 6 2013 1 1 533 529 4 850 830
|
||||
#> # … with 836 more rows, and 11 more variables: arr_delay <dbl>,
|
||||
#> # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
|
||||
#> # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
|
||||
#> # time_hour <dttm></pre>
|
||||
</div>
|
||||
<p>We’ll come back to cover missing values in more depth in <a href="#chp-missing-values" data-type="xref">#chp-missing-values</a>.</p>
|
||||
</section>
|
||||
@@ -240,7 +240,7 @@ Exercises</h2>
|
||||
<section id="boolean-algebra" data-type="sect1">
|
||||
<h1>
|
||||
Boolean algebra</h1>
|
||||
<p>Once you have multiple logical vectors, you can combine them together using Boolean algebra. In R, <code>&</code> is “and”, <code>|</code> is “or”, and <code>!</code> is “not”, and <code><a href="https://rdrr.io/r/base/Logic.html">xor()</a></code> is exclusive or<span data-type="footnote">That is, <code>xor(x, y)</code> is true if x is true, or y is true, but not both. This is how we usually use “or” In English. “Both” is not usually an acceptable answer to the question “would you like ice cream or cake?”.</span>. <a href="#fig-bool-ops" data-type="xref">#fig-bool-ops</a> shows the complete set of Boolean operations and how they work.</p>
|
||||
<p>Once you have multiple logical vectors, you can combine them together using Boolean algebra. In R, <code>&</code> is “and”, <code>|</code> is “or”, <code>!</code> is “not”, and <code><a href="https://rdrr.io/r/base/Logic.html">xor()</a></code> is exclusive or<span data-type="footnote">That is, <code>xor(x, y)</code> is true if x is true, or y is true, but not both. This is how we usually use “or” In English. “Both” is not usually an acceptable answer to the question “would you like ice cream or cake?”.</span>. <a href="#fig-bool-ops" data-type="xref">#fig-bool-ops</a> shows the complete set of Boolean operations and how they work.</p>
|
||||
<div class="cell">
|
||||
<div class="cell-output-display">
|
||||
|
||||
@@ -249,7 +249,7 @@ Boolean algebra</h1>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
<p>As well as <code>&</code> and <code>|</code>, R also has <code>&&</code> and <code>||</code>. Don’t use them in dplyr functions! These are called short-circuiting operators and only ever return a single <code>TRUE</code> or <code>FALSE</code>. They’re important for programming, not data science</p>
|
||||
<p>As well as <code>&</code> and <code>|</code>, R also has <code>&&</code> and <code>||</code>. Don’t use them in dplyr functions! These are called short-circuiting operators and only ever return a single <code>TRUE</code> or <code>FALSE</code>. They’re important for programming, not data science.</p>
|
||||
|
||||
<section id="sec-na-boolean" data-type="sect2">
|
||||
<h2>
|
||||
@@ -276,30 +276,30 @@ df |>
|
||||
<section id="order-of-operations" data-type="sect2">
|
||||
<h2>
|
||||
Order of operations</h2>
|
||||
<p>Note that the order of operations doesn’t work like English. Take the following code finds all flights that departed in November or December:</p>
|
||||
<p>Note that the order of operations doesn’t work like English. Take the following code that finds all flights that departed in November or December:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
filter(month == 11 | month == 12)</pre>
|
||||
</div>
|
||||
<p>You might be tempted to write it like you’d say in English: “find all flights that departed in November or December”:</p>
|
||||
<p>You might be tempted to write it like you’d say in English: “Find all flights that departed in November or December.”:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
filter(month == 11 | 12)
|
||||
#> # A tibble: 336,776 × 19
|
||||
#> year month day dep_time sched_…¹ dep_d…² arr_t…³ sched…⁴ arr_d…⁵ carrier
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <chr>
|
||||
#> 1 2013 1 1 517 515 2 830 819 11 UA
|
||||
#> 2 2013 1 1 533 529 4 850 830 20 UA
|
||||
#> 3 2013 1 1 542 540 2 923 850 33 AA
|
||||
#> 4 2013 1 1 544 545 -1 1004 1022 -18 B6
|
||||
#> 5 2013 1 1 554 600 -6 812 837 -25 DL
|
||||
#> 6 2013 1 1 554 558 -4 740 728 12 UA
|
||||
#> # … with 336,770 more rows, 9 more variables: flight <int>, tailnum <chr>,
|
||||
#> # origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
|
||||
#> # minute <dbl>, time_hour <dttm>, and abbreviated variable names
|
||||
#> # ¹sched_dep_time, ²dep_delay, ³arr_time, ⁴sched_arr_time, ⁵arr_delay</pre>
|
||||
#> year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int>
|
||||
#> 1 2013 1 1 517 515 2 830 819
|
||||
#> 2 2013 1 1 533 529 4 850 830
|
||||
#> 3 2013 1 1 542 540 2 923 850
|
||||
#> 4 2013 1 1 544 545 -1 1004 1022
|
||||
#> 5 2013 1 1 554 600 -6 812 837
|
||||
#> 6 2013 1 1 554 558 -4 740 728
|
||||
#> # … with 336,770 more rows, and 11 more variables: arr_delay <dbl>,
|
||||
#> # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
|
||||
#> # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
|
||||
#> # time_hour <dttm></pre>
|
||||
</div>
|
||||
<p>This code doesn’t error but it also doesn’t seem to have worked. What’s going on? Here R first evaluates <code>month == 11</code> creating a logical vector, which we call <code>nov</code>. It computes <code>nov | 12</code>. When you use a number with a logical operator it converts everything apart from 0 to TRUE, so this is equivalent to <code>nov | TRUE</code> which will always be <code>TRUE</code>, so every row will be selected:</p>
|
||||
<p>This code doesn’t error but it also doesn’t seem to have worked. What’s going on? Here, R first evaluates <code>month == 11</code> creating a logical vector, which we call <code>nov</code>. It computes <code>nov | 12</code>. When you use a number with a logical operator it converts everything apart from 0 to <code>TRUE</code>, so this is equivalent to <code>nov | TRUE</code> which will always be <code>TRUE</code>, so every row will be selected:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
mutate(
|
||||
@@ -348,18 +348,18 @@ c(1, 2, NA) %in% NA
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
filter(dep_time %in% c(NA, 0800))
|
||||
#> # A tibble: 8,803 × 19
|
||||
#> year month day dep_time sched_…¹ dep_d…² arr_t…³ sched…⁴ arr_d…⁵ carrier
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int> <dbl> <chr>
|
||||
#> 1 2013 1 1 800 800 0 1022 1014 8 DL
|
||||
#> 2 2013 1 1 800 810 -10 949 955 -6 MQ
|
||||
#> 3 2013 1 1 NA 1630 NA NA 1815 NA EV
|
||||
#> 4 2013 1 1 NA 1935 NA NA 2240 NA AA
|
||||
#> 5 2013 1 1 NA 1500 NA NA 1825 NA AA
|
||||
#> 6 2013 1 1 NA 600 NA NA 901 NA B6
|
||||
#> # … with 8,797 more rows, 9 more variables: flight <int>, tailnum <chr>,
|
||||
#> # origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
|
||||
#> # minute <dbl>, time_hour <dttm>, and abbreviated variable names
|
||||
#> # ¹sched_dep_time, ²dep_delay, ³arr_time, ⁴sched_arr_time, ⁵arr_delay</pre>
|
||||
#> year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
|
||||
#> <int> <int> <int> <int> <int> <dbl> <int> <int>
|
||||
#> 1 2013 1 1 800 800 0 1022 1014
|
||||
#> 2 2013 1 1 800 810 -10 949 955
|
||||
#> 3 2013 1 1 NA 1630 NA NA 1815
|
||||
#> 4 2013 1 1 NA 1935 NA NA 2240
|
||||
#> 5 2013 1 1 NA 1500 NA NA 1825
|
||||
#> 6 2013 1 1 NA 600 NA NA 901
|
||||
#> # … with 8,797 more rows, and 11 more variables: arr_delay <dbl>,
|
||||
#> # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
|
||||
#> # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
|
||||
#> # time_hour <dttm></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -368,7 +368,7 @@ c(1, 2, NA) %in% NA
|
||||
Exercises</h2>
|
||||
<ol type="1"><li>Find all flights where <code>arr_delay</code> is missing but <code>dep_delay</code> is not. Find all flights where neither <code>arr_time</code> nor <code>sched_arr_time</code> are missing, but <code>arr_delay</code> is.</li>
|
||||
<li>How many flights have a missing <code>dep_time</code>? What other variables are missing in these rows? What might these rows represent?</li>
|
||||
<li>Assuming that a missing <code>dep_time</code> implies that a flight is cancelled, look at the number of cancelled flights per day. Is there a pattern? Is there a connection between the proportion of cancelled flights and average delay of non-cancelled flights?</li>
|
||||
<li>Assuming that a missing <code>dep_time</code> implies that a flight is cancelled, look at the number of cancelled flights per day. Is there a pattern? Is there a connection between the proportion of cancelled flights and the average delay of non-cancelled flights?</li>
|
||||
</ol></section>
|
||||
</section>
|
||||
|
||||
@@ -385,7 +385,7 @@ Logical summaries</h2>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
group_by(year, month, day) |>
|
||||
summarise(
|
||||
summarize(
|
||||
all_delayed = all(arr_delay >= 0, na.rm = TRUE),
|
||||
any_delayed = any(arr_delay >= 0, na.rm = TRUE),
|
||||
.groups = "drop"
|
||||
@@ -404,18 +404,18 @@ Logical summaries</h2>
|
||||
<p>In most cases, however, <code><a href="https://rdrr.io/r/base/any.html">any()</a></code> and <code><a href="https://rdrr.io/r/base/all.html">all()</a></code> are a little too crude, and it would be nice to be able to get a little more detail about how many values are <code>TRUE</code> or <code>FALSE</code>. That leads us to the numeric summaries.</p>
|
||||
</section>
|
||||
|
||||
<section id="numeric-summaries-of-logical-vectors" data-type="sect2">
|
||||
<section id="sec-numeric-summaries-of-logicals" data-type="sect2">
|
||||
<h2>
|
||||
Numeric summaries of logical vectors</h2>
|
||||
<p>When you use a logical vector in a numeric context, <code>TRUE</code> becomes 1 and <code>FALSE</code> becomes 0. This makes <code><a href="https://rdrr.io/r/base/sum.html">sum()</a></code> and <code><a href="https://rdrr.io/r/base/mean.html">mean()</a></code> very useful with logical vectors because <code>sum(x)</code> will give the number of <code>TRUE</code>s and <code>mean(x)</code> the proportion of <code>TRUE</code>s. That lets us see the distribution of delays across the days of the year as shown in <a href="#fig-prop-delayed-dist" data-type="xref">#fig-prop-delayed-dist</a>.</p>
|
||||
<p>When you use a logical vector in a numeric context, <code>TRUE</code> becomes 1 and <code>FALSE</code> becomes 0. This makes <code><a href="https://rdrr.io/r/base/sum.html">sum()</a></code> and <code><a href="https://rdrr.io/r/base/mean.html">mean()</a></code> very useful with logical vectors because <code>sum(x)</code> will give the number of <code>TRUE</code>s and <code>mean(x)</code> the proportion of <code>TRUE</code>s. That lets us see the distribution of delays across the days of the year as shown in <a href="#fig-prop-delayed-dist" data-type="xref">#fig-prop-delayed-dist</a></p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
group_by(year, month, day) |>
|
||||
summarise(
|
||||
summarize(
|
||||
prop_delayed = mean(arr_delay > 0, na.rm = TRUE),
|
||||
.groups = "drop"
|
||||
) |>
|
||||
ggplot(aes(prop_delayed)) +
|
||||
ggplot(aes(x = prop_delayed)) +
|
||||
geom_histogram(binwidth = 0.05)</pre>
|
||||
<div class="cell-output-display">
|
||||
|
||||
@@ -424,11 +424,11 @@ Numeric summaries of logical vectors</h2>
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
<p>Or we could ask how many flights left before 5am, which are often flights that were delayed from the previous day:</p>
|
||||
<p>Or we could ask: “How many flights left before 5am?”, which are often flights that were delayed from the previous day:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
group_by(year, month, day) |>
|
||||
summarise(
|
||||
summarize(
|
||||
n_early = sum(dep_time < 500, na.rm = TRUE),
|
||||
.groups = "drop"
|
||||
) |>
|
||||
@@ -450,12 +450,12 @@ Numeric summaries of logical vectors</h2>
|
||||
<h2>
|
||||
Logical subsetting</h2>
|
||||
<p>There’s one final use for logical vectors in summaries: you can use a logical vector to filter a single variable to a subset of interest. This makes use of the base <code>[</code> (pronounced subset) operator, which you’ll learn more about in <a href="#sec-subset-many" data-type="xref">#sec-subset-many</a>.</p>
|
||||
<p>Imagine we wanted to look at the average delay just for flights that were actually delayed. One way to do so would be to first filter the flights:</p>
|
||||
<p>Imagine we wanted to look at the average delay just for flights that were actually delayed. One way to do so would be to first filter the flights and then calculate the average delay:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
filter(arr_delay > 0) |>
|
||||
group_by(year, month, day) |>
|
||||
summarise(
|
||||
summarize(
|
||||
behind = mean(arr_delay),
|
||||
n = n(),
|
||||
.groups = "drop"
|
||||
@@ -476,7 +476,7 @@ Logical subsetting</h2>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">flights |>
|
||||
group_by(year, month, day) |>
|
||||
summarise(
|
||||
summarize(
|
||||
behind = mean(arr_delay[arr_delay > 0], na.rm = TRUE),
|
||||
ahead = mean(arr_delay[arr_delay < 0], na.rm = TRUE),
|
||||
n = n(),
|
||||
@@ -500,7 +500,7 @@ Logical subsetting</h2>
|
||||
<h2>
|
||||
Exercises</h2>
|
||||
<ol type="1"><li>What will <code>sum(is.na(x))</code> tell you? How about <code>mean(is.na(x))</code>?</li>
|
||||
<li>What does <code><a href="https://rdrr.io/r/base/prod.html">prod()</a></code> return when applied to a logical vector? What logical summary function is it equivalent to? What does <code><a href="https://rdrr.io/r/base/Extremes.html">min()</a></code> return applied to a logical vector? What logical summary function is it equivalent to? Read the documentation and perform a few experiments.</li>
|
||||
<li>What does <code><a href="https://rdrr.io/r/base/prod.html">prod()</a></code> return when applied to a logical vector? What logical summary function is it equivalent to? What does <code><a href="https://rdrr.io/r/base/Extremes.html">min()</a></code> return when applied to a logical vector? What logical summary function is it equivalent to? Read the documentation and perform a few experiments.</li>
|
||||
</ol></section>
|
||||
</section>
|
||||
|
||||
@@ -513,7 +513,7 @@ Conditional transformations</h1>
|
||||
<h2>
|
||||
<code>if_else()</code>
|
||||
</h2>
|
||||
<p>If you want to use one value when a condition is true and another value when it’s <code>FALSE</code>, you can use <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">dplyr::if_else()</a></code><span data-type="footnote">dplyr’s <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code> is very similar to base R’s <code><a href="https://rdrr.io/r/base/ifelse.html">ifelse()</a></code>. There are two main advantages of <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code>over <code><a href="https://rdrr.io/r/base/ifelse.html">ifelse()</a></code>: you can choose what should happen to missing values, and <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code> is much more likely to give you a meaningful error if you variables have incompatible types.</span>. You’ll always use the first three argument of <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code>. The first argument, <code>condition</code>, is a logical vector, the second, <code>true</code>, gives the output when the condition is true, and the third, <code>false</code>, gives the output if the condition is false.</p>
|
||||
<p>If you want to use one value when a condition is <code>TRUE</code> and another value when it’s <code>FALSE</code>, you can use <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">dplyr::if_else()</a></code><span data-type="footnote">dplyr’s <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code> is very similar to base R’s <code><a href="https://rdrr.io/r/base/ifelse.html">ifelse()</a></code>. There are two main advantages of <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code>over <code><a href="https://rdrr.io/r/base/ifelse.html">ifelse()</a></code>: you can choose what should happen to missing values, and <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code> is much more likely to give you a meaningful error if you variables have incompatible types.</span>. You’ll always use the first three argument of <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code>. The first argument, <code>condition</code>, is a logical vector, the second, <code>true</code>, gives the output when the condition is true, and the third, <code>false</code>, gives the output if the condition is false.</p>
|
||||
<p>Let’s begin with a simple example of labeling a numeric vector as either “+ve” or “-ve”:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">x <- c(-3:3, NA)
|
||||
@@ -537,7 +537,7 @@ y1 <- c(3, NA, 4, 6)
|
||||
if_else(is.na(x1), y1, x1)
|
||||
#> [1] 3 1 2 6</pre>
|
||||
</div>
|
||||
<p>You might have noticed a small infelicity in our labeling: zero is neither positive nor negative. We could resolve this by adding an additional <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code>:</p>
|
||||
<p>You might have noticed a small infelicity in our labeling example above: zero is neither positive nor negative. We could resolve this by adding an additional <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code>:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">if_else(x == 0, "0", if_else(x < 0, "-ve", "+ve"), "???")
|
||||
#> [1] "-ve" "-ve" "-ve" "0" "+ve" "+ve" "+ve" "???"</pre>
|
||||
@@ -549,7 +549,7 @@ if_else(is.na(x1), y1, x1)
|
||||
<h2>
|
||||
<code>case_when()</code>
|
||||
</h2>
|
||||
<p>dplyr’s <code><a href="https://dplyr.tidyverse.org/reference/case_when.html">case_when()</a></code> is inspired by SQL’s <code>CASE</code> statement and provides a flexible way of performing different computations for different computations. It has a special syntax that unfortunately looks like nothing else you’ll use in the tidyverse. It takes pairs that look like <code>condition ~ output</code>. <code>condition</code> must be a logical vector; when it’s <code>TRUE</code>, <code>output</code> will be used.</p>
|
||||
<p>dplyr’s <code><a href="https://dplyr.tidyverse.org/reference/case_when.html">case_when()</a></code> is inspired by SQL’s <code>CASE</code> statement and provides a flexible way of performing different computations for different conditions. It has a special syntax that unfortunately looks like nothing else you’ll use in the tidyverse. It takes pairs that look like <code>condition ~ output</code>. <code>condition</code> must be a logical vector; when it’s <code>TRUE</code>, <code>output</code> will be used.</p>
|
||||
<p>This means we could recreate our previous nested <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code> as follows:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">case_when(
|
||||
@@ -592,11 +592,11 @@ if_else(is.na(x1), y1, x1)
|
||||
mutate(
|
||||
status = case_when(
|
||||
is.na(arr_delay) ~ "cancelled",
|
||||
arr_delay > 60 ~ "very late",
|
||||
arr_delay > 15 ~ "late",
|
||||
abs(arr_delay) <= 15 ~ "on time",
|
||||
arr_delay < -15 ~ "early",
|
||||
arr_delay < -30 ~ "very early",
|
||||
arr_delay < -15 ~ "early",
|
||||
abs(arr_delay) <= 15 ~ "on time",
|
||||
arr_delay > 15 ~ "late",
|
||||
arr_delay > 60 ~ "very late",
|
||||
),
|
||||
.keep = "used"
|
||||
)
|
||||
@@ -612,13 +612,38 @@ if_else(is.na(x1), y1, x1)
|
||||
#> # … with 336,770 more rows</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="compatible-types" data-type="sect2">
|
||||
<h2>
|
||||
Compatible types</h2>
|
||||
<p>Note that both <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code> and <code><a href="https://dplyr.tidyverse.org/reference/case_when.html">case_when()</a></code> require <strong>compatible</strong> types in the output. If they’re not compatible, you’ll see errors like this:</p>
|
||||
<div class="cell">
|
||||
<pre data-type="programlisting" data-code-language="r">if_else(TRUE, "a", 1)
|
||||
#> Error in `if_else()`:
|
||||
#> ! Can't combine `true` <character> and `false` <double>.
|
||||
|
||||
case_when(
|
||||
x < -1 ~ TRUE,
|
||||
x > 0 ~ lubridate::now()
|
||||
)
|
||||
#> Error in `case_when()`:
|
||||
#> ! Can't combine `TRUE` <logical> and `lubridate::now()` <datetime<local>>.</pre>
|
||||
</div>
|
||||
<p>Overall, relatively few types are compatible, because automatically converting one type of vector to another is a common source of errors. Here are the most important cases that are compatible:</p>
|
||||
<ul><li>Numeric and logical vectors are compatible, as we discussed in <a href="#sec-numeric-summaries-of-logicals" data-type="xref">#sec-numeric-summaries-of-logicals</a>.</li>
|
||||
<li>Strings and factors (<a href="#chp-factors" data-type="xref">#chp-factors</a>) are compatible, because you can think of a factor as a string with a restricted set of values.</li>
|
||||
<li>Dates and date-times, which we’ll discuss in <a href="#chp-datetimes" data-type="xref">#chp-datetimes</a>, are compatible because you can think of a date as a special case of date-time.</li>
|
||||
<li>
|
||||
<code>NA</code>, which is technically a logical vector, is compatible with everything because every vector has some way of representing a missing value.</li>
|
||||
</ul><p>We don’t expect you to memorize these rules, but they should become second nature over time because they are applied consistently throughout the tidyverse.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="summary" data-type="sect1">
|
||||
<h1>
|
||||
Summary</h1>
|
||||
<p>The definition of a logical vector is simple because each value must be either <code>TRUE</code>, <code>FALSE</code>, or <code>NA</code>. But logical vectors provide a huge amount of power. In this chapter, you learned how to create logical vectors with <code>></code>, <code><</code>, <code><=</code>, <code>=></code>, <code>==</code>, <code>!=</code>, and <code><a href="https://rdrr.io/r/base/NA.html">is.na()</a></code>, how to combine them with <code>!</code>, <code>&</code>, and <code>|</code>, and how to summarize them with <code><a href="https://rdrr.io/r/base/any.html">any()</a></code>, <code><a href="https://rdrr.io/r/base/all.html">all()</a></code>, <code><a href="https://rdrr.io/r/base/sum.html">sum()</a></code>, and <code><a href="https://rdrr.io/r/base/mean.html">mean()</a></code>. You also learned the powerful <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code> and <code><a href="https://dplyr.tidyverse.org/reference/case_when.html">case_when()</a></code> that allow you to return values depending on the value of a logical vector.</p>
|
||||
<p>We’ll see logical vectors again and in the following chapters. For example in <a href="#chp-strings" data-type="xref">#chp-strings</a> you’ll learn about <code>str_detect(x, pattern)</code> which returns a logical vector that’s <code>TRUE</code> for the elements of <code>x</code> that match the <code>pattern</code>, and in <a href="#chp-datetimes" data-type="xref">#chp-datetimes</a> you’ll create logical vectors from the comparison of dates and times. But for now, we’re going to move onto the next most important type of vector: numeric vectors.</p>
|
||||
<p>The definition of a logical vector is simple because each value must be either <code>TRUE</code>, <code>FALSE</code>, or <code>NA</code>. But logical vectors provide a huge amount of power. In this chapter, you learned how to create logical vectors with <code>></code>, <code><</code>, <code><=</code>, <code>=></code>, <code>==</code>, <code>!=</code>, and <code><a href="https://rdrr.io/r/base/NA.html">is.na()</a></code>, how to combine them with <code>!</code>, <code>&</code>, and <code>|</code>, and how to summarize them with <code><a href="https://rdrr.io/r/base/any.html">any()</a></code>, <code><a href="https://rdrr.io/r/base/all.html">all()</a></code>, <code><a href="https://rdrr.io/r/base/sum.html">sum()</a></code>, and <code><a href="https://rdrr.io/r/base/mean.html">mean()</a></code>. You also learned the powerful <code><a href="https://dplyr.tidyverse.org/reference/if_else.html">if_else()</a></code> and <code><a href="https://dplyr.tidyverse.org/reference/case_when.html">case_when()</a></code> functions that allow you to return values depending on the value of a logical vector.</p>
|
||||
<p>We’ll see logical vectors again and again in the following chapters. For example in <a href="#chp-strings" data-type="xref">#chp-strings</a> you’ll learn about <code>str_detect(x, pattern)</code> which returns a logical vector that’s <code>TRUE</code> for the elements of <code>x</code> that match the <code>pattern</code>, and in <a href="#chp-datetimes" data-type="xref">#chp-datetimes</a> you’ll create logical vectors from the comparison of dates and times. But for now, we’re going to move onto the next most important type of vector: numeric vectors.</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user