├── .Rbuildignore ├── .gitignore ├── .travis.yml ├── 00-how-to-use-this-book.Rmd ├── 01-program.Rmd ├── 02-import.Rmd ├── 03-tidy.Rmd ├── 04-transform-tables.Rmd ├── 05-transform-lists.Rmd ├── 06-transform-strings.Rmd ├── 07-transform-factors.Rmd ├── 08-transform-dates.Rmd ├── 09-visualize-data.Rmd ├── DESCRIPTION ├── README.md ├── _bookdown.yml ├── _bookdown_files └── tidyverse-cookbook_files │ └── figure-html │ ├── unnamed-chunk-10-1.png │ ├── unnamed-chunk-12-1.png │ ├── unnamed-chunk-14-1.png │ ├── unnamed-chunk-15-1.png │ ├── unnamed-chunk-17-1.png │ ├── unnamed-chunk-19-1.png │ ├── unnamed-chunk-20-1.png │ ├── unnamed-chunk-209-1.png │ ├── unnamed-chunk-21-1.png │ ├── unnamed-chunk-211-1.png │ ├── unnamed-chunk-213-1.png │ ├── unnamed-chunk-214-1.png │ ├── unnamed-chunk-216-1.png │ ├── unnamed-chunk-218-1.png │ ├── unnamed-chunk-219-1.png │ ├── unnamed-chunk-22-1.png │ ├── unnamed-chunk-220-1.png │ ├── unnamed-chunk-221-1.png │ ├── unnamed-chunk-222-1.png │ ├── unnamed-chunk-223-1.png │ ├── unnamed-chunk-224-1.png │ ├── unnamed-chunk-225-1.png │ ├── unnamed-chunk-226-1.png │ ├── unnamed-chunk-227-1.png │ ├── unnamed-chunk-228-1.png │ ├── unnamed-chunk-229-1.png │ ├── unnamed-chunk-23-1.png │ ├── unnamed-chunk-230-1.png │ ├── unnamed-chunk-231-1.png │ ├── unnamed-chunk-232-1.png │ ├── unnamed-chunk-233-1.png │ ├── unnamed-chunk-234-1.png │ ├── unnamed-chunk-235-1.png │ ├── unnamed-chunk-236-1.png │ ├── unnamed-chunk-237-1.png │ ├── unnamed-chunk-238-1.png │ ├── unnamed-chunk-239-1.png │ ├── unnamed-chunk-24-1.png │ ├── unnamed-chunk-240-1.png │ ├── unnamed-chunk-241-1.png │ ├── unnamed-chunk-242-1.png │ ├── unnamed-chunk-243-1.png │ ├── unnamed-chunk-244-1.png │ ├── unnamed-chunk-245-1.png │ ├── unnamed-chunk-246-1.png │ ├── unnamed-chunk-247-1.png │ ├── unnamed-chunk-248-1.png │ ├── unnamed-chunk-249-1.png │ ├── unnamed-chunk-25-1.png │ ├── unnamed-chunk-250-1.png │ ├── unnamed-chunk-251-1.png │ ├── unnamed-chunk-252-1.png │ ├── unnamed-chunk-253-1.png │ ├── unnamed-chunk-254-1.png │ ├── unnamed-chunk-255-1.png │ ├── unnamed-chunk-256-1.png │ ├── unnamed-chunk-257-1.png │ ├── unnamed-chunk-258-1.png │ ├── unnamed-chunk-259-1.png │ ├── unnamed-chunk-26-1.png │ ├── unnamed-chunk-260-1.png │ ├── unnamed-chunk-261-1.png │ ├── unnamed-chunk-262-1.png │ ├── unnamed-chunk-27-1.png │ ├── unnamed-chunk-28-1.png │ ├── unnamed-chunk-29-1.png │ ├── unnamed-chunk-30-1.png │ ├── unnamed-chunk-32-1.png │ ├── unnamed-chunk-33-1.png │ └── unnamed-chunk-34-1.png ├── _build.sh ├── _deploy.sh ├── _output.yml ├── book.bib ├── data └── mtcars.csv ├── images ├── caution.png ├── data-science-workflow.png ├── data-wrangling.png ├── dplyr-anti-join.png ├── dplyr-arrange.png ├── dplyr-desc.png ├── dplyr-filter.png ├── dplyr-full-join.png ├── dplyr-group_by.png ├── dplyr-groups.png ├── dplyr-inner-join.png ├── dplyr-left-join.png ├── dplyr-mutate.png ├── dplyr-pipe.png ├── dplyr-pull.png ├── dplyr-rename.png ├── dplyr-right-join.png ├── dplyr-select-drop.png ├── dplyr-select-everything.png ├── dplyr-select-range.png ├── dplyr-select-reorder.png ├── dplyr-select.png ├── dplyr-semi-join.png ├── dplyr-summarise.png ├── dplyr-summary-functions.png ├── dplyr-vectorized-functions.png ├── import-dataset.png ├── import-wizard.png ├── important.png ├── note.png ├── purrr-map-goal.png ├── purrr-map.png ├── purrr-pluck.png ├── readr-csv.png ├── readr-csv2.png ├── readr-delim.png ├── readr-fwf.png ├── readr-header.png ├── readr-missing.png ├── readr-nmax.png ├── readr-skip.png ├── readr-tab.png ├── tibble-tibble.png ├── tidy-data.png ├── tidyr-gather.png ├── tidyr-nest.png ├── tidyr-separate-rows.png ├── tidyr-separate.png ├── tidyr-spread.png ├── tidyr-unite.png ├── tidyr-unnest-single.png ├── tidyr-unnest.png ├── tip.png ├── viridis.png └── warning.png ├── index.Rmd ├── packages.bib ├── preamble.tex ├── setup.R ├── style.css └── tidyverse-recipes.Rproj /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | /SCRATCH 6 | outline.Rmd 7 | .DS_Store 8 | /docs 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: r 2 | sudo: false 3 | cache: packages 4 | 5 | before_script: 6 | - chmod +x ./_build.sh 7 | - chmod +x ./_deploy.sh 8 | 9 | script: 10 | - ./_build.sh 11 | - ./_deploy.sh 12 | 13 | r_github_packages: 14 | - nathaneastwood/knitrhooks 15 | -------------------------------------------------------------------------------- /00-how-to-use-this-book.Rmd: -------------------------------------------------------------------------------- 1 | # How to use this book {-} 2 | 3 | ```{r setup, warning=FALSE, message=FALSE, echo=FALSE} 4 | library(tidyverse) 5 | ``` 6 | 7 | The recipes in this book are organized according to the model of data science presented in [_R for Data Science_](http://r4ds.had.co.nz/introduction.html). When you do data science, you find yourself repeating the same sequence of steps: 8 | 9 | ```{r echo = FALSE, fig.align='center'} 10 | knitr::include_graphics("images/data-science-workflow.png") 11 | ``` 12 | 13 | I've grouped the recipes by task with the exception of Transform, which is split into chapters based on the type of data or structure to transform. To drill down to a recipe, click on one of the task names in the sidebar. If you are new to R, begin with [Program], which will show you how to install the tidyverse. 14 | 15 | To save space, each recipe assumes that you have already run `library("tidyverse")`. If additional `library()` calls are required, they will appear in the recipe. 16 | 17 | ## How to get help 18 | 19 | R comes with a built in reference manual, which is fondly (but sometimes inaccurately) called R's help pages. You can use R's help pages to glean details that I do not cover here. 20 | 21 | To access the help page for an R function, type a `?` at the command line of your R console, followed by the function name, and then hit enter to run the result, e.g. 22 | 23 | ```{r eval = FALSE} 24 | ?mutate 25 | ``` 26 | 27 | If a function comes in an R package, you will need to load the package with `library()` before you can access the function's help page. Alternatively, you can access the help page by typing a `?` followed by the package name, followed by two colons, followed by the function name, e.g. 28 | 29 | ```{r eval = FALSE} 30 | ?dplyr::mutate 31 | ``` 32 | 33 | 38 | 39 | ## What is the tidyverse? 40 | 41 | Each of the recipes in this book relies on R's [tidyverse](https://www.tidyverse.org/), which is a collection of R packages designed for data science. Tidyverse packages share a common design philosophy, so when you learn how to use one tidyverse package, you learn a lot about how to use the others. 42 | 43 | Tidyverse packages are also: 44 | 45 | * optimised to run fast, relying on C++ under the hood 46 | * maintained by a paid staff of talented developers 47 | * unusually well documented, see [tidyverse.org](tidyverse.org) and [_R for Data Science_](http://r4ds.had.co.nz/) as examples. 48 | 49 | Install the complete set of tidyverse packages with: 50 | 51 | ```{r eval = FALSE} 52 | install.packages("tidyverse") 53 | ``` 54 | 55 | Each tidyverse package is a collection of functions, documentation, and _ideas_. You do not need to know which ideas are in the tidyverse to use tidyverse functions, just as you do not need to know which ingredients are in a cake mix to make a cake. However, understanding the tidyverse will help you see the best practices embedded in each recipe. This will make it easier for you to adapt the recipes to your own work. 56 | 57 | ### Tidy data {#tidy-data} 58 | 59 | Each package in the tidyverse is designed to use and return **tidy data** whenever appropriate. Tidy data is tabular data organized so that: 60 | 61 | 1. Each column contains a single variable 62 | 1. Each row contains a single observation 63 | 64 | ```{r echo = FALSE, fig.align='center'} 65 | knitr::include_graphics("images/tidy-data.png") 66 | ``` 67 | 68 | In practice, tidy data in R appears as data frames or tibbles. A **tibble** is an enhanced version of a data frame that is easier to view at the command line. R treats tibbles like data frames in almost every other respect, because tibbles are a subclass of data frame. 69 | 70 | ```{r echo = FALSE, fig.align='center'} 71 | knitr::include_graphics("images/tibble-tibble.png") 72 | ``` 73 | 74 | Tidy tibbles act as a common data structure that tidyverse functions use to talk to each other. Tidy data has other advantages as well. Tidy data aligns with R's native data structure, the data frame; and tidy data is easy to use with R's fast, built in vectorized operations. You can think of tidy data as the data format optimized for R. 75 | 76 | ### Tidy tools 77 | 78 | Each package in the tidyverse also provides **tidy tools**. Tidy tools are R functions that: 79 | 80 | 1. Accept and return the same type of data structure (as input and output) 81 | 1. Focus on one task per function 82 | 1. Can be combined with other functions to perform multi-step operations (using the pipe operator, `%>%`) 83 | 84 | Tidy tools are easy to understand and easy to use. They encourage you to organize your work into a sequence of steps that can be considered and checked one at a time. If tidy data is the data format optimized for R, tidy tools are the function format optimized for _you_. 85 | 86 | ```{block2, type = "rmdtip"} 87 | If you'd like a deeper understanding of the tidyverse, I encourage you to read [_R for Data Science_](https://r4ds.had.co.nz/), or to work through the [free primers on RStudio Cloud](https://rstudio.cloud/learn/primers). 88 | ``` -------------------------------------------------------------------------------- /01-program.Rmd: -------------------------------------------------------------------------------- 1 | # (PART) The Recipes {-} 2 | 3 | # Program 4 | 5 | *** 6 | 7 | This chapter includes the following recipes. To manipulate vectors with [purrr](http://purrr.tidyverse.org), see [Transform Lists and Vectors]. 8 | 9 | ```{r echo = FALSE, results='asis'} 10 | build_toc("01-program.Rmd") 11 | ``` 12 | 13 | *** 14 | 15 | ## What you should know before you begin {-} 16 | 17 | ```{block2, type='rmdcaution'} 18 | The [tidyverse](http://www.tidyverse.org) is a collection of R packages that are designed to work well together. There are about 25 packages in the tidyverse. An R package is a bundle of functions, documentation, and data sets. R has over 13,000 packages. These are not installed with R, but are archived [online](https://cran.r-project.org/web/packages/index.html) for when you need them. 19 | 20 | To use an R package, you must: 21 | 22 | 1. Install the package on your local machine with `install.packages()`. You only need to do this once per machine. 23 | 24 | 2. Load the package into your R session with `library()`. You need to do this each time you start a new R session (if you wish to use the package in that session). 25 | 26 | You cannot use the contents of a package until you load the package in your current R session. You should update your packages from time to time to receive the latest improvements from package authors. 27 | ``` 28 | 29 | ```{block2, type='rmdcaution'} 30 | Tidyverse functions are designed to be used with the `%>%` operator. `%>%` links R functions together to create a "pipe" of functions that are run in sequence: `%>%` passes the output of one function to the input of the next. `%>%` comes with the dplyr package, which imports it from the magrittr package. 31 | ``` 32 | 33 | ## Install a tidyverse package {#install} 34 | 35 | You'd like to install a package that is in the tidyverse. 36 | 37 | #### Solution {-} 38 | 39 | ```{r eval = FALSE} 40 | install.packages("dplyr") 41 | ``` 42 | 43 | #### Discussion {-} 44 | 45 | Tidyverse packages can be installed in the normal way with `install.packages()`. See `?install.packages` for installation details. 46 | 47 | ```{block2, type = "rmdcaution"} 48 | By default, `install.packages()` will download packages from [https://cran.r-project.org](https://cran.r-project.org), or one of its mirrors---so be sure you are connected to the internet when you run it. 49 | ``` 50 | 51 | ## Install all of the tidyverse packages {#install-all} 52 | 53 | You'd like to install _all_ of the packages in the tidyverse with a single command. 54 | 55 | #### Solution {-} 56 | 57 | ```{r include = FALSE} 58 | install.packages("tidyverse", repo = "https://cloud.r-project.org") 59 | ``` 60 | 61 | ```{r eval = FALSE} 62 | install.packages("tidyverse") 63 | ``` 64 | 65 | #### Discussion {-} 66 | 67 | The `tidyverse` package provides a shortcut for downloading all of the packages in the tidyverse. `tidyverse` purposefully lists every package in the tidyverse as one of its dependencies. This causes R to install all of the packages in the tidyverse when R installs `tidyverse`. 68 | 69 | `install.packages("tidyverse")` will install the following packages: 70 | 71 | ```{r echo = FALSE} 72 | tidyverse_packages() 73 | ``` 74 | 75 | ## Load a tidyverse package {#load} 76 | 77 | You want to load a package that is in the tidyverse, so that you can use its contents. You've already [installed](#install) the package on your computer. 78 | 79 | #### Solution {-} 80 | 81 | ```{r eval = FALSE} 82 | library("dplyr") 83 | ``` 84 | 85 | #### Discussion {-} 86 | 87 | You can load individual tidyverse packages with `library()`. The package will stay loaded until you end your R session or run `detach()` on the package. If you begin a new R session, you will need to reload the package in the new session with `library()`. 88 | 89 | ```{block2, type = "rmdcaution"} 90 | `library()` cannot load packages that have not been [installed](#install) on your machine. 91 | ``` 92 | 93 | ```{block2, type = "rmdcaution"} 94 | You must place quotation marks around a package name when you use `install.packages()`, but the same is not true for `library()`. The commands below will both load the dplyr package if it is installed on your computer. 95 | 96 | library(dplyr) 97 | library("dplyr") 98 | 99 | ``` 100 | 101 | ## Load the core set of tidyverse packages 102 | 103 | You would like to load the most used packages in the tidyverse with a single command. You've already [installed](#install-all) these packages on your computer. 104 | 105 | #### Solution {-} 106 | 107 | ```{r results='hide', message = FALSE, warning = FALSE} 108 | library("tidyverse") 109 | ``` 110 | 111 | #### Discussion {-} 112 | 113 | When you load the `tidyverse` package, R will also load the following packages: 114 | 115 | - `ggplot2` 116 | - `dplyr` 117 | - `tidyr` 118 | - `readr` 119 | - `purrr` 120 | - `tibble` 121 | - `stringr` 122 | - `forcats` 123 | 124 | These eight packages are considered the "core" of the tidyverse because: 125 | 126 | 1. They are the most used tidyverse packages. 127 | 1. They are often used together as a set (when you use one of the packages, you tend to also use the others). 128 | 129 | You can still load each of these packages individually with `library()`. 130 | 131 | ```{block2, type = "rmdcaution"} 132 | Notice that `library("tidyverse")` does not load every package installed by `install.packages("tidyverse")`. You must use `library()` to individually load the "non-core" tidyverse packages. 133 | ``` 134 | 135 | ## Update a tidyverse package {#update} 136 | 137 | You want to check that you have the latest version of a package that is in the tidyverse. 138 | 139 | #### Solution {-} 140 | 141 | ```{r eval = FALSE} 142 | update.packages("dplyr") 143 | ``` 144 | 145 | #### Discussion {-} 146 | 147 | `update.packages()` compares the version number of your local copy of a package to the version number of the newest version available on CRAN. If your local copy is older than the newest version, `update.packages()` will download and install the newest version from CRAN. Otherwise, `update.packages()` will do nothing. 148 | 149 | ```{block2, type = "rmdcaution"} 150 | Be sure that you are connected to the internet when you run `update.packages()`. 151 | ``` 152 | 153 | ## Update all of the tidyverse packages {#update-all} 154 | 155 | You want to check that you have the latest version of _every_ package that is in the tidyverse. 156 | 157 | #### Solution {-} 158 | 159 | ```{r eval= FALSE} 160 | tidyverse_update() 161 | ``` 162 | 163 | #### Discussion {-} 164 | 165 | `tidyverse_update()` checks whether or not each of your tidyverse packages is [up-to-date](#update). If every package is up-to-date, `tidyverse_update()` will return the message: `All tidyverse packages up-to-date`. Otherwise, `tidyverse_update()` will return a piece of code that you can copy and run to selectively update only those packages that are out-of-date. 166 | 167 | ## List all of the tidyverse packages 168 | 169 | You want to generate a vector that contains the names of every package in the tidyverse. 170 | 171 | #### Solution {-} 172 | 173 | ```{r} 174 | tidyverse_packages() 175 | ``` 176 | 177 | #### Discussion {-} 178 | 179 | `tidyverse_packages()` returns a character vector that contains the names of every package that was in the tidyverse when you installed the `tidyverse` package. These are the packages that were installed onto your machine along with the `tidyverse` package. They are also the packages that [`tidyverse_update()`](#update-all) will check. 180 | 181 | [Update](#update) the `tidyverse` package before running `tidyverse_packages()` to receive the most current list. 182 | 183 | ## Create an object 184 | 185 | You want to create an object that stores content to use later. 186 | 187 | #### Solution {-} 188 | 189 | ```{r} 190 | x <- 1 191 | ``` 192 | 193 | #### Discussion {-} 194 | 195 | The assignment operator is made by a less than sign, `<`, followed by a minus sign `-`. The result looks like an arrow, `<-`. R will assign the contents on the right hand side of the operator to the name on the left hand sign. Afterwards, you can use the name in your code to refer to the contents, e.g. `log(x)`. 196 | 197 | Names cannot begin with a number, nor a special character like `^`, `!`, `$`, `@`, `+`, `-`, `/`, or `*`. 198 | 199 | ```{block2, type = "rmdcaution"} 200 | If you assign to a name that is already in use, the new content will mask or overwrite the previous object. 201 | ``` 202 | 203 | ## Create a vector 204 | 205 | You want to create a one-dimensional, ordered set of values. 206 | 207 | #### Solution {-} 208 | 209 | ```{r} 210 | c(3, 1, 7, 5) 211 | ``` 212 | 213 | #### Discussion {-} 214 | 215 | The concatenate function, `c()`, combines its arguments into a vector that can be passed to a function or assigned to an object. To name each value, provide names to the arguments of `c()`, e.g. 216 | 217 | ```{r} 218 | c(mu = 3, chi = 1, psi = 7, pi = 5) 219 | ``` 220 | 221 | 222 | ## See an object 223 | 224 | You want to see the contents of an object. 225 | 226 | #### Solution {-} 227 | 228 | ```{r} 229 | x 230 | ``` 231 | 232 | #### Discussion {-} 233 | 234 | R displays the contents of an object when you call the bare object name—not surrounded with quotation marks, not followed by parentheses. This works for functions too, in which case R displays the code elements assigned to the function name,e.g. `lm`. 235 | 236 | ## Remove an object 237 | 238 | You want to remove an object that you have created. 239 | 240 | #### Solution {-} 241 | 242 | ```{r} 243 | rm(x) 244 | ``` 245 | 246 | #### Discussion {-} 247 | 248 | The remove function, `rm()`, removes an object from R's memory. `rm()` will not remove an object that is loaded from an R package. 249 | 250 | ## Call a function 251 | 252 | You want to call a function, i.e. you want R to execute a function. 253 | 254 | #### Solution {-} 255 | 256 | ```{r} 257 | round(3.141593, digits = 2) 258 | ``` 259 | 260 | #### Discussion {-} 261 | 262 | To run a function, type its name followed by an open open and closed parentheses. If the function requires arguments (i.e. inputs) to do its job, place the arguments between the parentheses. 263 | 264 | It is a best practice to name every argument after the first. This is sometimes relaxed to every argument after the second argument, if the second argument is also obvious and required. 265 | 266 | 267 | ## See a function's arguments 268 | 269 | You want to see which arguments a function uses/recognizes. 270 | 271 | #### Solution {-} 272 | 273 | ```{r} 274 | args(round) 275 | ``` 276 | 277 | #### Discussion {-} 278 | 279 | `args()` displays the argument names of a function. Ignore the `function`, `(`, `)`, and `NULL` in the output. Each argument name will be listed between the parentheses. 280 | 281 | If an argument has a default value, the value will appear next to its name, as in `digits = 0`. Arguments that have default values are optional: the function will use the default value when you do not supply a different value for that argument. Arguments without default values must be supplied when you run the function to avoid an error. 282 | 283 | 284 | ## Open a function's help page 285 | 286 | You want to open the help page for a function. 287 | 288 | #### Solution {-} 289 | 290 | ```{r} 291 | ?round 292 | ``` 293 | 294 | #### Discussion {-} 295 | 296 | To open a function's help page, run a `?` followed by the bare function name—no parentheses or quotes. A function's help page is the technical documentation for the function and its arguments. Often the most useful section of a help page is the last, which is an examples section of code that uses the function. 297 | 298 | ```{block2, type = "rmdcaution"} 299 | A function's help page is loaded with the function. It will only be available if the package that contains the function is loaded. 300 | ``` 301 | 302 | 303 | ## Combine functions into a pipe 304 | 305 | You want to chain multiple functions together to be run in sequence, with each function operating on the preceding function's output. 306 | 307 | #### Solution {-} 308 | 309 | ```{r} 310 | starwars %>% 311 | group_by(species) %>% 312 | summarise(avg_height = mean(height, na.rm = TRUE)) %>% 313 | arrange(avg_height) 314 | ``` 315 | 316 | #### Discussion {-} 317 | 318 | The `%>%` operator (pronounced "pipe operator") evaluates the code on its left hand side (LHS) and then passes the result to the the code on its right hand side (RHS), which should be a function call. By default `%>%` will pass the result of the LHS to the first unnamed argument of the function on the RHS. 319 | 320 | ```{r echo = FALSE} 321 | knitr::include_graphics("images/dplyr-pipe.png") 322 | ``` 323 | 324 | 325 | So `starwars %>% group_by(species)` is the equivalent of `group_by(starwars, species)`, and the above solution is the equivalent of the nested code: 326 | 327 | ```{r eval = FALSE} 328 | arrange( 329 | summarise( 330 | group_by(starwars, species), 331 | avg_height = mean(height, na.rm = TRUE) 332 | ), 333 | avg_height 334 | ) 335 | ``` 336 | 337 | or the equivalent of: 338 | 339 | ```{r eval = FALSE} 340 | x1 <- starwars 341 | x2 <- group_by(x1, species) 342 | x3 <- summarise(x3, avg_height = mean(height, na.rm = TRUE)) 343 | arrange(x3, avg_height) 344 | ``` 345 | 346 | The chunk of functions connected by `%>%` is called a "pipe." To read a pipe as a sequence of steps, mentally pronounce `%>%` as "then." 347 | 348 | The `%>%` operator is loaded with the dplyr package, which imports it from the magrittr package. Tidyverse functions facilitate using `%>%` by 349 | 350 | 1. accepting a data frame or tibble as their first argument 351 | 2. returning a data frame or tibble as their result 352 | 353 | ```{block2, type = "rmdcaution"} 354 | `%>%` is easy to type in the RStudio IDE with the keyboard shortcuts 355 | 356 | * **Command + Shift + M** (Mac OS) 357 | * **Control + Shift + M** (Windows) 358 | ``` 359 | 360 | 361 | ## Pipe a result to a specific argument 362 | 363 | You want to use `%>%` to pass the result of the left hand side to an argument that is not the first argument of the function on the right hand side. 364 | 365 | #### Solution {-} 366 | 367 | ```{r} 368 | starwars %>% 369 | lm(mass ~ height, data = .) 370 | ``` 371 | 372 | #### Discussion {-} 373 | 374 | By default `%>%` passes the result of the left hand side to the the first unnamed argument of the function on the right hand side. To override this default, use `.` as a placeholder within the function call on the right hand side. `%>%` will evaluate `.` as the result of the left hand side, instead of passing the result to the first unnamed argument. 375 | 376 | The solution code is the equivalent of 377 | 378 | ```{r eval = FALSE} 379 | lm(mass ~ height, data = starwars) 380 | ``` 381 | 382 | -------------------------------------------------------------------------------- /02-import.Rmd: -------------------------------------------------------------------------------- 1 | # Import 2 | 3 | *** 4 | 5 | This chapter includes the following recipes: 6 | 7 | ```{r echo = FALSE, results='asis'} 8 | build_toc("02-import.Rmd") 9 | ``` 10 | 11 | *** 12 | 13 | ## What you should know before you begin {-} 14 | 15 | ```{block2, type='rmdcaution'} 16 | Before you can manipulate data with R, you need to import the data into R's memory, or build a connection to the data that R can use to access the data remotely. For example, you can build a connection to data that lives in a database. 17 | 18 | How you import your data will depend on the format of the data. The most common way to store small data sets is as a plain text file. Data may also be stored in a proprietary format associated with a specific piece of software, such as SAS, SPSS, or Microsoft Excel. Data used on the internet is often stored as a JSON or XML file. Large data sets may be stored in a database or a distributed storage system. 19 | 20 | When you import data into R, R stores the data in your computer's RAM while you manipulate it. This creates a size limitation: truly big data sets should be stored outside of R in a database or a distributed storage system. You can then create a connection to the system that R can use to access the data without bringing the data into your computer's RAM. 21 | 22 | The readr package contains the most common functions in the tidyverse for importing data. The readr package is loaded when you run `library(tidyverse)`. The tidyverse also includes the following packages for importing specific types of data. These are not loaded with `library(tidyverse)`. You must load them individually when you need them. 23 | 24 | * DBI - connect to databases 25 | * haven - read SPSS, Stata, or SAS data 26 | * httr - access data over web APIs 27 | * jsonlite - read JSON 28 | * readxl - read Excel spreadsheets 29 | * rvest - scrape data from the web 30 | * xml2 - read XML 31 | 32 | ### The working directory 33 | 34 | Reading and writing files often involves the use of file paths. If you pass R a partial file path, R will append it to the end of the file path that leads to your _working directory_. In other words, partial file paths are interpretted in relation to your working directory. The working directory can change from session to session, as a general rule, the working directory is the directory where: 35 | 36 | * Your .Rmd file lives (if you are running code by knitting the document) 37 | * Your .Rproj file lives (if you are using the RStudio Project system) 38 | * You opened the R interpreter from (if you are using a unix terminal/shell window) 39 | 40 | Run `getwd()` to see the file path that leads to your current working directory. 41 | ``` 42 | 43 | ## Import data quickly with a GUI 44 | 45 | You want to import data quickly, and you do not mind using a semi-reproducible graphical user interface (GUI) to do so. Your data is not so big that it needs to stay in a database or external storage system. 46 | 47 | #### Solution {-} 48 | 49 | ```{r echo = FALSE, fig.align='center', out.width = "80%"} 50 | knitr::include_graphics("images/import-dataset.png") 51 | ``` 52 | 53 | #### Discussion {-} 54 | 55 | The RStudio IDE provides an Import Dataset button in the Environment pane, which appears in the top right corner of the IDE by default. You can use this button to import data that is stored in plain text files as well as in Excel, SAS, SPSS, and Stata files. 56 | 57 | Click the button to launch a window that includes a file browser (below). Use the browser to select the file to import. 58 | 59 | ```{r echo = FALSE, fig.align='center', out.width = "80%"} 60 | knitr::include_graphics("images/import-wizard.png") 61 | ``` 62 | 63 | After you've selected a file, RStudio will display a preview of how the file will be imported as a data frame. Below the preview, RStudio provides a GUI interface to the common options for importing the type of file you have selected. As you customize the options, RStudio updates the data preview to display the results. 64 | 65 | The bottom right-hand corner of the window displays R code that, if run, will reproduce your importation process programatically. You should copy and save this code if you wish to document your work in a reproducible workflow. 66 | 67 | ## Read a comma-separated values (csv) file 68 | 69 | You want to read a .csv file. 70 | 71 | ```{r echo = FALSE, fig.align='center'} 72 | knitr::include_graphics("images/readr-csv.png") 73 | ``` 74 | 75 | #### Solution {-} 76 | 77 | ```{r} 78 | # To make a .csv file to read 79 | write_file(x = "a,b,c\n1,2,3\n4,5,NA", path = "file.csv") 80 | 81 | my_data <- read_csv("file.csv") 82 | my_data 83 | ``` 84 | 85 | 86 | #### Discussion {-} 87 | 88 | Comma separated value (.csv) files are plain text files arranged so that each line contains a row of data and each cell within a line is separated by a comma. Most data analysis software can export their data as .csv files. So if you are in a pinch you can usually export data from a program as a .csv and then read it into R. 89 | 90 | You can also use `read_csv()` to import csv files that are hosted at their own unique URL. This only works if you are connected to the internet, e.g. 91 | 92 | ```{r eval = FALSE} 93 | my_data <- read_csv("https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/master/data/mtcars.csv") 94 | ``` 95 | 96 | ## Read a semi-colon delimited file 97 | 98 | You want to read a file that resembles a [csv][Read a comma-separated values (csv) file], but uses a _semi-colon_ to separate cells. 99 | 100 | ```{r echo = FALSE, fig.align='center'} 101 | knitr::include_graphics("images/readr-csv2.png") 102 | ``` 103 | 104 | #### Solution {-} 105 | 106 | ```{r} 107 | # To make a .csv file to read 108 | write_file(x = "a;b;c\n1;2;3\n4;5;NA", path = "file2.csv") 109 | 110 | my_data <- read_csv2("file2.csv") 111 | my_data 112 | ``` 113 | 114 | #### Discussion {-} 115 | 116 | Semi-colon delimited files are popular in parts of the world that use commas for decimal places, like Europe. Semi-colon delimited files are often still given the .csv file extension. 117 | 118 | ## Read a tab delimited file 119 | 120 | You want to read a file that resembles a [csv][Read a comma-separated values (csv) file], but uses a _tab_ to separate cells. 121 | 122 | ```{r echo = FALSE, fig.align='center'} 123 | knitr::include_graphics("images/readr-tab.png") 124 | ``` 125 | 126 | #### Solution {-} 127 | 128 | ```{r} 129 | # To make a .tsv file to read 130 | write_file(x = "a\tb\tc\n1\t2\t3\n4\t5\tNA", path = "file.tsv") 131 | 132 | my_data <- read_tsv("file.tsv") 133 | my_data 134 | ``` 135 | 136 | #### Discussion {-} 137 | 138 | Tab delimited files are text files that place each row of a table in its own line, and separate each cell within a line with a tab. Tab delimited files commonly have the extensions .tab, .tsv, and .txt. 139 | 140 | 141 | ## Read a text file with an unusual delimiter 142 | 143 | You want to read a file that resembles a [csv][Read a comma-separated values (csv) file], but uses _something other than a comma_ to separate cells. 144 | 145 | ```{r echo = FALSE, fig.align='center'} 146 | knitr::include_graphics("images/readr-delim.png") 147 | ``` 148 | 149 | #### Solution {-} 150 | 151 | ```{r} 152 | # To make a file to read 153 | write_file(x = "a|b|c\n1|2|3\n4|5|NA", path = "file.txt") 154 | 155 | my_data <- read_delim("file.txt", delim = "|") 156 | my_data 157 | ``` 158 | 159 | 160 | #### Discussion {-} 161 | 162 | Use `read_delim()` as you would [`read_csv()`][Read a comma-separated values (csv) file]. Pass the delimiter that your file uses as a character string to the `delim` argument of `read_delim()`. 163 | 164 | ## Read a fixed-width file 165 | 166 | You want to read a .fwf file, which uses the fixed width format to represent a table (each column begins $n$ spaces from the left for every line). 167 | 168 | ```{r echo = FALSE, fig.align='center'} 169 | knitr::include_graphics("images/readr-fwf.png") 170 | ``` 171 | 172 | #### Solution {-} 173 | 174 | ```{r} 175 | # To make a .fwf file to read 176 | write_file(x = "a b c\n1 2 3\n4 5 NA", path = "file.fwf") 177 | 178 | my_data <- read_table("file.fwf") 179 | my_data 180 | ``` 181 | 182 | 183 | #### Discussion {-} 184 | 185 | Fixed width files arrange data so that each row of a table is in its own line, and each cell begins at a _fixed_ number of character spaces from the beginning of the line. For example, in the example below, the cells in the second column each begin 186 | 20 spaces from the beginning of the line, no matter many spaces the contents of the first cell required. At first glance, it is easy to mistake fixed width files for tab delimited files. Fixed with files use individual spaces to separate cells, and not tabs. 187 | 188 | ``` 189 | John Smith WA 418-Y11-4111 190 | Mary Hartford CA 319-Z19-4341 191 | Evan Nolan IL 219-532-c301 192 | ``` 193 | 194 | `read_table()` will read fixed-width files where each column is separated by at least one whitespace on every line. Use `read_fwf()` to read fixed-width files that have non-standard formatting. 195 | 196 | 197 | 198 | ## Read a file no header 199 | 200 | You want to read a file that does not include a line of column names at the start of the file. 201 | 202 | ```{r echo = FALSE, fig.align='center'} 203 | knitr::include_graphics("images/readr-header.png") 204 | ``` 205 | 206 | #### Solution {-} 207 | 208 | ```{r} 209 | # To make a .csv file to read 210 | write_file("1,2,3\n4,5,NA","file.csv") 211 | 212 | my_data <- read_csv("file.csv", col_names = c("a", "b", "c")) 213 | my_data 214 | ``` 215 | 216 | 217 | #### Discussion {-} 218 | 219 | If you do not wish to supply column names, set `col_names = FALSE`. The `col_names` argument works for all readr functions that read tabular data. 220 | 221 | 222 | ## Skip lines at the start of a file when reading a file 223 | 224 | You want to read a portion of a file, skipping one or more lines at the _start_ of the file. For example, you want to avoid reading the introductory text at the start of a file. 225 | 226 | ```{r echo = FALSE, fig.align='center'} 227 | knitr::include_graphics("images/readr-skip.png") 228 | ``` 229 | 230 | #### Solution {-} 231 | 232 | ```{r} 233 | # To make a .csv file to read 234 | write_file("a,b,c\n1,2,3\n4,5,NA","file.csv") 235 | 236 | my_data <- read_csv("file.csv", skip = 1) 237 | my_data 238 | ``` 239 | 240 | #### Discussion {-} 241 | 242 | Set `skip` equal to the number of lines you wish to skip before you begin reading the file. The `skip` argument works for all readr functions that read tabular data, and can be combined with the [`n_max` argument][Skip lines at the end of a file when reading a file] to skip more lines at the end of a file. 243 | 244 | When in doubt, first try reading the file with `read_lines("file.csv")` to determine how many lines you need to skip. 245 | 246 | ## Skip lines at the end of a file when reading a file 247 | 248 | You want to read a portion of a file, skipping one or more lines at the _end_ of the file. For example, you want to avoid reading in a text comment that appears at the end of a file. 249 | 250 | ```{r echo = FALSE, fig.align='center'} 251 | knitr::include_graphics("images/readr-nmax.png") 252 | ``` 253 | 254 | #### Solution {-} 255 | 256 | ```{r} 257 | # To make a .csv file to read 258 | write_file("a,b,c\n1,2,3\n4,5,NA","file.csv") 259 | 260 | my_data <- read_csv("file.csv", n_max = 1) 261 | my_data 262 | ``` 263 | 264 | #### Discussion {-} 265 | 266 | Set `n_max` equal to the number of _non-header_ lines you wish to read before you stop reading lines. The `n_max` argument works for all readr functions that read tabular data. 267 | 268 | When in doubt, first try reading the file with `read_lines("file.csv")` to determine how many lines you need to skip. 269 | 270 | ## Replace missing values as you read a file 271 | 272 | You want to convert missing values to NA as you read a file, because they have been recorded with a different symbol. 273 | 274 | ```{r echo = FALSE, fig.align='center'} 275 | knitr::include_graphics("images/readr-missing.png") 276 | ``` 277 | 278 | #### Solution {-} 279 | 280 | ```{r} 281 | # To make a .csv file to read 282 | write_file("a,b,c\n1,2,3\n4,5,.","file.csv") 283 | 284 | my_data <- read_csv("file.csv", na = ".") 285 | my_data 286 | ``` 287 | 288 | #### Discussion {-} 289 | 290 | R's uses the string `NA` to represent missing data. If your file was exported from another language or application, it might use a different convention. R is likely to read in the convention as a character string, failing to understand that it represents missing data. To prevent this, explicitly tell `read_csv()` which strings are used to represent missing data. 291 | 292 | The `na` argument works for all readr functions that read tabular data. 293 | 294 | ## Read a compressed RDS file 295 | 296 | You want to read an .RDS file. 297 | 298 | #### Solution {-} 299 | 300 | ```{r} 301 | # To make a .RDS file to read 302 | saveRDS(pressure, file = "file.RDS") 303 | 304 | my_data <- readRDS("file.RDS") 305 | my_data 306 | ``` 307 | 308 | 309 | #### Discussion {-} 310 | 311 | `readRDS` is a base R function—you do not need to run `library(tidyverse)` to use it. RDS is a file format native to R for saving compressed content. RDS files are _not_ text files and are not human readable in their raw form. Each RDS file contains a single object, which makes it easy to assign its output directly to a single R object. This is not necessarily the case for .RData files, which makes .RDS files safer to use. 312 | 313 | ## Read an Excel spreadsheet 314 | 315 | You want to read an Excel spreadsheet. 316 | 317 | #### Solution {-} 318 | 319 | ```{r} 320 | library(readxl) 321 | 322 | # File path to an example excel spreadsheet to import 323 | file_path <- readxl_example("datasets.xlsx") 324 | 325 | my_data <- read_excel(file_path) 326 | my_data 327 | ``` 328 | 329 | #### Discussion {-} 330 | 331 | By default, `read_excel()` reads the _first_ sheet in an Excel spreadsheet. See the [next recipe][Read a specific sheet from an Excel spreadsheet] to read in sheets other than the first. 332 | 333 | `read_excel()` is loaded with the readxl package, which must be loaded with `library(readxl)`. Pass `read_excel()` a file path or URL that leads to the Excel file you wish to read. `readxl_example("datasets.xlsx")` returns a file path that leads to an example Excel spreadsheet that is conveniently installed with the readxl package. 334 | 335 | 336 | ## Read a specific sheet from an Excel spreadsheet 337 | 338 | You want to read a specific sheet from an Excel spreadsheet. 339 | 340 | #### Solution {-} 341 | 342 | ```{r} 343 | library(readxl) 344 | 345 | # File path to an example excel spreadsheet to import 346 | file_path <- readxl_example("datasets.xlsx") 347 | 348 | my_data <- read_excel(file_path, sheet = "chickwts") 349 | my_data 350 | ``` 351 | 352 | #### Discussion {-} 353 | 354 | To read a specific sheet from a larger Excel spreadsheet, use the `sheet` argument to pass [`read_excel()`][Read an Excel spreadsheet] the name of the sheet as a character string. You can also pass `sheet` the number of the sheet to read. For example, `read_excel(file_path, sheet = 2)` would read the second spreadsheet in the file. 355 | 356 | If you are unsure of the name of a sheet, use the `excel_sheets()` function to list the names of the spreadsheets within a file, without importing the file, e.g. `excel_sheets(file_path)`. 357 | 358 | ## Read a field of cells from an excel spreadsheet 359 | 360 | You want to read a subset of cells from an Excel spreadsheet. 361 | 362 | #### Solution {-} 363 | 364 | ```{r} 365 | library(readxl) 366 | 367 | # File path to an example excel spreadsheet to import 368 | file_path <- readxl_example("datasets.xlsx") 369 | 370 | my_data <- read_excel(file_path, range = "C1:E4", skip = 3, n_max = 10) 371 | my_data 372 | ``` 373 | 374 | #### Discussion {-} 375 | 376 | `read_excel()` adopts the [`skip`][Skip lines at the start of a file when reading a file] and [`n_max][Skip lines at the end of a file when reading a file] arguments of reader functions to skip rows at the top of the spreadsheet and to control how far down the spreadsheet to read. Use the `range` argument to specify a subset of columns to read. Two column names separated by a `:` specifies those two columns and every column between them. 377 | 378 | 379 | 380 | ## Write to a comma-separate values (csv) file 381 | 382 | You want to save a tibble or data frame as a .csv file. 383 | 384 | #### Solution {-} 385 | 386 | ```{r eval = FALSE} 387 | write_csv(iris, path = "my_file.csv") 388 | ``` 389 | 390 | 391 | #### Discussion {-} 392 | 393 | `write_csv()` is about twice as fast as base R's `write.csv()` and never adds rownames to a table. Tidyverse users tend to place important information in its own column, where it can be easily accessed, instead of in the rownames, where it cannot be as easily accessed. 394 | 395 | R will save your file at the location described by appending the `path` argument to your [working directory][What you should know before you begin]. If your path contains directories, these must exist _before_ you run `write_csv()`. 396 | 397 | ## Write to a semi-colon delimited file 398 | 399 | You want to save a tibble or data frame as a .csv file _that uses semi-colons to delimit cells_. 400 | 401 | #### Solution {-} 402 | 403 | ```{r eval = FALSE} 404 | write_csv2(iris, path = "my_file.csv") 405 | ``` 406 | 407 | 408 | #### Discussion {-} 409 | 410 | R will save your file at the location described by appending the `path` argument to your [working directory][What you should know before you begin]. If your path contains directories, these must exist _before_ you run `write_csv2()`. 411 | 412 | 413 | ## Write to a tab-delimited file 414 | 415 | You want to save a tibble or data frame as a tab delimited file. 416 | 417 | #### Solution {-} 418 | 419 | ```{r eval = FALSE} 420 | write_tsv(iris, path = "my_file.tsv") 421 | ``` 422 | 423 | 424 | #### Discussion {-} 425 | 426 | R will save your file at the location described by appending the `path` argument to your [working directory][What you should know before you begin]. If your path contains directories, these must exist _before_ you run `write_tsv()`. 427 | 428 | 429 | ## Write to a text file with arbitrary delimiters 430 | 431 | You want to save a tibble or data frame as a plain text file that uses an unusual delimiter. 432 | 433 | #### Solution {-} 434 | 435 | ```{r eval = FALSE} 436 | write_delim(iris, path = "my_file.tsv", delim = "|") 437 | ``` 438 | 439 | #### Discussion {-} 440 | 441 | `write_delim()` behaves like [`write_csv()`][Write to a comma-separate values (csv) file], but requires a `delim` argument. Pass `delim` the delimiter you wish to use to separate cells, as a character string. 442 | 443 | R will save your file at the location described by appending the `path` argument to your [working directory][What you should know before you begin]. If your path contains directories, these must exist _before_ you run `write_delim()`. 444 | 445 | ## Write to a compressed RDS file 446 | 447 | You want to write a tibble or data frame to a .RDS file. 448 | 449 | #### Solution {-} 450 | 451 | ```{r} 452 | saveRDS(iris, file = "my_file.RDS") 453 | ``` 454 | 455 | #### Discussion {-} 456 | 457 | `saveRDS()`, along with `readRDS()`, is a base R function, which explains the difference in the argument names as well as the read/write naming pattern compared to readr functions—take note! 458 | 459 | R will save your file at the location described by appending the `path` argument to your [working directory][What you should know before you begin]. If your path contains directories, these must exist _before_ you run `saveRDS()`. Use the .RDS file extension in the file name to help make the uncommon file format obvious. 460 | 461 | ```{r include = FALSE} 462 | files <- c( 463 | "file.RDS", 464 | "file.csv", 465 | "file.fwf", 466 | "file.tsv", 467 | "file.txt", 468 | "file2.csv" 469 | ) 470 | map(files, ~if(file.exists(.x)) file.remove(.x)) 471 | ``` 472 | 473 | 474 | -------------------------------------------------------------------------------- /03-tidy.Rmd: -------------------------------------------------------------------------------- 1 | # Tidy 2 | 3 | *** 4 | 5 | This chapter includes the following recipes: 6 | 7 | ```{r echo = FALSE, results='asis'} 8 | build_toc("03-tidy.Rmd") 9 | ``` 10 | 11 | *** 12 | 13 | ## What you should know before you begin {-} 14 | 15 | ```{block2, type='rmdcaution'} 16 | Data tidying refers to reshaping your data into a tidy data frame or [tibble](#tidy-data). Data tidying is an important first step for your analysis because every tidyverse function will expect your data to be stored as **Tidy Data**. 17 | 18 | Tidy data is tabular data organized so that: 19 | 20 | 1. Each column contains a single variable 21 | 1. Each row contains a single observation 22 | 23 | Tidy data is not an arbitrary requirement of the tidyverse; it is the ideal data format for doing data science with R. Tidy data makes it easy to extract every value of a variable to build a plot or to compute a summary statistic. Tidy data also makes it easy to compute new variables; when your data is tidy, you can rely on R's rowwise operations to maintain the integrity of your observations. Moreover, R can directly manipulate tidy data with R's fast, built-in vectorised observations, which lets your code run as fast as possible. 24 | 25 | The definition of Tidy Data isn't complete until you define variable and observation, so let's borrow two definitions from [_R for Data Science_](https://r4ds.had.co.nz/exploratory-data-analysis.html): 26 | 27 | 1. A **variable** is a quantity, quality, or property that you can measure. 28 | 1. An **observation** is a set of measurements made under similar conditions (you usually make all of the measurements in an observation at the same time and on the same object). 29 | 30 | As you work with data, you will be surprised to realize that what is a variable (or observation) will depend less on the data itself and more on what you are trying to do with it. With enough mental flexibility, you can consider anything to be a variable. However, some variables will be more useful than others for any specific task. In general, if you can formulate your task as an equation (math or code that contains an equals sign), the most useful variables will be the names in the equation. 31 | ``` 32 | 33 | ## Create a tibble manually 34 | 35 | You want to create a tibble from scratch by typing in the contents of the tibble. 36 | 37 | #### Solution {-} 38 | 39 | ```{r} 40 | tribble(~number, ~letter, ~greek, 41 | 1, "a", "alpha", 42 | 2, "b", "beta", 43 | 3, "c", "gamma") 44 | ``` 45 | 46 | #### Discussion {-} 47 | 48 | `tribble()` creates a tibble and tricks you into typing out a preview of the result. To use `tribble()`, list each column name preceded by a `~`, then list the values of the tribble in a rowwise fashion. If you take care to align your columns, the transposed syntax of `tribble()` becomes a preview of the table. 49 | 50 | You can also create a tibble with `tibble()`, whose syntax mirrors `data.frame()`: 51 | 52 | ```{r eval = FALSE} 53 | tibble(number = c(1, 2, 3), 54 | letter = c("a", "b", "c"), 55 | greek = c("alpha", "beta", "gamma")) 56 | ``` 57 | 58 | 59 | ## Convert a data frame to a tibble 60 | 61 | You want to convert a data frame to a tibble. 62 | 63 | #### Solution {-} 64 | 65 | ```{r} 66 | as_tibble(iris) 67 | ``` 68 | 69 | ## Convert a tibble to a data frame 70 | 71 | You want to convert a tibble to a data frame. 72 | 73 | #### Solution {-} 74 | 75 | ```{r} 76 | as.data.frame(table1) 77 | ``` 78 | 79 | #### Discussion {-} 80 | 81 | ```{block2, type = "rmdcaution"} 82 | Be careful to use `as.data.frame()` and not `as_data_frame()`, which is an alias for `as_tibble()`. 83 | ``` 84 | 85 | ## Preview the contents of a tibble 86 | 87 | You want to get an idea of what variables and values are stored in a tibble. 88 | 89 | #### Solution {-} 90 | 91 | ```{r} 92 | storms 93 | ``` 94 | 95 | #### Discussion {-} 96 | 97 | When you call a tibble directly, R will display enough information to give you a quick sense of the contents of the tibble. This includes: 98 | 99 | 1. the dimensions of the tibble 100 | 1. the column names and types 101 | 1. as many cells of the tibble as will fit comfortably in your console window 102 | 103 | ## Inspect every cell of a tibble 104 | 105 | You want to see every value that is stored in a tibble. 106 | 107 | #### Solution {-} 108 | 109 | ```{r eval = FALSE} 110 | View(storms) 111 | ``` 112 | 113 | #### Discussion {-} 114 | 115 | `View()` (with a capital V) opens the tibble in R's data viewer, which will let you scroll to every cell in the tibble. 116 | 117 | ## Spread a pair of columns into a field of cells 118 | 119 | You want to **pivot**, **convert long data to wide**, or move variable names out of the cells and into the column names. These are different ways of describing the same action. 120 | 121 | ```{r echo = FALSE, fig.align = 'center'} 122 | knitr::include_graphics("images/tidyr-spread.png") 123 | ``` 124 | 125 | For example, `table2` contains `type`, which is a column that repeats the variable names `case` and `population`. To make `table2` tidy, you must move `case` and `population` values into their own columns. 126 | 127 | ```{r} 128 | table2 129 | ``` 130 | 131 | #### Solution {-} 132 | 133 | ```{r} 134 | table2 %>% 135 | spread(key = type, value = count) 136 | ``` 137 | 138 | #### Discussion {-} 139 | 140 | To use `spread()`, assign the column that contains variable names to `key`. Assign the column that contains the values that are associated with those names to `value`. `spread()` will: 141 | 142 | 1. Make a copy of the original table 143 | 1. Remove the `key` and `value` columns from the copy 144 | 1. Remove every duplicate row in the data set that remains 145 | 1. Insert a new column for each unique variable name in the `key` column 146 | 1. Fill the new columns with the values of the `value` column in a way that preserves every relationship between values in the original data set 147 | 148 | ```{block2, type='rmdcaution'} 149 | Since this is easier to see than explain, you may want to study the diagram and result above. 150 | ``` 151 | 152 | Each new column created by `spread()` will inherit the data type of the `value` column. If you would to convert each new column to the most sensible data type given its final contents, add the argument `convert = TRUE`. 153 | 154 | ## Gather a field of cells into a pair of columns 155 | 156 | You want to **convert wide data to long**, reshape a **two-by-two table**, or move variable values out of the column names and into the cells. These are different ways of describing the same action. 157 | 158 | ```{r echo = FALSE, fig.align = 'center'} 159 | knitr::include_graphics("images/tidyr-gather.png") 160 | ``` 161 | 162 | For example, `table4a` is a two-by-two table with the column names `1999` and `2000`. These names are values of a `year` variable. The field of cells in `table4a` contains counts of TB cases, which is another variable. To make `table4a` tidy, you need to move year and case values into their own columns. 163 | 164 | ```{r} 165 | table4a 166 | ``` 167 | 168 | #### Solution {-} 169 | 170 | ```{r} 171 | table4a %>% 172 | gather(key = "year", value = "cases", 2:3) 173 | ``` 174 | 175 | #### Discussion {-} 176 | 177 | `gather()` is the inverse of `spread()`: `gather()` collapses a field of cells that spans several columns into two new columns: 178 | 179 | 1. A column of former "keys", which contains the column names of the former field 180 | 1. A column of former "values", which contains the cell values of the former field 181 | 182 | To use `gather()`, pick names for the new `key` and `value` columns, and supply them as strings. Then identify the columns to gather into the new key and value columns. `gather()` will: 183 | 184 | 1. Create a copy of the original table 185 | 1. Remove the identified columns from the copy 186 | 1. Add a key column with the supplied name 187 | 1. Fill the key column with the column names of the removed columns, repeating rows as necessary so that each combination of row and removed column name appears once 188 | 1. Add a value column with the supplied name 189 | 1. Fill the value column with the values of the removed columns in a way that preserves every relationship between values and column names in the original data set 190 | 191 | ```{block2, type='rmdcaution'} 192 | Since this is easier to see than explain, you may want to study the diagram and result above. 193 | ``` 194 | 195 | ##### Identify columns to gather {-} 196 | 197 | You can identify the columns to gather (i.e. remove) by: 198 | 199 | 1. name 200 | 1. index (numbers) 201 | 1. inverse index (negative numbers that specifiy the columns to _retain_, all other columns will be removed.) 202 | 1. the [`select()` helpers](https://dplyr.tidyverse.org/reference/select.html#useful-functions) that come in the dplyr package 203 | 204 | So for example, the following commands will do the same thing as the solution above: 205 | 206 | ```{r eval = FALSE} 207 | table4a %>% gather(key = "year", value = "cases", `"1999", "2000") 208 | table4a %>% gather(key = "year", value = "cases", -1) 209 | table4a %>% gather(key = "year", value = "cases", one_of(c("1999", "2000"))) 210 | ``` 211 | 212 | By default, the new key column will contain character strings. If you would like to convert the new key column to the most sensible data type given its final contents, add the argument `convert = TRUE`. 213 | 214 | ## Separate a column into new columns 215 | 216 | You want to split a single column into multiple columns by separating each cell in the column into a row of cells. Each new cell should contain a separate portion of the value in the original cell. 217 | 218 | ```{r echo = FALSE, fig.align = 'center'} 219 | knitr::include_graphics("images/tidyr-separate.png") 220 | ``` 221 | 222 | For example, `table3` combines `cases` and `population` values in a single column named `rate`. To tidy `table3`, you need to separate `rate` into two columns: one for the `cases` variable and one for the `population` variable. 223 | 224 | ```{r} 225 | table3 226 | ``` 227 | 228 | #### Solution {-} 229 | 230 | ```{r} 231 | table3 %>% 232 | separate(col = rate, into = c("cases", "population"), 233 | sep = "/", convert = TRUE) 234 | ``` 235 | 236 | #### Discussion {-} 237 | 238 | To use `separate()`, pass `col` the name of the column to split, and pass `into` a vector of names for the new columns to split `col` into. You should supply one name for each new column that you expect to appear in the result; a mismatch will imply that something went wrong. 239 | 240 | `separate()` will: 241 | 242 | 1. Create a copy of the original data set 243 | 1. Add a new column for each value of `into`. The values will become the names of the new columns. 244 | 1. Split each cell of `col` into multiple values, based on the locations of a separator character. 245 | 1. Place the new values into the new columns in order, one value per column 246 | 1. Remove the `col` column. Add the argument `remove = FALSE` to retain the `col` column in the final result. 247 | 248 | ```{block2, type='rmdcaution'} 249 | Since this is easier to see than explain, you may want to study the diagram and result above. 250 | ``` 251 | 252 | Each new column created by `separate()` will inherit the data type of the `col` column. If you would like to convert each new column to the most sensible data type given its final contents, add the argument `convert = TRUE`. 253 | 254 | ##### Control where cells are separated {-} 255 | 256 | By default, `separate()` will use non-alpha-numeric characters as a separators. Pass a regular expression to the `sep` argument to specify a different set of separators. Alternatively, pass an integer vector to the `sep` argument to split cells into sequences that each have a specific number of characters: 257 | 258 | * `sep = 1` will split each cell between the first and second character. 259 | * `sep = c(1, 3)` will split each cell between the first and second character and then again between the third and fourth character. 260 | * `sep = -1` will split each cell between the last and second to last character. 261 | 262 | ##### Separate into multiple rows {-} 263 | 264 | `separate_rows()` behaves like `separate()` except that it places each new value into a new row (instead of into a new column). 265 | 266 | ```{r echo = FALSE, fig.align = 'center'} 267 | knitr::include_graphics("images/tidyr-separate-rows.png") 268 | ``` 269 | 270 | To use `separate_rows()`, follow the same syntax as `separate()`. 271 | 272 | ## Unite multiple columns into a single column 273 | 274 | You want to combine several columns into a single column by uniting their values across rows. 275 | 276 | ```{r echo = FALSE, fig.align = 'center'} 277 | knitr::include_graphics("images/tidyr-unite.png") 278 | ``` 279 | 280 | For example, `table5` splits the `year` variable across two columns: `century` and `year`. To make `table5` tidy, you need to unite `century` and `year` into a single column. 281 | 282 | ```{r} 283 | table5 284 | ``` 285 | 286 | #### Solution {-} 287 | 288 | ```{r} 289 | table5 %>% 290 | unite(col = "year", century, year, sep = "") 291 | ``` 292 | 293 | #### Discussion {-} 294 | 295 | To use `unite()`, give the `col` argument a character string to use as the name of the new column to create. Then list the columns to combine. Finally, give the `sep` argument a separator character to use to paste together the values in the cells of each column. `unite()` will: 296 | 297 | 1. Create a copy of the original data set 298 | 1. Paste together the values of the listed columns in a vectorized (i.e. rowwise) fashion. `unite()` will place the value of `sep` between each value during the paste process. 299 | 1. Append the results as a new column whose name is the value of `col` 300 | 1. Remove the listed columns. To retain the columns in the result, add the argument `remove = FALSE`. 301 | 302 | ```{block2, type='rmdcaution'} 303 | Since this is easier to see than explain, you may want to study the diagram and result above. 304 | ``` 305 | 306 | ```{block2, type = "rmdcaution"} 307 | If you do not suppy a `sep` value, `unite()` will use `_` as a separator character. To avoid a separator character, use `sep = ""`. 308 | ``` -------------------------------------------------------------------------------- /04-transform-tables.Rmd: -------------------------------------------------------------------------------- 1 | # Transform Tables 2 | 3 | *** 4 | 5 | This chapter includes the following recipes: 6 | 7 | ```{r echo = FALSE, results='asis'} 8 | build_toc("04-transform-tables.Rmd") 9 | ``` 10 | 11 | *** 12 | 13 | ## What you should know before you begin {-} 14 | 15 | ```{block2, type='rmdcaution'} 16 | The dplyr package provides the most important tidyverse functions for manipulating tables. These functions share some defaults that make it easy to transform tables: 17 | 18 | 1. dplyr functions always return a transformed _copy_ of your table. They won't change your original table unless you tell them to (by saving over the name of the original table). That's good news, because you should always retain a clean copy of your original data in case something goes wrong. 19 | 20 | 2. You can refer to columns by name inside of a dplyr function. There's no need for `$` syntax or `""`. Every dplyr function requires you to supply a data frame, and it will recognize the columns in that data frame, e.g. 21 | 22 | `summarise(mpg, h = mean(hwy), c = mean(cty))` 23 | 24 | This only becomes a problem if you'd like to use an object that has the same name as one of the columns in the data frame. In this case, place `!!` before the object's name to unquote it, dplyr will skip the columns when looking up the object. e.g. 25 | 26 | `hwy <- 1:10` 27 | `summarise(mpg, h = mean(!!hwy), c = mean(cty))` 28 | 29 | Transforming a table sometimes requires more than one recipe. Why? Because tables are made of multiple data structures that work together: 30 | 31 | 1. The table itself is a data frame or tibble. 32 | 1. The columns of the table are vectors. 33 | 1. Some columns may be list-columns, which are lists that contain vectors. 34 | 35 | Each tidyverse function tends to focus on a single type of data structure; it is part of the tidyverse philosophy that each function should do one thing and do it well. 36 | 37 | So to transform a table, begin with a recipe that transforms the structure of the table. You'll find those recipes in this chapter. Then complete it with a recipe that transforms the actual data values in your table. The [Combine transform recipes] recipe will show you how. 38 | ``` 39 | 40 | ## Arrange rows by value in ascending order 41 | 42 | You want to sort the rows of a data frame in **ascending** order by the values in one or more columns. 43 | 44 | ```{r echo = FALSE, fig.align='center'} 45 | knitr::include_graphics("images/dplyr-arrange.png") 46 | ``` 47 | 48 | #### Solution {-} 49 | 50 | ```{r} 51 | mpg %>% 52 | arrange(displ) 53 | ``` 54 | 55 | #### Discussion {-} 56 | 57 | `arrange()` sorts the rows according to the values of the specified column, with the lowest values appearing near the top of the data frame. If you provide additional column names, `arrange()` will use the additional columns in order as tiebreakers to sort within rows that share the same value of the first column. 58 | 59 | ```{r} 60 | mpg %>% 61 | arrange(displ, cty) 62 | ``` 63 | 64 | ## Arrange rows by value in descending order 65 | 66 | You want to sort the rows of a data frame in **descending** order by the values in one or more columns. 67 | 68 | ```{r echo = FALSE, fig.align='center'} 69 | knitr::include_graphics("images/dplyr-desc.png") 70 | ``` 71 | 72 | #### Solution {-} 73 | 74 | ```{r} 75 | mpg %>% 76 | arrange(desc(displ)) 77 | ``` 78 | 79 | #### Discussion {-} 80 | 81 | Place `desc()` around a column name to cause `arrange()` to sort by descending values of that column. You can use `desc()` for tie-breaker columns as well (compare line nine below to the table above). 82 | 83 | ```{r} 84 | mpg %>% 85 | arrange(desc(displ), desc(cty)) 86 | ``` 87 | 88 | 89 | ## Filter rows with a logical test 90 | 91 | You want to filter your table to just the rows that meet a specific condition. 92 | 93 | ```{r echo = FALSE, fig.align='center'} 94 | knitr::include_graphics("images/dplyr-filter.png") 95 | ``` 96 | 97 | #### Solution {-} 98 | 99 | ```{r} 100 | mpg %>% 101 | filter(model == "jetta") 102 | ``` 103 | 104 | #### Discussion {-} 105 | 106 | `filter()` takes a logical test and returns the rows for which the logical test returns `TRUE`. `filter()` will match column names that appear within the logical test to columns in your data frame. 107 | 108 | If you provide multiple logical tests, `filter()` will combine them with an AND operator (`&`): 109 | 110 | ```{r eval = FALSE} 111 | mpg %>% 112 | filter(model == "jetta", year == 1999) 113 | ``` 114 | 115 | Use R's boolean operators, like `|`and `!`, to create other combinations of logical tests to pass to filter. See the help pages for `?Comparison` and `?Logic` to learn more about writing logical tests in R. 116 | 117 | ## Select columns by name 118 | 119 | You want to return a "subset" of columns from your data frame by listing the name of each column to return. 120 | 121 | ```{r echo = FALSE, fig.align='center'} 122 | knitr::include_graphics("images/dplyr-select.png") 123 | ``` 124 | 125 | #### Solution {-} 126 | 127 | ```{r} 128 | table1 %>% 129 | select(country, year, cases) 130 | ``` 131 | 132 | 133 | 134 | #### Discussion {-} 135 | 136 | `select()` returns a new data frame that includes each column passed to `select()`. Repeat a name to include the column twice. 137 | 138 | ## Drop columns by name 139 | 140 | You want to return a "subset" of columns from your data frame by listing the name of each column to drop. 141 | 142 | ```{r echo = FALSE, fig.align='center'} 143 | knitr::include_graphics("images/dplyr-select-drop.png") 144 | ``` 145 | 146 | #### Solution {-} 147 | 148 | ```{r} 149 | table1 %>% 150 | select(-c(population, year)) 151 | ``` 152 | 153 | #### Discussion {-} 154 | 155 | If you use a `-` before a column name, `select()` will return every column in the data frame except that column. To drop more than one column at a time, group the columns into a vector preceded by `-`. 156 | 157 | ## Select a range of columns 158 | 159 | You want to return two columns from a data frame as well as every column that appears between them. 160 | 161 | ```{r echo = FALSE, fig.align='center'} 162 | knitr::include_graphics("images/dplyr-select-range.png") 163 | ``` 164 | 165 | #### Solution {-} 166 | 167 | ```{r} 168 | table1 %>% 169 | select(country:cases) 170 | ``` 171 | 172 | #### Discussion {-} 173 | 174 | If you combine two column names with a `:`, `select()` will return both columns and every column that appears between them in the data frame. 175 | 176 | ## Select columns by integer position 177 | 178 | You want to return a "subset" of columns from your data frame by listing the position of each column to return. 179 | 180 | #### Solution {-} 181 | 182 | ```{r} 183 | table1 %>% 184 | select(1, 2, 4) 185 | ``` 186 | 187 | #### Discussion {-} 188 | 189 | `select()` interprets the whole number _n_ as the _n_th column in the data set. You can combine numbers with `-` and `:` inside of `select()` as well. 190 | 191 | ## Select columns by start of name 192 | 193 | You want to return evey column in your data that begins with a specific string. 194 | 195 | #### Solution {-} 196 | 197 | ```{r} 198 | table1 %>% 199 | select(starts_with("c")) 200 | ``` 201 | 202 | ## Select columns by end of name 203 | 204 | You want to return evey column in your data that ends with a specific string. 205 | 206 | #### Solution {-} 207 | 208 | ```{r} 209 | table1 %>% 210 | select(ends_with("tion")) 211 | ``` 212 | 213 | ## Select columns by string in name 214 | 215 | You want to return evey column in your data whose name contains a specific string or regular expression. 216 | 217 | #### Solution {-} 218 | 219 | ```{r} 220 | table1 %>% 221 | select(matches("o.*u")) 222 | ``` 223 | 224 | #### Discussion {-} 225 | 226 | `o.*u` is a regular expression that matches an `o` followed by a `u` with any number of characters in between. `country` and `population` are returned because the names `country` and `population` each contain an `o` followed (at any distance) by a `u`. 227 | 228 | See the help page for `?regex` to learn more about regular expressions in R. 229 | 230 | ## Reorder columns 231 | 232 | You want to return all of the columns in the original data frame in a new order. 233 | 234 | ```{r echo = FALSE, fig.align='center'} 235 | knitr::include_graphics("images/dplyr-select-reorder.png") 236 | ``` 237 | 238 | #### Solution {-} 239 | 240 | ```{r} 241 | table1 %>% 242 | select(country, year, population, cases) 243 | ``` 244 | 245 | #### Discussion {-} 246 | 247 | Use `select()` to select all of the columns. List the column names in the new order. 248 | 249 | ## Reorder columns without naming each 250 | 251 | You want to reorder some of the columns in the original data frame, but you don't care about the order for other columns, and you may have too many columns to name them each individually. 252 | 253 | ```{r echo = FALSE, fig.align='center'} 254 | knitr::include_graphics("images/dplyr-select-everything.png") 255 | ``` 256 | 257 | #### Solution {-} 258 | 259 | ```{r} 260 | table1 %>% 261 | select(country, year, everything()) 262 | ``` 263 | 264 | #### Discussion {-} 265 | 266 | Use `everything()` within `select()` to select all of the columns in the order they are named: all columns are kept, and no columns are duplicated. Using `everything()` preserves the original ordering of the original (unnamed) columns. 267 | 268 | ## Rename columns 269 | 270 | You want to rename one or more columns in your data frame, retaining the rest. 271 | 272 | ```{r echo = FALSE, fig.align='center'} 273 | knitr::include_graphics("images/dplyr-rename.png") 274 | ``` 275 | 276 | #### Solution {-} 277 | 278 | ```{r} 279 | table1 %>% 280 | rename(state = country, date = year) 281 | ``` 282 | 283 | #### Discussion {-} 284 | 285 | For each column to be renamed, type a new name for the column and set it equal to the old name for the column. 286 | 287 | ## Return the contents of a column as a vector 288 | 289 | You want to return the contents of a single column as a vector, not as a data frame with one column. 290 | 291 | ```{r echo = FALSE, fig.align='center'} 292 | knitr::include_graphics("images/dplyr-pull.png") 293 | ``` 294 | 295 | #### Solution {-} 296 | 297 | ```{r} 298 | table1 %>% 299 | pull(cases) 300 | ``` 301 | 302 | 303 | #### Discussion {-} 304 | 305 | `pull()` comes in the dplyr package. It does the equivalent of `pluck()` in the purrr package; however, `pull()` is designed to work specifically with data frames. `pluck()` is designed to work with all types of lists. 306 | 307 | You can also pull a column by integer position: 308 | 309 | ```{r} 310 | table1 %>% 311 | pull(3) 312 | ``` 313 | 314 | ## Mutate data (Add new variables) 315 | 316 | You want to compute one or more new variables and add them to your table as columns. 317 | 318 | ```{r echo = FALSE, fig.align='center'} 319 | knitr::include_graphics("images/dplyr-mutate.png") 320 | ``` 321 | 322 | #### Solution {-} 323 | 324 | ```{r} 325 | table1 %>% 326 | mutate(rate = cases/population, percent = rate * 100) 327 | ``` 328 | 329 | #### Discussion {-} 330 | 331 | To use `mutate()`, pass it a series of names followed by R expressions. `mutate()` will return a copy of your table that contains one column for each name that you pass to `mutate()`. The name of the column will be the name that you passed to `mutate()`; the contents of the column will be the result of the R expression that you assigned to the name. The R expression should always return a vector of the same length as the other columns in the data frame,^[Or one that can be made the same length with R's recycling rules, e.g. a vector of length one.] because `mutate()` will add the vector as a new column. 332 | 333 | ```{r echo = FALSE, fig.align='center'} 334 | knitr::include_graphics("images/dplyr-vectorized-functions.png") 335 | ``` 336 | 337 | In other words, `mutate()` is intended to be used with _vectorized functions_, which are functions that take a vector of values as input and return a new vector of values as output (e.g `abs()`, `round()`, and all of R's math operations). 338 | 339 | `mutate()` will build the columns in the order that you define them. As a result, you may use a new column in the column definitions that follow it. 340 | 341 | ##### Dropping the original data {-} 342 | 343 | Use `transmute()` to return only the new columns that `mutate()` would create. 344 | 345 | ```{r} 346 | table1 %>% 347 | transmute(rate = cases/population, percent = rate * 100) 348 | ``` 349 | 350 | 351 | ## Summarise data 352 | 353 | You want to compute summary statistics for the data in your data frame. 354 | 355 | ```{r echo = FALSE, fig.align='center'} 356 | knitr::include_graphics("images/dplyr-summarise.png") 357 | ``` 358 | 359 | #### Solution {-} 360 | 361 | ```{r} 362 | table1 %>% 363 | summarise(total_cases = sum(cases), max_rate = max(cases/population)) 364 | ``` 365 | 366 | #### Discussion {-} 367 | 368 | To use `summarise()`, pass it a series of names followed by R expressions. `summarise()` will return a new tibble that contains one column for each name that you pass to `summarise()`. The name of the column will be the name that you passed to `summarise()`; the contents of the column will be the result of the R expression that you assigned to the name. The R expression should always return a single value because `summarise()` will always return a 1 x n tibble.^[`summarise()` will return a larger tibble if you pair it with `group_by()`.] 369 | 370 | ```{r echo = FALSE, fig.align='center'} 371 | knitr::include_graphics("images/dplyr-summary-functions.png") 372 | ``` 373 | 374 | In other words, `summarise()` is intended to be used with _summary functions_, which are functions that take a vector of values as input and return a single value as output (e.g `sum()`, `max()`, `mean()`). In normal use, `summarise()` will pass each function a column (i.e. vector) of values and expect a single value in return. 375 | 376 | `summarize()` is an alias for `summarise()`. 377 | 378 | ## Group data 379 | 380 | You want to assign the rows of your data to subgroups based on their shared values or their shared combinations of values. 381 | 382 | ```{r echo = FALSE, fig.align='center'} 383 | knitr::include_graphics("images/dplyr-groups.png") 384 | ``` 385 | 386 | You want to do this as the first step in a multi-step analysis, because grouping data doesn't do anything noticeable until you pass the grouped data to a tidyverse function. 387 | 388 | #### Solution {-} 389 | 390 | ```{r} 391 | table1 %>% 392 | group_by(country) 393 | ``` 394 | 395 | #### Discussion {-} 396 | 397 | `group_by()` converts your data into a grouped tibble, which is a tibble subclass that indicates in its attributes^[Attributes are metadata associated with a data structure. R can see an object's attributes, but users typically cannot.] which rows belong to which group. 398 | 399 | To group rows by the values of a single column, pass `group_by()` a single column name. To group rows by the unique _combination_ of values across multiple columns, pass `group_by()` the names of two or more columns. 400 | 401 | ##### Group-wise operations {-} 402 | 403 | Where appropriate, tidyverse functions recognize grouped tibbles. Tidyverse functions: 404 | 405 | 1. treat each group as a distinct data set 406 | 1. execute their code separately on each group 407 | 1. combine the results into a new data frame that contains the same grouping characteristics. `summarise()` is a slight exception, see below. 408 | 409 | ## Summarise data by groups 410 | 411 | You want to compute summary statistics for different subgroups of data in your grouped data frame. 412 | 413 | ```{r echo = FALSE, fig.align='center'} 414 | knitr::include_graphics("images/dplyr-group_by.png") 415 | ``` 416 | 417 | #### Solution {-} 418 | 419 | ```{r} 420 | table1 %>% 421 | group_by(country) %>% 422 | summarise(total_cases = sum(cases), max_rate = max(cases/population)) 423 | ``` 424 | 425 | #### Discussion {-} 426 | 427 | Group-wise summaries are the most common use of grouped data. When you apply `summarise()` to grouped data, `summarise()` will: 428 | 429 | 1. treat each group as a distinct data set 430 | 1. compute separate statistics for each group 431 | 1. combine the results into a new tibble 432 | 433 | ```{block2, type='rmdcaution'} 434 | Since this is easier to see than explain, you may want to study the diagram and result above. 435 | ``` 436 | 437 | `summarise()` gives grouped data special treatment in two ways: 438 | 439 | 1. `summarise()` will retain the column(s) that were used to group the data in its result. This makes the output of grouped summaries interpretable. 440 | 441 | 2. `summarise()` will shorten the grouping criteria of its result by one column name (the last column name). Compare this to other tidyverse functions which give their result the _same_ grouping criteria as their input. 442 | 443 | For example, if the input of `summarise()` is grouped by `country` and `year`, the output of `summarise()` will only be grouped by `country`. Because of this, you can call `summarise()` repeatedly to view progressively higher level summaries: 444 | 445 | ```{r} 446 | table1 %>% 447 | group_by(country, year) %>% 448 | summarise(total_cases = sum(cases)) 449 | ``` 450 | 451 | ```{r} 452 | table1 %>% 453 | group_by(country, year) %>% 454 | summarise(total_cases = sum(cases)) %>% 455 | summarise(total_cases = sum(total_cases)) 456 | ``` 457 | 458 | ```{r} 459 | table1 %>% 460 | group_by(country, year) %>% 461 | summarise(total_cases = sum(cases)) %>% 462 | summarise(total_cases = sum(total_cases)) %>% 463 | summarise(total_cases = sum(total_cases)) 464 | ``` 465 | 466 | ## Nest a data frame 467 | 468 | You want to move portions of your data frame into their own tables, and then store those tables in cells in your original data frame. 469 | 470 | ```{r echo = FALSE, fig.align='center'} 471 | knitr::include_graphics("images/tidyr-nest.png") 472 | ``` 473 | 474 | This lets you manipulate the collection of tables with `filter()`, `select()`, `arrange()`, and so on, as you would normally manipulate a collection of values. 475 | 476 | #### Solution {-} 477 | 478 | ```{r} 479 | iris %>% 480 | group_by(Species) %>% 481 | nest(.key = "Measurements") 482 | ``` 483 | 484 | 485 | #### Discussion {-} 486 | 487 | `nest()` comes in the tidyr package. You can use it to nest portions of your data frame in two ways: 488 | 489 | 1. Pass `nest()` a _grouped data frame_ made with `dplyr::group_by()` (as above). `nest()` will create a separate table for each group. The table will contain every row in the group and every column that is not part of the grouping criteria. 490 | 491 | 2. Pass `nest()` an ungrouped data frame and then specify which columns to nest. `nest()` will perform an implicit grouping on the combination of values that appear across the remaining columns, and then create a separate table for each implied grouping. 492 | 493 | You can specify columns with the same syntax and helpers that you would use with dplyr's `select()` function. So, for example, the two calls below will produce the same result as the solution above. 494 | 495 | ```{r eval = FALSE} 496 | iris %>% 497 | nest(Sepal.Width, 498 | Sepal.Length, 499 | Petal.Width, 500 | Petal.Length, 501 | .key = "Measurements") %>% 502 | as_tibble() 503 | 504 | iris %>% 505 | nest(-Species, .key = "Measurements") %>% 506 | as_tibble() 507 | ``` 508 | 509 | `nest()` preserves class, which means that `nest()` will return a data frame if its input is a data frame and a tibble if its input is a tibble. In each case, `nest()` will add the subtables to the result as a list-column. Since, list-columns are much easier to view in a tibble than a data frame, I recommend that you convert the result of `nest()` to a tibble when necessary. 510 | 511 | Use the `.key` argument to provide a name for the new list-column. 512 | 513 | ## Extract a table from a nested data frame 514 | 515 | You want to extract a single table nested within a data frame. 516 | 517 | ```{r echo = FALSE, fig.align='center'} 518 | knitr::include_graphics("images/tidyr-unnest-single.png") 519 | ``` 520 | 521 | For example, you want to extract the setosa table from the nested data set created in the solution above, 522 | 523 | ```{r} 524 | nested_iris <- 525 | iris %>% 526 | group_by(Species) %>% 527 | nest(.key = "Measurements") 528 | ``` 529 | 530 | #### Solution {-} 531 | 532 | ```{r} 533 | nested_iris %>% 534 | filter(Species == "setosa") %>% 535 | unnest() 536 | ``` 537 | 538 | 539 | #### Discussion {-} 540 | 541 | Since the table is in a cell of the data frame, it is possible to extract the table by extracting the contents of the cell (as below). Be sure to use double brackets to extract the content itself, and not a 1 x 1 data frame that contains the cell. 542 | 543 | ```{r eval = FALSE} 544 | nested_iris[[1, 2]] 545 | ``` 546 | 547 | However, this approach can be suboptimal for nested data. Often a nested table relies on information that is stored alongside it for meaning. For example, in the above example, the table relies on the Species variable to indicate that it describes setosa flowers. 548 | 549 | You can extract a nested table along with its related information by first subsetting to just the relevant information and then unnesting the result. 550 | 551 | ## Unnest a data frame 552 | 553 | You want to transform a nested data frame into a flat data frame by re-integrating the nested tables into the surrounding data frame. 554 | 555 | ```{r echo = FALSE, fig.align='center'} 556 | knitr::include_graphics("images/tidyr-unnest.png") 557 | ``` 558 | 559 | For example, you want to unnest the `nested_iris` data frame created in the recipe above, 560 | 561 | ```{r} 562 | nested_iris <- 563 | iris %>% 564 | group_by(Species) %>% 565 | nest(.key = "Measurements") 566 | ``` 567 | 568 | #### Solution {-} 569 | 570 | ```{r} 571 | unnest(nested_iris) 572 | ``` 573 | 574 | #### Discussion {-} 575 | 576 | `unnest()` converts a list-column into a regular column or columns, repeating the surrounding rows as necessary. `unnest()` can handle list columns that contain atomic vectors and data frames, but cannot handle list columns that contain objects that would not naturally fit into a data frame, such as model objects. 577 | 578 | By default, `unnest()` will unnest every list-column in a data frame. To unnest only a subset of list-columns, pass the names of the list-columns to `unnest()` using dplyr `select()` syntax or helpers. `unnest()` will ignore unnamed list columns, excluding them from the result to return a flat data frame. `unnest()` comes in the tidyr package. 579 | 580 | 592 | 593 | 594 | ## Combine transform recipes 595 | 596 | You want to transform the structure of a table, and you want to use the data within the table to do it. This is the sort of thing you do everytime you call `summarise()` or `mutate()`. 597 | 598 | #### Solution {-} 599 | 600 | See the discussion. 601 | 602 | #### Discussion {-} 603 | 604 | When you transform a data frame, you often work with several functions: 605 | 606 | 1. A function that transforms the _table_ itself, adding columns to its structure, or building a whole new table to hold results. 607 | 608 | 1. A function that transforms the values held in the table. Since values are always held in vectors (here column vectors), this function transforms a _vector_ to create a new vector that can then be added to the empty column or table created by function 1. 609 | 610 | 1. A function that mediates between 1 and 2 if the values are embedded in a list-column, which is a _list_. 611 | 612 | The most concise way to learn how to combine these functions is to learn about the functions in isolation, and to then have the functions call each other as necessary. 613 | 614 | ##### An example {-} 615 | 616 | `smiths` contains measurements that describe two fictional people: John and Mary Smith. 617 | 618 | ```{r} 619 | smiths 620 | ``` 621 | 622 | To round the `height` value for each person, you would need two functions: 623 | 624 | 1. `round()` which can round the values of the data vector stored in `smiths$height`. 625 | 626 | ```{r} 627 | round(smiths$height) 628 | ``` 629 | 630 | 2. `mutate()` which can add the results to a copy of the `smiths` table. 631 | 632 | ```{r} 633 | smiths %>% 634 | mutate(height_int = round(height)) 635 | ``` 636 | 637 | `round()` works with data vectors. `mutate()` works with tables. Together they create the table you want. 638 | 639 | ##### An example that uses list columns {-} 640 | 641 | `sepals` is a tibble that I made for this example.^[I made this data frame with the code `sepals <- iris %>% 642 | group_by(Species) %>% 643 | summarise(lengths = list(Sepal.Length))`] It contains sepal length measurements for three species of flowers. The measurements are stored in a list-column named `lengths`. 644 | 645 | ```{r echo = FALSE} 646 | sepals <- iris %>% 647 | group_by(Species) %>% 648 | summarise(lengths = list(Sepal.Length)) 649 | ``` 650 | 651 | ```{r} 652 | sepals 653 | ``` 654 | 655 | Each cell in `lengths` contains a data vector of 50 sepal lengths. 656 | 657 | ```{r} 658 | # For example, the first cell of lengths 659 | sepals[[1, 2]] 660 | ``` 661 | 662 | To add the average sepal length for each species to the table, you would need three functions: 663 | 664 | 1. `mean()` which can compute the average of a data vector in `lengths` 665 | 666 | ```{r} 667 | mean(sepals[[1, 2]]) 668 | ``` 669 | 670 | 2. `map_dbl()` which can apply `mean()` to each cell of `lengths`, which is a list-column. 671 | 672 | ```{r} 673 | map_dbl(sepals$lengths, mean) 674 | ``` 675 | 676 | 3. `mutate()` which can add the results to a copy of the `sepals` table. 677 | 678 | ```{r} 679 | sepals %>% 680 | mutate(avg_length = map_dbl(lengths, mean)) 681 | ``` 682 | 683 | `mean()` works with data vectors. `map_dbl()` works with list-columns. `mutate()` works with tables. Together they create the table you want. 684 | 685 | 686 | ## Join data sets by common column(s) {#joins} 687 | 688 | You want to combine two data frames into a single data frame, such that observations in the first data frame are matched to the corresponding observations in the second data frame, even if those observations do not appear in the same order. 689 | 690 | Your data is structured in such a way that you can match observations by the values of one or more ID columns that appear in both data frames. 691 | 692 | ```{r echo = FALSE, fig.align='center'} 693 | knitr::include_graphics("images/dplyr-left-join.png") 694 | ``` 695 | 696 | For example, you would like to combine `band_members` and `band_instruments` into a single data frame based on the values of the `name` column. The new data frame will correctly list who plays what. 697 | 698 | ```{r} 699 | band_members 700 | ``` 701 | 702 | ```{r} 703 | band_instruments 704 | ``` 705 | 706 | #### Solution {-} 707 | 708 | ```{r} 709 | band_members %>% 710 | left_join(band_instruments, by = "name") 711 | ``` 712 | 713 | #### Discussion {-} 714 | 715 | There are four ways to join content from one data frame to another. Each uses a different function name, but the same arguments and syntax. Of these, `left_join()` is the most common. 716 | 717 | 1. `left_join()` drops any row in the _second_ data set does not match a row in the first data set. (It retains every row in the first data set, which appears on the left when you type the function call, hence the name). 718 | 719 | ```{r echo = FALSE, fig.align='center'} 720 | knitr::include_graphics("images/dplyr-left-join.png") 721 | ``` 722 | 723 | 1. `right_join()` drops any row in the _first_ data set does not match a row in the first data set. 724 | 725 | ```{r echo = FALSE, fig.align='center'} 726 | knitr::include_graphics("images/dplyr-right-join.png") 727 | ``` 728 | 729 | ```{r} 730 | band_members %>% 731 | right_join(band_instruments, by = "name") 732 | ``` 733 | 734 | 1. `inner_join()` drops any row in _either_ data set that does not have a match in both data sets, i.e. `inner_join()` does not retain any incomplete rows in the final result. 735 | 736 | ```{r echo = FALSE, fig.align='center'} 737 | knitr::include_graphics("images/dplyr-inner-join.png") 738 | ``` 739 | 740 | ```{r} 741 | band_members %>% 742 | inner_join(band_instruments, by = "name") 743 | ``` 744 | 745 | 1. `full_join()` retains every row from both data sets; it is the only join guaranteed to retain all of the original data. 746 | 747 | ```{r echo = FALSE, fig.align='center'} 748 | knitr::include_graphics("images/dplyr-full-join.png") 749 | ``` 750 | 751 | ```{r} 752 | band_members %>% 753 | full_join(band_instruments, by = "name") 754 | ``` 755 | 756 | ##### Mutating joins {-} 757 | 758 | `left_join()`, `right_join()`, `inner_join()`, and `full_join()` are collectively called _mutating joins_ because they add additional columns to a copy of a data set, as does `mutate()`. 759 | 760 | ##### Specifying column(s) to join on {-} 761 | 762 | By default, the mutating join functions will join on the set of columns whose names appear in both data frames. The join functions will match each row in the first data frame to the row in the second data frame that has the same combination of values across the commonly named columns. 763 | 764 | To override the default, add a `by` argument to your join function. Pass it the name(s) of the column(s) to join on as a character vector. These names should appear in both data sets. R will join together rows that contain the same combination of values in these columns, ignoring the values in other columns, even if those columns share a name with a column in the other data frame. 765 | 766 | ```{r} 767 | table1 %>% 768 | left_join(table3, by = c("country", "year")) 769 | ``` 770 | 771 | 772 | ##### Joining when ID names do not match {-} 773 | 774 | Often an ID variable will appear with a different name in each data frame. For example, the `name` variable appears as `artist` in `band_instruments2`. 775 | 776 | ```{r} 777 | band_instruments2 778 | ``` 779 | 780 | To join by two columns that have different names, pass `by` a named character vector: each element of the vector should be a pair of names, e.g. 781 | 782 | ```{r eval = FALSE} 783 | c(name1 = "name2", name4 = "name4") 784 | ``` 785 | 786 | For each element, 787 | 788 | 1. Write the name of the column that appears in the first data frame 789 | 2. Write an equals sign 790 | 3. Write the name of the matching column that appears in the second data set. 791 | 792 | Only the second name needs to be surrounded with quotation marks. The join will match the corresponding columns across data frames. 793 | 794 | ```{r} 795 | band_members %>% 796 | left_join(band_instruments2, by = c(name = "artist")) 797 | ``` 798 | 799 | R will use the column name(s) from the first data set in the result. 800 | 801 | ##### Suffixes {-} 802 | 803 | Joins will append the suffixes `.x` and `.y` to any columns that have the same name in both data sets _but are not used to join on_. The columns from the first data set are suffixed with `.x`, the columns from the second with `.y`. 804 | 805 | ```{r} 806 | table4a %>% 807 | left_join(table4b, by = "country") 808 | ``` 809 | 810 | To use different suffixes, supply a character vector of length two as a `suffix` argument. 811 | 812 | ```{r} 813 | table4a %>% 814 | left_join(table4b, by = "country", suffix = c("_cases", "_pop")) 815 | ``` 816 | 817 | ## Find rows that have a match in another data set 818 | 819 | You want to find the rows in one data frame that have a match in a second data frame. By match, you mean that both rows refer to the same observation, even if they include different measurements. 820 | 821 | Your data is structured in such a way that you can match rows by the values of one or more ID columns that appear in both data frames. 822 | 823 | ```{r echo = FALSE, fig.align='center'} 824 | knitr::include_graphics("images/dplyr-semi-join.png") 825 | ``` 826 | 827 | For example, you would like to return the rows of `band_members` that have a corresponding row in `band_instruments`. The new data frame will be a reduced version of `band_members` that does not contain any new columns. 828 | 829 | ```{r} 830 | band_members 831 | ``` 832 | 833 | ```{r} 834 | band_instruments 835 | ``` 836 | 837 | #### Solution {-} 838 | 839 | ```{r} 840 | band_members %>% 841 | semi_join(band_instruments, by = "name") 842 | ``` 843 | 844 | #### Discussion {-} 845 | 846 | `semi_join()` returns only the rows of the first data frame that _have_ a match in the second data frame. A match is a row that would be combined with the first row by a [mutating join](#joins). This makes `semi_join()` a useful way to preview which rows will be retained by a mutating join. 847 | 848 | `semi_join()` uses the same syntax as mutating joins. Learn more in [Specifying column(s) to join on] and [Joining when ID names do not match]. 849 | 850 | ##### Filtering joins {-} 851 | 852 | `semi_join()` and `anti_join()` (see below) are called _filtering joins_ because they filter a data frame to only those rows that meet a specific criteria, as does `filter()`. 853 | 854 | Unlike mutating joins, filtering joins do not add columns from the second data frame to the first. Instead, they use the second data frame to identify rows to return from the first. 855 | 856 | When you need to filter on a complicated set of conditions, filtering joins can be more effective than `filter()`: use `tribble()` to create a data frame to filter against with a filtering join. 857 | 858 | ## Find rows that do not have a match in another data set 859 | 860 | You want to find the rows in one data frame that _do not_ have a match in a second data frame. By match, you mean that both rows refer to the same observation, even if they include different measurements. 861 | 862 | Your data is structured in such a way that you can match rows by the values of one or more ID columns that appear in both data frames. 863 | 864 | ```{r echo = FALSE, fig.align='center'} 865 | knitr::include_graphics("images/dplyr-anti-join.png") 866 | ``` 867 | 868 | For example, you would like to return the rows of `band_members` that do not have a corresponding row in `band_instruments`. The new data frame will be a reduced version of `band_members` that does not contain any new columns. 869 | 870 | ```{r} 871 | band_members 872 | ``` 873 | 874 | ```{r} 875 | band_instruments 876 | ``` 877 | 878 | #### Solution {-} 879 | 880 | ```{r} 881 | band_members %>% 882 | anti_join(band_instruments, by = "name") 883 | ``` 884 | 885 | #### Discussion {-} 886 | 887 | `anti_join()` returns only the rows of the first data frame that _do not have_ a match in the second data frame. A match is a row that would be combined with the first row by a [mutating join](#joins). This makes `ant_join()` a useful way to debug a mutating join. 888 | 889 | `anti_join()` provides a useful way to check for typos that could interfere with a mutating join; these rows will not have a match in the second data frame (assuming that the typo does not also appear in the second data frame). 890 | 891 | `anti_join()` also highlights entries that are coded in different ways across data frames, such as `"North_Carolina"` and `"North Carolina"`. 892 | 893 | `anti_join()` uses the same syntax as mutating joins. Learn more in [Specifying column(s) to join on] and [Joining when ID names do not match]. Along with `semi_join()`, `anti_join()` is one of the two [Filtering joins]. 894 | 895 | 896 | 897 | 898 | 899 | -------------------------------------------------------------------------------- /05-transform-lists.Rmd: -------------------------------------------------------------------------------- 1 | 2 | # Transform Lists and Vectors 3 | 4 | ```{r include = FALSE} 5 | library(knitrhooks) 6 | output_max_height() 7 | ``` 8 | 9 | 10 | *** 11 | 12 | This chapter includes the following recipes: 13 | 14 | ```{r echo = FALSE, results='asis'} 15 | build_toc("05-transform-lists.Rmd") 16 | ``` 17 | 18 | *** 19 | 20 | ## What you should know before you begin {-} 21 | 22 | ```{block2, type='rmdcaution'} 23 | A vector is a one dimensional array of elements. Vectors are the basic building blocks of R. Almost all data in R is stored in a vector, or even a vector of vectors. 24 | 25 | A list is a _recursive vector_: a vector that can contain another vector or list in each of its elements. 26 | 27 | Lists are one of the most flexible data structures in R. As a result, they are used as a general purpose glue to hold objects together. You will find lists disguised as model objects, data frames, list-columns within data frames, and more. 28 | 29 | Data frames are a sub-type of list. Each column of a data frame is an element of the list that the data frame is built around. 30 | 31 | More than any other part of R, lists demonstrate how a programming language can appear different to beginners than to experts. Seasoned R programmers do not distinguish between lists and vectors because the two are equivalent: a list is a type of vector. 32 | 33 | However, a beginner who uses R for data science will quickly see that lists behave differently than other types of vectors. First, many R functions will not accept lists as input, even though they accept other types of vectors. Second, when you subset a list with `[ ]` to extract the value of one of its elements, R will give you a new list of length one that contains the value as its first element. This poses a problem if you want to pass that value to a function that does not accept lists as input (solve that problem with [this recipe](#extract)). 34 | 35 | To respect this difference, I try to be clear when talking about vectors that are not lists. This introduces a new problem: when you speak about R, it is difficult to distinguish between vectors that are lists and vectors that are not lists. Whenever the difference matters, I'll call the first set of vectors **lists** and the second set of vectors **data vectors**^[if you're an R afficianado, data vectors include both atomic vectors and the S3 classes built upon them, like factors and dates and times]. I'll refer to the superset that includes both lists and data vectors as vectors. 36 | 37 | Data vectors come in six atomic _types_: double, integer logical, character, complex, and raw. Every element in a data vector must be the same type of data as the vector (if you try to put a different type of data into an atomic vector, R will coerce the data's type to match the vector). R also contains an S3 class system that builds classes like factors and date-times on top of the atomic types. You don't need to understand R's types and classes to use R or this cookbook, but you should know that R will recognize different types of data and treat them accordingly. 38 | 39 | This chapter focuses on both lists and data vectors, but it only features recipes that work with the _structure_ of a list or data vector. The chapters that follow will contain recipes that work with the _types_ of data stored in a data vector. 40 | ``` 41 | 42 | ## Extract an element from a list {#extract} 43 | 44 | You want to return the value of an element of a list as it is, perhaps to use in a function. You do not want the value to come embedded in a list of length one. 45 | 46 | ```{r echo = FALSE, fig.align='center'} 47 | knitr::include_graphics("images/purrr-pluck.png") 48 | ``` 49 | 50 | 51 | #### Solution {-} 52 | 53 | ```{r} 54 | # returns the element named x in state.center 55 | state.center %>% 56 | pluck("x") 57 | ``` 58 | 59 | #### Discussion {-} 60 | 61 | `pluck()` comes in the purrr package and does the equivalent of `[[` subsetting. If you pass `pluck()` a character string, `pluck()` will return the element whose name matches the string. If you pass `pluck()` an integer _n_, `pluck()` will return the _nth_ element of the list. 62 | 63 | Pass multiple arguments to `pluck()` to subset multiple times. `pluck()` will subset the result of each argument with the argument that follows, e.g. 64 | 65 | ```{r} 66 | library(repurrrsive) 67 | sw_films %>% 68 | pluck(7, "title") 69 | ``` 70 | 71 | ## Determine the type of a vector 72 | 73 | You want to know the type of a vector. 74 | 75 | #### Solution {-} 76 | 77 | ```{r} 78 | typeof(letters) 79 | ``` 80 | 81 | #### Discussion {-} 82 | 83 | R vectors can be one of six atomic types, or a list. `typeof()` provides a useful way to check which type of vector you are working with. This is useful, for example, when you want to match a function's output to an appropriate map function ([below](#map)). 84 | 85 | ## Map a function to each element of a vector {#map} 86 | 87 | You want to apply a function separately to each element in a vector and then combine the results into a single object. This is similar to what you might do with a for loop, or with the apply family of functions. 88 | 89 | ```{r echo = FALSE, fig.align='center'} 90 | knitr::include_graphics("images/purrr-map-goal.png") 91 | ``` 92 | 93 | For example, `got_chars` is a list of 30 sublists. You want to compute the `length()` of each sublist. 94 | 95 | #### Solution {-} 96 | 97 | ```{r, output_max_height = "300px"} 98 | library(repurrrsive) 99 | got_chars %>% 100 | map(length) 101 | ``` 102 | 103 | #### Discussion {-} 104 | 105 | `map()` takes a vector to iterate over (here supplied by the pipe) followed by a function to apply to each element of the vector, followed by any arguments to pass to the function when it is applied to the vector. 106 | 107 | ```{r echo = FALSE, fig.align='center'} 108 | knitr::include_graphics("images/purrr-map.png") 109 | ``` 110 | 111 | Pass the function name to `map()` without quotes and without parentheses. `map()` will pass each element of the vector one at a time to the first argument of the function. 112 | 113 | If your function requires additional arguments to do its job, pass the arguments to `map()`. `map()` will forward these arguments in order, with their names, to the function when `map()` runs the function. 114 | 115 | ```{r, output_max_height = "300px"} 116 | got_chars %>% 117 | map(keep, is.numeric) 118 | ``` 119 | 120 | ##### The map family of functions 121 | 122 | `map()` is one of ten similar functions provided by the purrr package that together form a family of functions. Each member of the map family applies a function to a vector in the same iterative way; but each member returns the results in a different type of data structure. 123 | 124 | Function | Returns 125 | --------- | --------- 126 | `map` | A list 127 | `map_chr` | A character vector 128 | `map_dbl` | A double (numeric) vector 129 | `map_df` | A data frame (`map_df` does the equivalent of `map_dfr`) 130 | `map_dfr` | A single data frame made by row-binding the individual results^[These results should themselves be data frames. In other words, the function that is mapped should return a data frame.] 131 | `map_dfc` | A single data frame made by column-binding the individual results^[These results should themselves be data frames. In other words, the function that is mapped should return a data frame.] 132 | `map_int` | An integer vector 133 | `map_lgl` | A logical vector 134 | `walk` | The original input (returned invisibly) 135 | 136 | #### How to choose a map function 137 | 138 | To map a function over a vector, consider what type of output the function will produce. Then pick the map function that returns that type of output. This is a general rule that will return sensible results. 139 | 140 | For example, the `length()` function returns an integer, so you would map `length()` over `got_chars` with `map_int()`, which returns the results as an integer vector. 141 | 142 | ```{r} 143 | got_chars %>% 144 | map_int(length) 145 | ``` 146 | 147 | `walk()` returns the original vector invisibly (so you can pipe the result to a new function). `walk()` is intended to be used with functions like `plot()` or `print()`, which execute side effects but do not return an object to pass on. 148 | 149 | ##### Map shorthand syntax 150 | 151 | Map functions recognize two syntax shorthands. 152 | 153 | 1. If your vector is a list of sublists, you can extract elements from the sublists by name or position, e.g. 154 | 155 | ```{r} 156 | got_chars %>% 157 | map_chr("name") 158 | ``` 159 | 160 | ```{r} 161 | got_chars %>% 162 | map_chr(3) 163 | ``` 164 | 165 | These do the equivalent of 166 | 167 | ```{r eval = FALSE} 168 | got_chars %>% 169 | map_chr(pluck, "name") 170 | got_chars %>% 171 | map_chr(pluck, 3) 172 | ``` 173 | 174 | 2. You can use `~` and `.x` to map with expressions instead of functions. To turn a pice of code into an expression to map, first place a `~` at the start of the code. Then use `.x` as a pronoun for the value that map should supply from the vector to map over. The map function will iteratively pass each element of your vector to the `.x` in the expression and then run the expression. 175 | 176 | An expression like this: 177 | 178 | ```{r eval = FALSE} 179 | got_chars %>% 180 | map_lgl(~length(.x) > 0) 181 | ``` 182 | 183 | becomes the equivalent of 184 | 185 | ```{r eval = FALSE} 186 | got_chars %>% 187 | map_lgl(function(x) length(x) > 0) 188 | ``` 189 | 190 | Expressions provide an easy way to map over a function argument that is not the first. 191 | 192 | -------------------------------------------------------------------------------- /06-transform-strings.Rmd: -------------------------------------------------------------------------------- 1 | 2 | # Transform Strings 3 | 4 | *** 5 | 6 | ```{r echo = FALSE, results='asis'} 7 | build_toc("06-transform-strings.Rmd") 8 | ``` 9 | 10 | *** 11 | 12 | -------------------------------------------------------------------------------- /07-transform-factors.Rmd: -------------------------------------------------------------------------------- 1 | 2 | # Transform Factors 3 | 4 | *** 5 | 6 | ```{r echo = FALSE, results='asis'} 7 | build_toc("07-transform-factors.Rmd") 8 | ``` 9 | 10 | *** 11 | 12 | -------------------------------------------------------------------------------- /08-transform-dates.Rmd: -------------------------------------------------------------------------------- 1 | 2 | # Transform Dates and Times 3 | 4 | *** 5 | 6 | ```{r echo = FALSE, results='asis'} 7 | build_toc("08-transform-dates.Rmd") 8 | ``` 9 | 10 | *** 11 | 12 | -------------------------------------------------------------------------------- /09-visualize-data.Rmd: -------------------------------------------------------------------------------- 1 | # Visualize Data 2 | 3 | *** 4 | 5 | ```{r echo = FALSE, results='asis'} 6 | build_toc("09-visualize-data.Rmd") 7 | ``` 8 | 9 | *** 10 | 11 | ## What you should know before you begin {-} 12 | 13 | ```{block2, type='rmdcaution'} 14 | The ggplot2 package provides the most important tidyverse functions for making plots. These functions let you use the [layered grammar of graphics](https://r4ds.had.co.nz/data-visualisation.html#the-layered-grammar-of-graphics) to describe the plot you wish to make. In theory, you can describe _any_ plot with the layered grammar of graphics. 15 | 16 | To use ggplot2, you build and then extend the graph template described in [Make a plot]. ggplot is loaded when you run `library(tidyverse)`. 17 | ``` 18 | 19 | ## Make a plot 20 | 21 | You want to make a plot. 22 | 23 | #### Solution {-} 24 | 25 | ```{r} 26 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 27 | geom_point() 28 | ``` 29 | 30 | #### Discussion {-} 31 | 32 | Use the same code template to begin _any_ plot: 33 | 34 | ```{r eval = FALSE} 35 | ggplot(data = , mapping = aes(x = , y = )) + 36 | () 37 | ``` 38 | 39 | Replace ``, ``, `` and `` with the data set, column names within that data set, and [geom_function][Make a specific "type" of plot, like a line plot, bar chart, etc.] that you'd like to use in your plot. Within ggplot2 code, you should _not_ surround column names with quotes. 40 | 41 | The `geom_point()` function above will create a scatterplot. Notice that some type of plots, like a histogram, will not require a y variable, e.g. 42 | 43 | ```{r} 44 | ggplot(data = mpg, mapping = aes(x = cty)) + 45 | geom_histogram() 46 | ``` 47 | 48 | ```{block2, type='rmdcaution'} 49 | When using the ggplot2 template, be sure to put each `+` at the _end_ of the line it follows and never at the beginning of the line that follows it. 50 | ``` 51 | 52 | ## Make a specific "type" of plot, like a line plot, bar chart, etc. 53 | 54 | You want to make a plot that is not a scatterplot, as in the [Make a plot] recipe. 55 | 56 | #### Solution {-} 57 | 58 | ```{r} 59 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 60 | geom_line() 61 | ``` 62 | 63 | #### Discussion {-} 64 | 65 | The `` in the [ggplot2 code template][Make a plot] determines which type of plot R will draw. So use the geom function that corresponds to the type of plot you have in mind. A complete list of geom functions can be found in the [ggplot2 cheatsheet](https://github.com/rstudio/cheatsheets/raw/master/data-visualization-2.1.pdf) or at the [ggplot2 package website](https://ggplot2.tidyverse.org/reference/index.html). 66 | 67 | Geom is short for _geometric object_. It refers to the type of visual mark your plot uses to represent data. 68 | 69 | 70 | ## Add a variable to a plot as a color, shape, etc. 71 | 72 | You want to add a new variable your plot that will appear as a color, shape, line type or some other visual element accompanied by a legend. 73 | 74 | #### Solution {-} 75 | 76 | ```{r} 77 | ggplot( 78 | data = mpg, 79 | mapping = aes(x = displ, y = hwy, color = class, size = cty) 80 | ) + 81 | geom_point() 82 | ``` 83 | 84 | #### Discussion {-} 85 | 86 | In the language of ggplot2, visual elements, like color, are called _aesthetics_. Use the `mapping = aes()` argument of `ggplot` to map aesthetics to variables in the data set, like `class` and `cty`, in this example. Separate each new mapping with a comma. ggplot2 will automatically add a legend to the plot that explains which elements of the aesthetic correspond to which values of the variable. 87 | 88 | Different types of plots support different types of aesthetics. To determine which aesthetics you may use, read the aesthetics section of the help page of the plot's geom function, e.g. `?geom_point`. 89 | 90 | ```{block2, type='rmdcaution'} 91 | Aesthetic mappings must be defined inside of the `aes()` helper function, which preprocesses them to pass to ggplot2. 92 | ``` 93 | 94 | ## Add multiple layers to a plot 95 | 96 | You want to add multiple layers of data to your plot. For example, you want to overlay a trend line on top of a scatterplot. 97 | 98 | #### Solution {-} 99 | 100 | ```{r} 101 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 102 | geom_point() + 103 | geom_smooth() 104 | ``` 105 | 106 | #### Discussion {-} 107 | 108 | To add new layers to a plot, add new geom functions to the end of the plot's [ggplot2 code template][Make a plot]. Each new geom will be drawn _on top_ of the previous geoms in the same coordinate space. 109 | 110 | ```{block2, type='rmdcaution'} 111 | Be sure to put each `+` at the _end_ of the line it follows and never at the beginning of the line that follows it. 112 | ``` 113 | 114 | When you use multiple geoms, data and mappings defined in `ggplot()` are applied _globally_ to each geom. You may also define data and mappings within each geom function. These will be applied locally to only the geom in which they are defined. For that geom, local mappings will override and extend global ones, e.g. 115 | 116 | ```{r} 117 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 118 | geom_point(mapping = aes(color = class)) + 119 | geom_smooth() 120 | ``` 121 | 122 | ## Subdivide a plot into multiple subplots 123 | 124 | You want to make a collection of subplots that each display a different part of the data set. 125 | 126 | #### Solution {-} 127 | 128 | ```{r} 129 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 130 | geom_point() + 131 | facet_wrap(~class) 132 | ``` 133 | 134 | #### Discussion {-} 135 | 136 | In ggplot2 vocabulary, subplots are called _facets_. Each subplot shares the same x and y variables, which facilitates comparison. 137 | 138 | Use one of two functions to facet your plot.`facet_wrap()` creates a separate subplot for each value of a variable. Pass the variable to `facet_wrap()` preceded by a `~`. 139 | 140 | `facet_grid()` creates a grid of facets based on the combinations of values of _two_ variables. Pass `facet_grid()` two variables separated by a `~`, e.g. 141 | 142 | ```{r} 143 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 144 | geom_point() + 145 | facet_grid(cyl ~ fl) 146 | ``` 147 | 148 | 149 | ## Add a title, subtitle, or caption to a plot 150 | 151 | You want to add a title and subtitle above your plot, and/or a caption below it. 152 | 153 | #### Solution {-} 154 | 155 | ```{r} 156 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 157 | geom_point() + 158 | labs( 159 | title = "Engine size vs. Fuel efficiency", 160 | subtitle = "Fuel efficiency estimated for highway driving", 161 | caption = "Data from fueleconomy.gov" 162 | ) 163 | ``` 164 | 165 | #### Discussion {-} 166 | 167 | The `labs()` function adds labels to ggplot2 plots. Each argument of `labs()` is optional. Labels should be provided as character strings. 168 | 169 | ## Change the axis labels of a plot 170 | 171 | You want to change the names of the x and y axes. 172 | 173 | #### Solution {-} 174 | 175 | ```{r} 176 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 177 | geom_point() + 178 | labs( 179 | title = "Engine size vs. Fuel efficiency", 180 | x = "Engine Displacement (L)", 181 | y = "Fuel Efficiency (MPG)" 182 | ) 183 | ``` 184 | 185 | #### Discussion {-} 186 | 187 | By default, ggplot2 labels the x and y axes with the names of the variables mapped to the axes. Override this with the `x` and `y` arguments of `labs()`. 188 | 189 | ## Change the title of a legend 190 | 191 | You want to change the title of a legend. 192 | 193 | #### Solution {-} 194 | 195 | ```{r} 196 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = class)) + 197 | geom_point() + 198 | labs(color = "Type of car") 199 | ``` 200 | 201 | #### Discussion {-} 202 | 203 | ggplot2 creates a legend for each aesthetic except for `x`, `y`, and `group`. By default, ggplot2 labels the legend with the name of the variable mapped to the aesthetic. To override this, add the `labs()` function to your template and pass a character string to the aesthetic whose legend you want to relabel. 204 | 205 | Use a `\n` to place a line break in the title, e.g. 206 | 207 | ```{r} 208 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = class)) + 209 | geom_point() + 210 | labs(color = "Type of\ncar") 211 | ``` 212 | 213 | ## Change the names within a legend 214 | 215 | You want to change the value labels that appear within a legend. 216 | 217 | #### Solution {-} 218 | 219 | ```{r} 220 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = class)) + 221 | geom_point() + 222 | scale_color_discrete(labels = c("Two seater", "Compact" ,"Sedan", "Minivan", "Truck", "Subcompact", "SUV")) 223 | ``` 224 | 225 | #### Discussion {-} 226 | 227 | To change the labels within a legend, you must interact with ggplot2's [scale system](https://r4ds.had.co.nz/graphics-for-communication.html#scales). To do this: 228 | 229 | 1. Determine which scale the plot will use. This will be a function whose name is composed of `scale_`, followed by the name of an aesthetic, followed by `_`, followed by an identifier, often `discrete` or `continuous`. 230 | 1. Explicitly add the scale to your code template 231 | 1. Set the labels argument of the scale to a vector of character strings, one for each label in the legend. 232 | 233 | ## Remove the legend from a plot 234 | 235 | You want to remove the legend from a ggplot2 plot. 236 | 237 | #### Solution {-} 238 | 239 | ```{r} 240 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = class)) + 241 | geom_point() + 242 | theme(legend.position = "none") 243 | ``` 244 | 245 | #### Discussion {-} 246 | 247 | To suppress legends, add `theme()` to the end of your [ggplot2 code template][Make a plot]. Pass it the argument `legend.position = "none"`. 248 | 249 | ## Change the appearance or look of a plot 250 | 251 | You want to change the appearance of the _non-data_ elements of your plot. 252 | 253 | #### Solution {-} 254 | 255 | ```{r} 256 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = class)) + 257 | geom_point() + 258 | theme_bw() 259 | ``` 260 | 261 | #### Discussion {-} 262 | 263 | The appearance of the non-data elements of a ggplot2 plot are controlled by a _theme_. To give your plot a theme, add a theme function to your [ggplot2 code template][Make a plot]. ggplot2 comes with nine theme functions, `theme_grey()`, `theme_bw()`, `theme_linedraw()`, `theme_light()`, `theme_dark()`, `theme_minimal()`, `theme_classic()`, `theme_void()`, `theme_test()`, and more can be loaded from the [ggthemes package](https://jrnold.github.io/ggthemes/reference/index.html). 264 | 265 | Use the `theme()` function to tweak individual elements of the active theme as in [Remove the legend from a plot]. 266 | 267 | ## Change the colors used in a plot 268 | 269 | You want to change the colors that you plot uses to display data. 270 | 271 | #### Solution {-} 272 | 273 | ```{r} 274 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = class)) + 275 | geom_point() + 276 | scale_color_brewer(palette = "Spectral") 277 | ``` 278 | 279 | #### Discussion {-} 280 | 281 | ggplot2 uses colors for both the `color` and `fill` aesthetics. Determine which one you are using, and then add a new color of fill scale with ggplot2's [scale system](https://r4ds.had.co.nz/graphics-for-communication.html#scales). See the [ggplot2 website](https://ggplot2.tidyverse.org/reference/index.html) for a list of available scales. Additional scales are available in the [ggthemes package](https://jrnold.github.io/ggthemes/reference/index.html). 282 | 283 | `scale_color_brewer()`/`scale_fill_brewer()` (for discrete data) and `scale_color_distill()`/`scale_fill_distill()` (for continuous data) are popular choices for pleasing color schemes. Each takes a `palette` argument that can be set to the name of any of the scales displayed below 284 | 285 | ```{r fig.height = 8} 286 | # install.packages(RColorBrewer) 287 | library(RColorBrewer) 288 | display.brewer.all() 289 | ``` 290 | 291 | `scale_color_viridis_d()`/`scale_fill_viridis_d()` (for discrete data) and `scale_color_viridis()_c`/`scale_fill_viridis()_c` (for continuous data) are another popular choice for continuous data. Each takes an `option` argument that can be set to one of the palette names below. 292 | 293 | ```{r echo = FALSE} 294 | knitr::include_graphics(rep('images/viridis.png')) 295 | ``` 296 | 297 | The [`ggsci`](https://nanx.me/ggsci/) and [`wesanderson`](https://github.com/karthik/wesanderson) packages also provide popular color scales. 298 | 299 | ## Change the range of the x or y axis 300 | 301 | You want to change the range of the x or y axes, effectively zooming in or out on your data. 302 | 303 | #### Solution {-} 304 | 305 | ```{r} 306 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 307 | geom_point() + 308 | geom_smooth() + 309 | coord_cartesian(xlim = c(5, 7), ylim = c(20, 30)) 310 | ``` 311 | 312 | #### Discussion {-} 313 | 314 | Each ggplot2 plot uses a coordinate system, which can be set by adding a `coord_` function to the [ggplot2 code template][Make a plot]. If you do add a `coord_` function, ggplot2 will use `coord_cartesian()` whihc provides a cartesian coordinate system. 315 | 316 | To change the range of a plot, set one or both of the `xlim` and `ylim` arguments of its `coord_` function. Each argument taxes a vector of length two: the minimum and maximum values for the range of the x or y axis. 317 | 318 | ## Use polar coordinates 319 | 320 | You want to make a polar plot, e.g. one that uses polar coordinates. 321 | 322 | #### Solution {-} 323 | 324 | ```{r} 325 | ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + 326 | geom_point() + 327 | coord_polar(theta = "x") 328 | ``` 329 | 330 | #### Discussion {-} 331 | 332 | To draw a plot in a polar coordinate system, add `coord_polar()` to the [ggplot2 code template][Make a plot]. Set the `theta` argument to `"x"` or `"y"` to indicate which axis should be mapped to the angle of the polar coordinate system (defaults to `"x"`). 333 | 334 | ## Flip the x and y axes 335 | 336 | You want to flip the plot along its diagonal, swapping the locations of the x and y axes. 337 | 338 | #### Solution {-} 339 | 340 | ```{r} 341 | ggplot(data = diamonds, mapping = aes(x = cut)) + 342 | geom_bar() + 343 | coord_flip() 344 | ``` 345 | 346 | #### Discussion {-} 347 | 348 | To flip a plot, add `coord_flip()` to the [ggplot2 code template][Make a plot]. This swaps the locations of the x and y axes and keeps the correct orientation of all words. 349 | 350 | `coord_flip()` has a different effect from merely exchanging the x and y variables. For example, you can use it to make bars and boxplots extend horizontally instead of vertically. 351 | 352 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: tidyverse-cookbook 2 | Title: The Tidyverse Cookbook 3 | Version: 0.1 4 | Authors@R: person("Garrett", "Grolemund", , "garrett@rstudio.com", "aut") 5 | Depends: R (>= 3.1.0) 6 | URL: https://github.com/rstudio-education/htidyverse-cookbook 7 | Imports: 8 | bookdown, 9 | knitr, 10 | rmarkdown, 11 | tidyverse, 12 | repurrrsive, 13 | knitrhooks 14 | Remotes: 15 | rstudio/bookdown, 16 | nathaneastwood/knitrhooks 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Tidyverse Cookbook 2 | 3 | [![Travis build status](https://travis-ci.org/rstudio-education/tidyverse-cookbook.svg?branch=master)](https://travis-ci.org/rstudio-education/tidyverse-cookbook) 4 | 5 | This is the development website for __The Tidyverse Cookbook__, a collection of user contributed Tidyverse code recipes. 6 | 7 | * Read the online version of the book [here](https://rstudio-education.github.io/tidyverse-cookbook/). 8 | * Request a recipe [here](https://github.com/rstudio-education/tidyverse-cookbook/issues). 9 | 10 | The book is in very early stages of development, which means that we are hard at work making the initial coverage, quality, and taxonomy as good as possible! We hope to one soon open the book to the community, so that anyone can submit a recipe in the form of a pull request. Until then, if you see this message in the README **please refrain from submitting pull requests.** 11 | -------------------------------------------------------------------------------- /_bookdown.yml: -------------------------------------------------------------------------------- 1 | book_filename: "tidyverse-cookbook" 2 | edit: "https://github.com/rstudio-education/tidyverse-cookbook/edit/main/%s" 3 | delete_merged_file: true 4 | before_chapter_script: "setup.R" 5 | 6 | rmd_files: [ 7 | "index.Rmd", 8 | "00-how-to-use-this-book.Rmd", 9 | "01-program.Rmd", 10 | "02-import.Rmd", 11 | "03-tidy.Rmd", 12 | "04-transform-tables.Rmd", 13 | "05-transform-lists.Rmd", 14 | "06-transform-strings.Rmd", 15 | "07-transform-factors.Rmd", 16 | "08-transform-dates.Rmd", 17 | "09-visualize-data.Rmd" 18 | ] 19 | 20 | output_dir: "docs" 21 | -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-10-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-10-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-12-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-12-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-14-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-14-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-15-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-15-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-17-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-17-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-19-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-19-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-20-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-20-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-209-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-209-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-21-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-21-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-211-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-211-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-213-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-213-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-214-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-214-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-216-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-216-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-218-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-218-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-219-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-219-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-22-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-22-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-220-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-220-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-221-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-221-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-222-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-222-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-223-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-223-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-224-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-224-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-225-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-225-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-226-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-226-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-227-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-227-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-228-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-228-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-229-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-229-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-23-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-23-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-230-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-230-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-231-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-231-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-232-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-232-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-233-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-233-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-234-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-234-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-235-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-235-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-236-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-236-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-237-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-237-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-238-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-238-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-239-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-239-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-24-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-24-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-240-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-240-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-241-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-241-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-242-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-242-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-243-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-243-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-244-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-244-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-245-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-245-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-246-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-246-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-247-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-247-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-248-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-248-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-249-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-249-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-25-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-25-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-250-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-250-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-251-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-251-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-252-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-252-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-253-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-253-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-254-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-254-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-255-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-255-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-256-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-256-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-257-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-257-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-258-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-258-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-259-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-259-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-26-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-26-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-260-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-260-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-261-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-261-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-262-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-262-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-27-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-27-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-28-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-28-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-29-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-29-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-30-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-30-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-32-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-32-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-33-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-33-1.png -------------------------------------------------------------------------------- /_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-34-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/_bookdown_files/tidyverse-cookbook_files/figure-html/unnamed-chunk-34-1.png -------------------------------------------------------------------------------- /_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ev 4 | 5 | Rscript -e 'bookdown::render_book("index.Rmd")' -------------------------------------------------------------------------------- /_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | [ -z "${GITHUB_PAT}" ] && exit 0 6 | [ "${TRAVIS_BRANCH}" != "master" ] && exit 0 7 | 8 | git config --global user.email "grolemund@gmail.com" 9 | git config --global user.name "Garrett Grolemund" 10 | 11 | # clone the repository to the book-output directory 12 | git clone -b gh-pages \ 13 | https://${GITHUB_PAT}@github.com/${TRAVIS_REPO_SLUG}.git \ 14 | book-output 15 | cd book-output 16 | git rm -rf * 17 | cp -r ../docs/* ./ 18 | git add --all * 19 | git commit -m"Update the book" 20 | git push -q origin gh-pages 21 | -------------------------------------------------------------------------------- /_output.yml: -------------------------------------------------------------------------------- 1 | bookdown::gitbook: 2 | config: 3 | toc: 4 | collapse: section 5 | before: | 6 |
  • A Tidyverse Cookbook
  • 7 | after: | 8 |
  • Published with bookdown
  • 9 | edit: 10 | link: https://github.com/rstudio-education/tidyverse-cookbook/edit/master/%s 11 | text: "Edit" 12 | css: style.css 13 | toc_depth: 1 14 | -------------------------------------------------------------------------------- /book.bib: -------------------------------------------------------------------------------- 1 | @Book{xie2015, 2 | title = {Dynamic Documents with {R} and knitr}, 3 | author = {Yihui Xie}, 4 | publisher = {Chapman and Hall/CRC}, 5 | address = {Boca Raton, Florida}, 6 | year = {2015}, 7 | edition = {2nd}, 8 | note = {ISBN 978-1498716963}, 9 | url = {http://yihui.name/knitr/}, 10 | } 11 | -------------------------------------------------------------------------------- /data/mtcars.csv: -------------------------------------------------------------------------------- 1 | mpg,cyl,disp,hp,drat,wt,qsec,vs,am,gear,carb 2 | 21,6,160,110,3.9,2.62,16.46,0,1,4,4 3 | 21,6,160,110,3.9,2.875,17.02,0,1,4,4 4 | 22.8,4,108,93,3.85,2.32,18.61,1,1,4,1 5 | 21.4,6,258,110,3.08,3.215,19.44,1,0,3,1 6 | 18.7,8,360,175,3.15,3.44,17.02,0,0,3,2 7 | 18.1,6,225,105,2.76,3.46,20.22,1,0,3,1 8 | 14.3,8,360,245,3.21,3.57,15.84,0,0,3,4 9 | 24.4,4,146.7,62,3.69,3.19,20,1,0,4,2 10 | 22.8,4,140.8,95,3.92,3.15,22.9,1,0,4,2 11 | 19.2,6,167.6,123,3.92,3.44,18.3,1,0,4,4 12 | 17.8,6,167.6,123,3.92,3.44,18.9,1,0,4,4 13 | 16.4,8,275.8,180,3.07,4.07,17.4,0,0,3,3 14 | 17.3,8,275.8,180,3.07,3.73,17.6,0,0,3,3 15 | 15.2,8,275.8,180,3.07,3.78,18,0,0,3,3 16 | 10.4,8,472,205,2.93,5.25,17.98,0,0,3,4 17 | 10.4,8,460,215,3,5.424,17.82,0,0,3,4 18 | 14.7,8,440,230,3.23,5.345,17.42,0,0,3,4 19 | 32.4,4,78.7,66,4.08,2.2,19.47,1,1,4,1 20 | 30.4,4,75.7,52,4.93,1.615,18.52,1,1,4,2 21 | 33.9,4,71.1,65,4.22,1.835,19.9,1,1,4,1 22 | 21.5,4,120.1,97,3.7,2.465,20.01,1,0,3,1 23 | 15.5,8,318,150,2.76,3.52,16.87,0,0,3,2 24 | 15.2,8,304,150,3.15,3.435,17.3,0,0,3,2 25 | 13.3,8,350,245,3.73,3.84,15.41,0,0,3,4 26 | 19.2,8,400,175,3.08,3.845,17.05,0,0,3,2 27 | 27.3,4,79,66,4.08,1.935,18.9,1,1,4,1 28 | 26,4,120.3,91,4.43,2.14,16.7,0,1,5,2 29 | 30.4,4,95.1,113,3.77,1.513,16.9,1,1,5,2 30 | 15.8,8,351,264,4.22,3.17,14.5,0,1,5,4 31 | 19.7,6,145,175,3.62,2.77,15.5,0,1,5,6 32 | 15,8,301,335,3.54,3.57,14.6,0,1,5,8 33 | 21.4,4,121,109,4.11,2.78,18.6,1,1,4,2 34 | -------------------------------------------------------------------------------- /images/caution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/caution.png -------------------------------------------------------------------------------- /images/data-science-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/data-science-workflow.png -------------------------------------------------------------------------------- /images/data-wrangling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/data-wrangling.png -------------------------------------------------------------------------------- /images/dplyr-anti-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-anti-join.png -------------------------------------------------------------------------------- /images/dplyr-arrange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-arrange.png -------------------------------------------------------------------------------- /images/dplyr-desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-desc.png -------------------------------------------------------------------------------- /images/dplyr-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-filter.png -------------------------------------------------------------------------------- /images/dplyr-full-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-full-join.png -------------------------------------------------------------------------------- /images/dplyr-group_by.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-group_by.png -------------------------------------------------------------------------------- /images/dplyr-groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-groups.png -------------------------------------------------------------------------------- /images/dplyr-inner-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-inner-join.png -------------------------------------------------------------------------------- /images/dplyr-left-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-left-join.png -------------------------------------------------------------------------------- /images/dplyr-mutate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-mutate.png -------------------------------------------------------------------------------- /images/dplyr-pipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-pipe.png -------------------------------------------------------------------------------- /images/dplyr-pull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-pull.png -------------------------------------------------------------------------------- /images/dplyr-rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-rename.png -------------------------------------------------------------------------------- /images/dplyr-right-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-right-join.png -------------------------------------------------------------------------------- /images/dplyr-select-drop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-select-drop.png -------------------------------------------------------------------------------- /images/dplyr-select-everything.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-select-everything.png -------------------------------------------------------------------------------- /images/dplyr-select-range.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-select-range.png -------------------------------------------------------------------------------- /images/dplyr-select-reorder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-select-reorder.png -------------------------------------------------------------------------------- /images/dplyr-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-select.png -------------------------------------------------------------------------------- /images/dplyr-semi-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-semi-join.png -------------------------------------------------------------------------------- /images/dplyr-summarise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-summarise.png -------------------------------------------------------------------------------- /images/dplyr-summary-functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-summary-functions.png -------------------------------------------------------------------------------- /images/dplyr-vectorized-functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/dplyr-vectorized-functions.png -------------------------------------------------------------------------------- /images/import-dataset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/import-dataset.png -------------------------------------------------------------------------------- /images/import-wizard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/import-wizard.png -------------------------------------------------------------------------------- /images/important.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/important.png -------------------------------------------------------------------------------- /images/note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/note.png -------------------------------------------------------------------------------- /images/purrr-map-goal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/purrr-map-goal.png -------------------------------------------------------------------------------- /images/purrr-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/purrr-map.png -------------------------------------------------------------------------------- /images/purrr-pluck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/purrr-pluck.png -------------------------------------------------------------------------------- /images/readr-csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/readr-csv.png -------------------------------------------------------------------------------- /images/readr-csv2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/readr-csv2.png -------------------------------------------------------------------------------- /images/readr-delim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/readr-delim.png -------------------------------------------------------------------------------- /images/readr-fwf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/readr-fwf.png -------------------------------------------------------------------------------- /images/readr-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/readr-header.png -------------------------------------------------------------------------------- /images/readr-missing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/readr-missing.png -------------------------------------------------------------------------------- /images/readr-nmax.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/readr-nmax.png -------------------------------------------------------------------------------- /images/readr-skip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/readr-skip.png -------------------------------------------------------------------------------- /images/readr-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/readr-tab.png -------------------------------------------------------------------------------- /images/tibble-tibble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tibble-tibble.png -------------------------------------------------------------------------------- /images/tidy-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tidy-data.png -------------------------------------------------------------------------------- /images/tidyr-gather.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tidyr-gather.png -------------------------------------------------------------------------------- /images/tidyr-nest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tidyr-nest.png -------------------------------------------------------------------------------- /images/tidyr-separate-rows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tidyr-separate-rows.png -------------------------------------------------------------------------------- /images/tidyr-separate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tidyr-separate.png -------------------------------------------------------------------------------- /images/tidyr-spread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tidyr-spread.png -------------------------------------------------------------------------------- /images/tidyr-unite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tidyr-unite.png -------------------------------------------------------------------------------- /images/tidyr-unnest-single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tidyr-unnest-single.png -------------------------------------------------------------------------------- /images/tidyr-unnest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tidyr-unnest.png -------------------------------------------------------------------------------- /images/tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/tip.png -------------------------------------------------------------------------------- /images/viridis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/viridis.png -------------------------------------------------------------------------------- /images/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rstudio-education/tidyverse-cookbook/3ee71665279de13033bde4c877c34effab9cc89c/images/warning.png -------------------------------------------------------------------------------- /index.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The Tidyverse Cookbook" 3 | author: "Edited by Garrett Grolemund" 4 | date: "`r Sys.Date()`" 5 | site: bookdown::bookdown_site 6 | github-repo: rstudio-education/tidyverse-cookbook 7 | documentclass: book 8 | description: "How to solve common data science tasks with R's Tidyverse" 9 | --- 10 | 11 | # Welcome {-} 12 | 13 | 18 | 19 | This book collects code recipes for doing data science with R's [tidyverse](#what-is-the-tidyverse). Each recipe solves a single common task, with a minimum of discussion. Everything in this book is licensed under the permissive [Creative Commons 4.0 International License](https://creativecommons.org/licenses/by/4.0/). We encourage you to reuse and adapt the recipes. 20 | 21 | ## Legal disclaimer {-} 22 | 23 | I believe that each recipe in this book works as advertised, but be aware that the recipes come with the same warranty as R: ABSOLUTELY NO WARRANTY. 24 | 25 | *** 26 | 27 | The online version of this book is licensed under the [Creative Commons 4.0 International License](https://creativecommons.org/licenses/by/4.0/). 28 | 29 | -------------------------------------------------------------------------------- /packages.bib: -------------------------------------------------------------------------------- 1 | @Manual{R-base, 2 | title = {R: A Language and Environment for Statistical Computing}, 3 | author = {{R Core Team}}, 4 | organization = {R Foundation for Statistical Computing}, 5 | address = {Vienna, Austria}, 6 | year = {2018}, 7 | url = {https://www.R-project.org/}, 8 | } 9 | @Manual{R-bookdown, 10 | title = {bookdown: Authoring Books and Technical Documents with R Markdown}, 11 | author = {Yihui Xie}, 12 | year = {2018}, 13 | note = {R package version 0.7}, 14 | url = {https://CRAN.R-project.org/package=bookdown}, 15 | } 16 | @Manual{R-knitr, 17 | title = {knitr: A General-Purpose Package for Dynamic Report Generation in R}, 18 | author = {Yihui Xie}, 19 | year = {2018}, 20 | note = {R package version 1.20}, 21 | url = {https://CRAN.R-project.org/package=knitr}, 22 | } 23 | @Manual{R-rmarkdown, 24 | title = {rmarkdown: Dynamic Documents for R}, 25 | author = {JJ Allaire and Yihui Xie and Jonathan McPherson and Javier Luraschi and Kevin Ushey and Aron Atkins and Hadley Wickham and Joe Cheng and Winston Chang}, 26 | year = {2018}, 27 | note = {R package version 1.10}, 28 | url = {https://CRAN.R-project.org/package=rmarkdown}, 29 | } 30 | -------------------------------------------------------------------------------- /preamble.tex: -------------------------------------------------------------------------------- 1 | \usepackage{booktabs} 2 | -------------------------------------------------------------------------------- /setup.R: -------------------------------------------------------------------------------- 1 | # setup.R 2 | 3 | library(tidyverse, 4 | verbose = FALSE, 5 | quietly = TRUE, 6 | warn.conflicts = FALSE) 7 | 8 | build_toc <- function(filename) { 9 | text <- read_file(filename) 10 | recipes <- text %>% 11 | stringr::str_extract_all("\\n##\\s.+\\n") %>% 12 | pluck(1) %>% 13 | `[`(-1) %>% 14 | stringr::str_replace_all("\\s\\{.*\\}", "") %>% 15 | stringr::str_replace_all("\\n##\\s", "1. [") %>% 16 | stringr::str_replace_all("\\n", "]") 17 | headers <- paste(recipes, collapse = "\n") 18 | cat("
    \n", headers, "\n
    ") 19 | } -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | p.caption { 2 | color: #777; 3 | margin-top: 10px; 4 | } 5 | p code { 6 | white-space: inherit; 7 | } 8 | pre { 9 | word-break: normal; 10 | word-wrap: normal; 11 | } 12 | pre code { 13 | white-space: inherit; 14 | } 15 | 16 | .rmdcaution, .rmdimportant, .rmdnote, .rmdtip, .rmdwarning { 17 | padding: 1em 1em 1em 4em; 18 | margin-bottom: 10px; 19 | background: #f5f5f5 5px center/3em no-repeat; 20 | } 21 | .rmdcaution { 22 | background-image: url("images/caution.png"); 23 | } 24 | .rmdimportant { 25 | background-image: url("images/important.png"); 26 | } 27 | .rmdnote { 28 | background-image: url("images/note.png"); 29 | } 30 | .rmdtip { 31 | background-image: url("images/tip.png"); 32 | } 33 | .rmdwarning { 34 | background-image: url("images/warning.png"); 35 | } 36 | 37 | .col2 { 38 | columns: 2 200px; /* number of columns and width in pixels*/ 39 | -webkit-columns: 2 200px; /* chrome, safari */ 40 | -moz-columns: 2 200px; /* firefox */ 41 | } 42 | .col3 { 43 | columns: 3 100px; 44 | -webkit-columns: 3 100px; 45 | -moz-columns: 3 100px; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /tidyverse-recipes.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Website 16 | --------------------------------------------------------------------------------