forked from NUstat/intro-stat-data-sci
-
Notifications
You must be signed in to change notification settings - Fork 0
/
04-tidy.qmd
536 lines (372 loc) · 29.6 KB
/
04-tidy.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
# Data Importing & "Tidy Data" {#sec-tidy}
```{r}
#| label: setup_tidy
#| include: false
# for number learning checks
chap <- 4
lc <- 0
# `r paste0(chap, ".", (lc <- lc + 1))`
knitr::opts_chunk$set(
tidy = FALSE,
out.width = '\\textwidth',
fig.height = 4,
fig.align='center',
warning = FALSE,
message = FALSE
)
options(scipen = 99, digits = 3)
# In knitr::kable printing replace all NA's with blanks
options(knitr.kable.NA = '')
# Set random number generator see value for replicable pseudorandomness. Why 76?
# https://www.youtube.com/watch?v=xjJ7FheCkCU
set.seed(76)
```
In [Subsection -@sec-programming-concepts)] we introduced the concept of a data frame: a rectangular spreadsheet-like representation of data in R where the rows correspond to observations and the columns correspond to variables describing each observation. In @sec-nycflights13, we started exploring our first data frame: the `flights` data frame included in the `nycflights13` package. In @sec-viz we created visualizations based on the data included in `flights` and other data frames such as `weather`. In @sec-wrangling, we learned how to wrangle data, in other words take existing data frames and transform/ modify them to suit our analysis goals.
In this final chapter of the "Data Science via the tidyverse" portion of the book, we extend some of these ideas by discussing a type of data formatting called "tidy" data. You will see that having data stored in "tidy" format is about more than what the colloquial definition of the term "tidy" might suggest: having your data "neatly organized." Instead, we define the term "tidy" in a more rigorous fashion, outlining a set of rules by which data can be stored, and the implications of these rules for analyses.
Although knowledge of this type of data formatting was not necessary for our treatment of data visualization in @sec-viz and data wrangling in @sec-wrangling since all the data was already in "tidy" format, we'll now see this format is actually essential to using the tools we covered in these two chapters. Furthermore, it will also be useful for all subsequent chapters in this book when we cover regression and statistical inference. First however, we'll show you how to import spreadsheet data for use in R.
## Packages Needed {.unnumbered}
Let's load all the packages needed for this chapter (this assumes you've already installed them). If needed, read @sec-packages for information on how to install and load R packages.
```{r}
library(dplyr)
library(ggplot2)
library(readr)
library(tidyr)
library(nycflights13)
library(fivethirtyeight)
```
```{r}
#| echo: false
# Packages needed internally, but not in text.
library(knitr)
library(kableExtra)
library(fivethirtyeight)
library(stringr)
```
## Importing data {#sec-csv}
Up to this point, we've almost entirely used data stored inside of an R package. Say instead you have your own data saved on your computer or somewhere online? How can you analyze this data in R? Spreadsheet data is often saved in one of the following formats:
* A *Comma Separated Values* `.csv` file. You can think of a `.csv` file as a bare-bones spreadsheet where:
+ Each line in the file corresponds to one row of data/one observation.
+ Values for each line are separated with commas. In other words, the values of different variables are separated by commas.
+ The first line is often, but not always, a *header* row indicating the names of the columns/variables.
* An Excel `.xlsx` file. This format is based on Microsoft's proprietary Excel software. As opposed to a bare-bones `.csv` files, `.xlsx` Excel files contain a lot of meta-data, or put more simply, data about the data. (Recall we saw a previous example of meta-data in @sec-groupby when adding "group structure" meta-data to a data frame by using the `group_by()` verb.) Some examples of spreadsheet meta-data include the use of bold and italic fonts, colored cells, different column widths, and formula macros.
* A [Google Sheets](https://www.google.com/sheets/about/) file, which is a "cloud" or online-based way to work with a spreadsheet. Google Sheets allows you to download your data in both comma separated values `.csv` and Excel `.xlsx` formats however: go to the Google Sheets menu bar -> File -> Download as -> Select "Microsoft Excel" or "Comma-separated values."
We'll cover two methods for importing `.csv` and `.xlsx` spreadsheet data in R: one using the R console and the other using RStudio's graphical user interface, abbreviated a GUI.
### Using the console
First, let's import a Comma Separated Values `.csv` file of data directly off the internet. The `.csv` file `dem_score.csv` accessible at <https://moderndive.com/data/dem_score.csv> contains ratings of the level of democracy in different countries spanning 1952 to 1992. Let's use the `read_csv()` function from the `readr` package to read it off the web, import it into R, and save it in a data frame called `dem_score`
```{r}
#| message: false
#| eval: false
library(readr)
dem_score <- read_csv("https://moderndive.com/data/dem_score.csv")
dem_score
```
```{r}
#| message: false
#| echo: false
dem_score <- read_csv("data/dem_score.csv")
dem_score
```
In this `dem_score` data frame, the minimum value of `-10` corresponds to a highly autocratic nation whereas a value of `10` corresponds to a highly democratic nation. We'll revisit the `dem_score` data frame in a case study in the upcoming @sec-case-study-tidy.
Note that the `read_csv()` function included in the `readr` package is different than the `read.csv()` function that comes installed with R by default. While the difference in the names might seem near meaningless (an `_` instead of a `.`), the `read_csv()` function is in our opinion easier to use since it can more easily read data off the web and generally imports data at a much faster speed.
### Using RStudio's interface
Let's read in the exact same data saved in Excel format, but this time via RStudio's graphical interface instead of via the R console. First download the Excel file `dem_score.xlsx` by clicking [here](https://moderndive.com/data/dem_score.xlsx), then
1. Go to the Files panel of RStudio.
2. Navigate to the directory i.e. folder on your computer where the downloaded `dem_score.xlsx` Excel file is saved.
3. Click on `dem_score.xlsx`.
4. Click "Import Dataset..."
At this point you should see an image like this:
![](images/read_excel.png)
After clicking on the "Import" button on the bottom right RStudio, RStudio will save this spreadsheet's data in a data frame called `dem_score` and display its contents in the spreadsheet viewer. Furthermore, note in the bottom right of the above image there exists a "Code Preview": you can copy and paste this code to reload your data again later automatically instead of repeating the above manual point-and-click process.
## Tidy data {#sec-tidy-data-ex}
Let's now switch gears and learn about the concept of "tidy" data format by starting with a motivating example. Let's consider the `drinks` data frame included in the `fivethirtyeight` data. Run the following:
```{r}
drinks
```
After reading the help file by running `?drinks`, we see that `drinks` is a data frame containing results from a survey of the average number of servings of beer, spirits, and wine consumed for 193 countries. This data was originally reported on the data journalism website FiveThirtyEight.com in Mona Chalabi's article ["Dear Mona Followup: Where Do People Drink The Most Beer, Wine And Spirits?"](https://fivethirtyeight.com/features/dear-mona-followup-where-do-people-drink-the-most-beer-wine-and-spirits/)
Let's apply some of the data wrangling verbs we learned in @sec-wrangling on the `drinks` data frame. Let's
1. `filter()` the `drinks` data frame to only consider 4 countries (the United States, China, Italy, and Saudi Arabia) then
1. `select()` all columns except `total_litres_of_pure_alcohol` by using `-` sign, then
1. `rename()` the variables `beer_servings`, `spirit_servings`, and `wine_servings` to `beer`, `spirit`, and `wine` respectively
and save the resulting data frame in `drinks_smaller`.
```{r}
drinks_smaller <- drinks %>%
filter(country %in% c("USA", "China", "Italy", "Saudi Arabia")) %>%
select(-total_litres_of_pure_alcohol) %>%
rename(beer = beer_servings, spirit = spirit_servings, wine = wine_servings)
drinks_smaller
```
Using the `drinks_smaller` data frame, how would we create the side-by-side AKA dodged barplot in @fig-drinks-smaller? Recall we saw barplots displaying two categorical variables in @sec-two-categ-barplot.
```{r}
#| label: fig-drinks-smaller
#| fig-cap: Alcohol consumption in 4 countries
#| fig-height: 3.5
#| echo: false
drinks_smaller_tidy <- drinks_smaller %>%
pivot_longer(cols = -country, names_to = "type", values_to = "servings")
ggplot(drinks_smaller_tidy, aes(x = country, y = servings, fill = type)) +
geom_col(position = "dodge") +
labs(x = "country", y = "servings")
```
Let's break down the Grammar of Graphics:
1. The categorical variable `country` with four levels (China, Italy, Saudi Arabia, USA) would have to be mapped to the `x`-position of the bars.
1. The numerical variable `servings` would have to be mapped to the `y`-position of the bars, in other words the height of the bars.
1. The categorical variable `type` with three levels (beer, spirit, wine) who have to be mapped to the `fill` color of the bars.
Observe however that `drinks_smaller` has *three separate variables* for `beer`, `spirit`, and `wine`, whereas in order to recreate the side-by-side AKA dodged barplot in @fig-drinks-smaller we would need a *single variable* `type` with three possible values: `beer`, `spirit`, and `wine`, which we would then map to the `fill` aesthetic. In other words, for us to be able to create the barplot in @fig-drinks-smaller, our data frame would have to look like this:
```{r}
drinks_smaller_tidy
```
Let's compare the `drinks_smaller_tidy` with the `drinks_smaller` data frame from earlier:
```{r}
drinks_smaller
```
Observe that while `drinks_smaller` and `drinks_smaller_tidy` are both rectangular in shape and contain the same 12 numerical values (3 alcohol types $\times$ 4 countries), they are formatted differently. `drinks_smaller` is formatted in what's known as ["wide"](https://en.wikipedia.org/wiki/Wide_and_narrow_data) format, whereas `drinks_smaller_tidy` is formatted in what's known as ["long/narrow"](https://en.wikipedia.org/wiki/Wide_and_narrow_data#Narrow). In the context of using R, long/narrow format is also known as "tidy" format. Furthermore, in order to use the `ggplot2` and `dplyr` packages for data visualization and data wrangling, your input data frames *must* be in "tidy" format. So all non-"tidy" data must be converted to "tidy" format first.
Before we show you how to convert non-"tidy" data frames like `drinks_smaller` to "tidy" data frames like `drinks_smaller_tidy`, let's go over the explicit definition of "tidy" data.
### Definition of "tidy" data
You have surely heard the word "tidy" in your life:
* "Tidy up your room!"
* "Please write your homework in a tidy way so that it is easier to grade and to provide feedback."
* Marie Kondo's best-selling book [_The Life-Changing Magic of Tidying Up: The Japanese Art of Decluttering and Organizing_](https://www.amazon.com/Life-Changing-Magic-Tidying-Decluttering-Organizing/dp/1607747308/ref=sr_1_1?ie=UTF8&qid=1469400636&sr=8-1&keywords=tidying+up) and Netflix TV series [_Tidying Up with Marie Kondo_](https://www.netflix.com/title/80209379).
* "I am not by any stretch of the imagination a tidy person, and the piles of unread books on the coffee table and by my bed have a plaintive, pleading quality to me - 'Read me, please!'" - Linda Grant
What does it mean for your data to be "tidy"? While "tidy" has a clear English meaning of "organized", "tidy" in the context of data science using R means that your data follows a standardized format. We will follow Hadley Wickham's definition of *tidy data* here [@tidy]:
> A dataset is a collection of values, usually either numbers (if quantitative)
or strings AKA text data (if qualitative). Values are organised in two ways.
Every value belongs to a variable and an observation. A variable contains all
values that measure the same underlying attribute (like height, temperature,
duration) across units. An observation contains all values measured on the same
unit (like a person, or a day, or a city) across attributes.
>
> Tidy data is a standard way of mapping the meaning of a dataset to its
structure. A dataset is messy or tidy depending on how rows, columns and tables
are matched up with observations, variables and types. In *tidy data*:
>
> 1. Each variable forms a column.
> 2. Each observation forms a row.
> 3. Each type of observational unit forms a table.
![Tidy data graphic from [R for Data Science](http://r4ds.had.co.nz/tidy-data.html)](images/tidy-1.png){fig-align="center"}
For example, say you have the following table of stock prices in @tbl-non-tidy-stocks:
```{r}
#| label: tbl-non-tidy-stocks
#| tbl-cap: "Stock Prices (Non-Tidy Format)"
#| echo: false
stocks <- tibble(
Date = as.Date('2009-01-01') + 0:4,
`Boeing Stock Price` = paste("$", c("173.55", "172.61", "173.86", "170.77", "174.29"), sep = ""),
`Amazon Stock Price` = paste("$", c("174.90", "171.42", "171.58", "173.89", "170.16"), sep = ""),
`Google Stock Price` = paste("$", c("174.34", "170.04", "173.65", "174.87", "172.19") ,sep = "")
) %>%
slice(1:2)
stocks %>%
kable(
digits = 2,
caption = "Stock Prices (Non-Tidy Format)",
booktabs = TRUE,
format = "markdown"
) %>%
kable_styling(
font_size = ifelse(knitr:::is_latex_output(), 10, 16),
latex_options = c("HOLD_position")
)
```
Although the data are neatly organized in a rectangular spreadsheet-type format, they are not in tidy format because while there are three variables corresponding to three unique pieces of information (Date, Stock Name, and Stock Price), there are not three columns. In "tidy" data format each variable should be its own column, as shown in @tbl-tidy-stocks). Notice that both tables present the same information, but in different formats.
```{r}
#| label: tbl-tidy-stocks
#| tbl-cap: "Stock Prices (Tidy Format)"
#| echo: false
stocks_tidy <- stocks %>%
rename(
Boeing = `Boeing Stock Price`,
Amazon = `Amazon Stock Price`,
Google = `Google Stock Price`
) %>%
pivot_longer(cols = -Date, names_to = "Stock Name", values_to = "Stock Price")
stocks_tidy %>%
kable(
digits = 2,
caption = "Stock Prices (Tidy Format)",
booktabs = TRUE,
format = "markdown"
) %>%
kable_styling(font_size = ifelse(knitr:::is_latex_output(), 10, 16),
latex_options = c("HOLD_position"))
```
Now we have the requisite three columns Date, Stock Name, and Stock Price. On the other hand, consider the data in @tbl-tidy-stocks-2.
```{r}
#| label: tbl-tidy-stocks-2
#| tbl-cap: "Date, Boeing Price, Weather Data"
#| echo: false
stocks <- tibble(
Date = as.Date('2009-01-01') + 0:4,
`Boeing Price` = paste("$", c("173.55", "172.61", "173.86", "170.77", "174.29"), sep = ""),
`Weather` = c("Sunny", "Overcast", "Rain", "Rain", "Sunny")
) %>%
slice(1:2)
stocks %>%
kable(
format = "markdown",
digits = 2,
caption = "Date, Boeing Price, Weather Data",
booktabs = TRUE
) %>%
kable_styling(font_size = ifelse(knitr:::is_latex_output(), 10, 16),
latex_options = c("HOLD_position"))
```
In this case, even though the variable "Boeing Price" occurs just like in our non-"tidy" data in @tbl-non-tidy-stocks), the data *is* "tidy" since there are three variables corresponding to three unique pieces of information: Date, Boeing stock price, and the weather that particular day.
:::{.callout-tip icon=false collapse=true}
## :dart: Learning Check `r paste0(chap, ".", (lc <- lc + 1))`
What are common characteristics of "tidy" data frames?
:::
:::{.callout-tip icon=false collapse=true}
## :dart: Learning Check `r paste0(chap, ".", (lc <- lc + 1))`
What makes "tidy" data frames useful for organizing data?
:::
### Converting to "tidy" data
In this book so far, you've only seen data frames that were already in "tidy" format. Furthermore for the rest of this book, you'll mostly only see data frames that are already in "tidy" format as well. This is not always the case however with data in the wild. If your original data frame is in wide i.e. non-"tidy" format and you would like to use the `ggplot2` package for data visualization or the `dplyr` package for data wrangling, you will first have to convert it to "tidy" format using the `pivot_longer()` function in the `tidyr` package [@R-tidyr].
Going back to our `drinks_smaller` data frame from earlier:
```{r}
drinks_smaller
```
We convert it to "tidy" format by using the `pivot_longer()` function from the `tidyr` package as follows:
```{r}
# tidy drinks_smaller
drinks_smaller_tidy <- drinks_smaller %>%
pivot_longer(
cols = -country,
names_to = "type",
values_to = "servings"
)
# print
drinks_smaller_tidy
```
We set the arguments to `pivot_longer()` as follows:
1. The first argument, `cols`, are the columns you either want to or don't want to tidy. Observe how we set this to `-country` indicating that we don't want to tidy the `country` variable in `drinks_smaller` which leaves `beer`, `spirit`, and `wine` to be tidied.
1. `names_to` is the name of the column/variable in the new "tidy" frame that contains the column names of the original data frame that you want to tidy. Observe how we set `names_to = "type"` and in the resulting `drinks_smaller_tidy` the column `type` contains the three types of alcohol `beer`, `spirit`, and `wine`.
1. `values_to` is the name of the column/variable in the "tidy" frame that contains the rows and columns of values in the original data frame you want to tidy. Observe how we set `values_to = "servings"` and in the resulting `drinks_smaller_tidy` the column `servings` contains the 4 $\times$ 3 = 12 numerical values.
The first argument, `cols`, is a little nuanced, so let's consider another example. Note the code below is very similar, but now the first argument species which columns we'd want to tidy `c(beer, spirit, wine)`, instead of the columns we don't want to tidy `-country`. Note the use of `c()` to create a vector of the columns in `drinks_smaller` that we'd like to tidy. If you run the code below, you'll see that the result is as `drinks_smaller_tidy`.
```{r}
#| eval: false
# tidy drinks_smaller
drinks_smaller %>%
pivot_longer(
cols = c(beer, spirit, wine),
names_to = "type",
values_to = "servings"
)
```
With our `drinks_smaller_tidy` "tidy" format data frame, we can now produce a side-by-side AKA dodged barplot using `geom_col()` and not `geom_bar()`, since we would like to map the `servings` variable to the `y`-aesthetic of the bars.
```{r}
ggplot(drinks_smaller_tidy, aes(x=country, y=servings, fill=type)) +
geom_col(position = "dodge")
```
Converting "wide" format data to "tidy" format often confuses new R users. The only way to learn to get comfortable with the `pivot_longer()` function is with practice, practice, and more practice. For example, see the examples in the bottom of the help file for `pivot_longer()` by running `?pivot_longer`. We'll show another example of using `pivot_longer()` to convert a "wide" formatted data frame to "tidy" format in @sec-case-study-tidy. For other examples of converting a dataset into "tidy" format, check out the different functions available for data tidying and a case study using data from the World Health Organization in [R for Data Science](http://r4ds.had.co.nz/tidy-data.html) [@rds2016].
:::{.callout-tip icon=false collapse=true}
## :dart: Learning Check `r paste0(chap, ".", (lc <- lc + 1))`
Take a look the `airline_safety` data frame included in the `fivethirtyeight` data. Run the following:
```{r}
#| eval: false
airline_safety
```
After reading the help file by running `?airline_safety`, we see that `airline_safety` is a data frame containing information on different airlines companies' safety records. This data was originally reported on the data journalism website FiveThirtyEight.com in Nate Silver's article ["Should Travelers Avoid Flying Airlines That Have Had Crashes in the Past?"](https://fivethirtyeight.com/features/should-travelers-avoid-flying-airlines-that-have-had-crashes-in-the-past/). Let's ignore the `incl_reg_subsidiaries` and `avail_seat_km_per_week` variables for simplicity:
```{r}
airline_safety_smaller <- airline_safety %>%
select(-c(incl_reg_subsidiaries, avail_seat_km_per_week))
airline_safety_smaller
```
This data frame is not in "tidy" format. How would you convert this data frame to be in "tidy" format, in particular so that it has a variable `incident_type_years` indicating the incident type/year and a variable `count` of the counts?
:::
### `nycflights13` package
Recall the `nycflights13` package with data about all domestic flights departing from New York City in 2013 that we introduced in @sec-nycflights13 and used extensively in @sec-viz on data visualization and @sec-wrangling on data wrangling. Let's revisit the `flights` data frame by running `View(flights)`. We saw that `flights` has a rectangular shape with each of its `r scales::comma(nrow(flights))` rows corresponding to a flight and each of its `r ncol(flights)` columns corresponding to different characteristics/measurements of each flight. This matches exactly with our definition of "tidy" data from above.
1. Each variable forms a column.
2. Each observation forms a row.
But what about the third property of "tidy" data?
> 3. Each type of observational unit forms a table.
Recall that we also saw in @sec-exploredataframes that the observational unit for the `flights` data frame is an individual flight. In other words, the rows of the `flights` data frame refer to characteristics/measurements of individual flights. Also included in the `nycflights13` package are other data frames with their rows representing different observational units [@R-nycflights13]:
* `airlines`: translation between two letter IATA carrier codes and names (`r nrow(nycflights13::airlines)` in total). i.e. the observational unit is an airline company.
* `planes`: construction information about each of `r scales::comma(nrow(nycflights13::planes))` planes used. i.e. the observational unit is an aircraft.
* `weather`: hourly meteorological data (about `r nycflights13::weather %>% count(origin) %>% .[["n"]] %>% mean() %>% round()` observations) for each of the three NYC airports. i.e. the observational unit is an hourly measurement.
* `airports`: airport names and locations. i.e. the observational unit is an airport.
The organization of the information into these five data frames follow the third "tidy" data property: observations corresponding to the same observational unit should be saved in the same table i.e. data frame. You could think of this property as the old English expression: "birds of a feather flock together."
## Case study: Democracy in Guatemala {#sec-case-study-tidy}
In this section, we'll show you another example of how to convert a data frame that isn't in "tidy" format i.e. "wide" format, to a data frame that is in "tidy" format i.e. "long/narrow" format. We'll do this using the `pivot_longer()` function from the `tidyr` package again. Furthermore, we'll make use of some of the `ggplot2` data visualization and `dplyr` data wrangling tools you learned in Chapters @sec-viz and @sec-wrangling.
Let's use the `dem_score` data frame we imported in @sec-csv, but focus on only data corresponding to Guatemala.
```{r}
guat_dem <- dem_score %>%
filter(country == "Guatemala")
guat_dem
```
Now let's produce a *time-series plot* showing how the democracy scores have changed over the 40 years from 1952 to 1992 for Guatemala. Recall that we saw time-series plot in @sec-linegraphs on creating linegraphs using `geom_line()`. Let's lay out the Grammar of Graphics we saw in @sec-grammarofgraphics.
First we know we need to set `data = guat_dem` and use a `geom_line()` layer, but what is the aesthetic mapping of variables. We'd like to see how the democracy score has changed over the years, so we need to map:
* `year` to the x-position aesthetic and
* `democracy_score` to the y-position aesthetic
Now we are stuck in a predicament, much like with our `drinks_smaller` example in sec-tidy-data-ex. We see that we have a variable named `country`, but its only value is `"Guatemala"`. We have other variables denoted by different year values. Unfortunately, the `guat_dem` data frame is not "tidy" and hence is not in the appropriate format to apply the Grammar of Graphics and thus we cannot use the `ggplot2` package. We need to take the values of the columns corresponding to years in `guat_dem` and convert them into a new "key" variable called `year`. Furthermore, we'd like to take the democracy scores on the inside of the table and turn them into a new "value" variable called `democracy_score`. Our resulting data frame will thus have three columns: `country`, `year`, and `democracy_score`.
Recall that the `pivot_longer()` function in the `tidyr` package can complete this task for us:
```{r}
guat_dem_tidy <- guat_dem %>%
pivot_longer(
cols = -country,
names_to = "year",
values_to = "democracy_score"
)
guat_dem_tidy
```
We set the arguments to `pivot_longer()` as follows:
1. The first argument, `cols`, indicatesthe columns you either want to or don't want to tidy. Observe how we set this to `-country` indicating that we don't want to tidy the `country` variable in `guat_dem` which leaves `1952` through `1992` to be tidied.
1. `names_to` is the name of the column/variable in the new "tidy" frame that contains the column names of the original data frame that you want to tidy. Observe how we set `names_to = "year"` and in the resulting `guat_dem_tidy` the column `year` contains the years where the Guatemala's democracy score were measured.
1. `values_to` is the name of the column/variable in the "tidy" frame that contains the rows and columns of values in the original data frame you want to tidy. Observe how we set `values_to = "democracy_score"` and in the resulting `guat_dem_tidy` the column `democracy_score` contains the 1 $\times$ 9 = 9 democracy scores.
However, observe in the output for `guat_dem_tidy` that the `year` variable is of type `chr` or character. Before we can plot this variable on the x-axis, we need to convert it into a numerical variable using the `as.numeric()` function within the `mutate()` function, which we saw in @sec-mutate on mutating existing variables to create new ones.
```{r}
guat_dem_tidy <- guat_dem_tidy %>%
mutate(year = as.numeric(year))
```
We can now create the plot to show how the democracy score of Guatemala changed from 1952 to 1992 using a `geom_line()`:
```{r}
#| errors = TRUE
ggplot(guat_dem_tidy, aes(x = year, y = democracy_score)) +
geom_line() +
labs(
x = "Year",
y = "Democracy Score",
title = "Democracy score in Guatemala 1952-1992"
)
```
:::{.callout-tip icon=false collapse=true}
## :dart: Learning Check `r paste0(chap, ".", (lc <- lc + 1))`
Convert the `dem_score` data frame into a tidy data frame and assign the name of `dem_score_tidy` to the resulting long-formatted data frame.
:::
:::{.callout-tip icon=false collapse=true}
## :dart: Learning Check `r paste0(chap, ".", (lc <- lc + 1))`
Read in the life expectancy data stored at <https://moderndive.com/data/le_mess.csv> and convert it to a tidy data frame.
:::
## Conclusion {#tidy-conclusion}
### `tidyverse` package {#sec-tidyverse-package}
Notice at the beginning of the chapter we loaded the following four packages, which are among the four of the most frequently used R packages for data science:
```{r}
#| eval: false
library(dplyr)
library(ggplot2)
library(readr)
library(tidyr)
```
There is a much quicker way to load these packages than by individually loading them as we did above: by installing and loading the `tidyverse` package. The `tidyverse` package acts as an "umbrella" package whereby installing/loading it will install/load multiple packages at once for you. So after installing the `tidyverse` package as you would a normal package, running this:
```{r}
#| eval: false
library(tidyverse)
```
would be the same as running this:
```{r}
#| eval: false
library(ggplot2)
library(dplyr)
library(tidyr)
library(readr)
library(purrr)
library(tibble)
library(stringr)
library(forcats)
```
You've seen the first 4 of the these packages: `ggplot2` for data visualization, `dplyr` for data wrangling, `tidyr` for converting data to "tidy" format, and `readr` for importing spreadsheet data into R. The remaining packages (`purrr`, `tibble`, `stringr`, and `forcats`) are left for a more advanced book; check out [R for Data Science](http://r4ds.had.co.nz/) to learn about these packages.
The `tidyverse` "umbrella" package gets its name from the fact that all functions in all its constituent packages are designed to that all inputs/argument data frames are in "tidy" format and all output data frames are in "tidy" format as well. This standardization of input and output data frames makes transitions between the various functions in these packages as seamless as possible.
### Additional resources
If you want to learn more about using the `readr` and `tidyr` package, we suggest you that you check out RStudio's "Data Import" cheatsheet. You can access this cheatsheet by going to RStudio's [cheatsheet page](https://www.rstudio.com/resources/cheatsheets/) and searching for "Data Import Cheat Sheet".
![Data Import cheatsheat](images/import_cheatsheet-1.png)
### What's to come?
Congratulations! We've completed the "Data Science via the tidyverse" portion of this book! We'll now move to the "data modeling" portion in Chapters -@sec-regression and -@sec-multiple-regression, where you'll leverage your data visualization and wrangling skills to model relationships between different variables in data frames.