Copyedits for factors.Rmd (#280)
This commit is contained in:
parent
322e3981e5
commit
7784ced193
40
factors.Rmd
40
factors.Rmd
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
In R, factors are used to work with categorical variables, variables that have a fixed and known set of possible values. They are also useful when you want to display character vectors with non-alphabetical order.
|
In R, factors are used to work with categorical variables, variables that have a fixed and known set of possible values. They are also useful when you want to display character vectors in a non-alphabetical order.
|
||||||
|
|
||||||
Historically, factors were much easier to work with than characters so many functions in base R automatically convert characters to factors. That means factors often crop up in places where they're not actually helpful. Fortunately, you don't need to worry about that in the tidyverse, and can focus on where factors are genuinely useful.
|
Historically, factors were much easier to work with than characters, so many functions in base R automatically convert characters to factors. That means that factors often crop up in places where they're not actually helpful. Fortunately, you don't need to worry about that in the tidyverse, and can focus on situations where factors are genuinely useful.
|
||||||
|
|
||||||
To get more historical context on factors, I'd reccommed [_stringsAsFactors: An unauthorized biography_](http://simplystatistics.org/2015/07/24/stringsasfactors-an-unauthorized-biography/) by Roger Peng, and [_stringsAsFactors = \<sigh\>_](http://notstatschat.tumblr.com/post/124987394001/stringsasfactors-sigh) by Thomas Lumley.
|
For more historical context on factors, I reccommed [_stringsAsFactors: An unauthorized biography_](http://simplystatistics.org/2015/07/24/stringsasfactors-an-unauthorized-biography/) by Roger Peng, and [_stringsAsFactors = \<sigh\>_](http://notstatschat.tumblr.com/post/124987394001/stringsasfactors-sigh) by Thomas Lumley.
|
||||||
|
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
To work with factors, we'll use the __forcats__ packages which provides tools for dealing **cat**egorical variables (and it's an anagram of factors!). It provides a wide range of helpers for working with factors. We'll also need dplyr for some data manipulation, and ggplot2 for visualisation.
|
To work with factors, we'll use the __forcats__ package, which provides tools for dealing with **cat**egorical variables (and it's an anagram of factors!). It provides a wide range of helpers for working with factors. We'll also need dplyr for some data manipulation, and ggplot2 for visualisation.
|
||||||
|
|
||||||
```{r setup, message = FALSE}
|
```{r setup, message = FALSE}
|
||||||
# devtools::install_github("hadley/forcats")
|
# devtools::install_github("hadley/forcats")
|
||||||
|
@ -23,7 +23,7 @@ library(dplyr)
|
||||||
|
|
||||||
## Creating factors
|
## Creating factors
|
||||||
|
|
||||||
Typically you'll convert a factor from a character vector, using `factor()`. Apart from the character input, the most important argument are the valid __levels__:
|
Typically you'll convert a factor from a character vector, using `factor()`. Apart from the character input, the most important argument is the list of valid __levels__:
|
||||||
|
|
||||||
```{r}
|
```{r}
|
||||||
x <- c("pear", "apple", "banana", "apple", "pear", "apple")
|
x <- c("pear", "apple", "banana", "apple", "pear", "apple")
|
||||||
|
@ -42,7 +42,7 @@ If you omit the levels, they'll be taken from the data in alphabetical order:
|
||||||
factor(x)
|
factor(x)
|
||||||
```
|
```
|
||||||
|
|
||||||
Sometimes you'd prefer that the order of the levels match the order of the first appearnace in the data. You can do that during creation by setting levels to `unique(x)`, or after the with `fct_inorder()`:
|
Sometimes you'd prefer that the order of the levels match the order of the first appearance in the data. You can do that when creating the factor by setting levels to `unique(x)`, or after the fact, with `fct_inorder()`:
|
||||||
|
|
||||||
```{r}
|
```{r}
|
||||||
f1 <- factor(x, levels = unique(x))
|
f1 <- factor(x, levels = unique(x))
|
||||||
|
@ -52,7 +52,7 @@ f2 <- x %>% factor() %>% fct_inorder()
|
||||||
f2
|
f2
|
||||||
```
|
```
|
||||||
|
|
||||||
If you ever need to access the set of valid levels directly, you can get at them with `levels()`:
|
If you ever need to access the set of valid levels directly, you can do so with `levels()`:
|
||||||
|
|
||||||
```{r}
|
```{r}
|
||||||
levels(f2)
|
levels(f2)
|
||||||
|
@ -60,7 +60,7 @@ levels(f2)
|
||||||
|
|
||||||
## General Social Survey
|
## General Social Survey
|
||||||
|
|
||||||
In rest of this chapter, we're going to focus on `forcats::gss_cat`. It's a sample data from the [General Social Survey](http://gss.norc.org), which is a long-running US survey run by the the independent research organization NORC at the University of Chicago. The survey has thousands of questions, so in `gss_cat` I've selected a handful that will illustrate some common challenges you'll hit when working with factors.
|
For the rest of this chapter, we're going to focus on `forcats::gss_cat`. It's a sample of data from the [General Social Survey](http://gss.norc.org), which is a long-running US survey conducted by the independent research organization NORC at the University of Chicago. The survey has thousands of questions, so in `gss_cat` I've selected a handful that will illustrate some common challenges you'll encounter when working with factors.
|
||||||
|
|
||||||
```{r}
|
```{r}
|
||||||
gss_cat
|
gss_cat
|
||||||
|
@ -90,9 +90,9 @@ ggplot(gss_cat, aes(race)) +
|
||||||
scale_x_discrete(drop = FALSE)
|
scale_x_discrete(drop = FALSE)
|
||||||
```
|
```
|
||||||
|
|
||||||
These levels represent valid values that we simply did not see in this dataset. Unfortunately dplyr doesn't yet have a `drop` option, but it will in the future.
|
These levels represent valid values that simply did not occur in this dataset. Unfortunately, dplyr doesn't yet have a `drop` option, but it will in the future.
|
||||||
|
|
||||||
There are two main operations that you'll do time and time again when working with factors: changing the order of the levels, and changing the values of the levels. Those operation are described in the sections below.
|
When working with factors, the two most common operations are changing the order of the levels, and changing the values of the levels. Those operation are described in the sections below.
|
||||||
|
|
||||||
### Exercise
|
### Exercise
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ There are two main operations that you'll do time and time again when working wi
|
||||||
|
|
||||||
## Modifying factor order
|
## Modifying factor order
|
||||||
|
|
||||||
It's often useful to change the order of the factors levels in a visualisation. For example, imagine you want to explore the average number of hours spend watching tv per day across religions:
|
It's often useful to change the order of the factor levels in a visualisation. For example, imagine you want to explore the average number of hours spent watching TV per day across religions:
|
||||||
|
|
||||||
```{r}
|
```{r}
|
||||||
relig <- gss_cat %>%
|
relig <- gss_cat %>%
|
||||||
|
@ -121,11 +121,11 @@ relig <- gss_cat %>%
|
||||||
ggplot(relig, aes(tvhours, relig)) + geom_point()
|
ggplot(relig, aes(tvhours, relig)) + geom_point()
|
||||||
```
|
```
|
||||||
|
|
||||||
It's a little hard to take in this plot because there's no overall pattern. We can improve it by reordering the levels of `relig` using `fct_reorder()`. `fct_reorder()` takes three arguments:
|
It is difficult to interpret this plot because there's no overall pattern. We can improve it by reordering the levels of `relig` using `fct_reorder()`. `fct_reorder()` takes three arguments:
|
||||||
|
|
||||||
* `f`, the factor whose levels you want to modify.
|
* `f`, the factor whose levels you want to modify.
|
||||||
* `x`, a numeric vector that you want to use to reorder the levels.
|
* `x`, a numeric vector that you want to use to reorder the levels.
|
||||||
* Optionally, `fun`, a function that's used to if there are multiple values of
|
* Optionally, `fun`, a function that's used if there are multiple values of
|
||||||
`x` for each value of `f`. The default value is `median`.
|
`x` for each value of `f`. The default value is `median`.
|
||||||
|
|
||||||
```{r}
|
```{r}
|
||||||
|
@ -133,9 +133,9 @@ ggplot(relig, aes(tvhours, fct_reorder(relig, tvhours))) +
|
||||||
geom_point()
|
geom_point()
|
||||||
```
|
```
|
||||||
|
|
||||||
Reordering religion makes it much easier to see that "Don't know" seems to watch much more, and Hinduism & Other Eastern religions watch much less.
|
Reordering religion makes it much easier to see that people in the "Don't know" category watch much more TV, and Hinduism & Other Eastern religions watch much less.
|
||||||
|
|
||||||
As you start making more complicated transformations, I'd recommend moving them about out `aes()` and into a separate `mutate()` step. For example, you could rewrite the plot above as:
|
As you start making more complicated transformations, I'd recommend moving them out of `aes()` and into a separate `mutate()` step. For example, you could rewrite the plot above as:
|
||||||
|
|
||||||
```{r, eval = FALSE}
|
```{r, eval = FALSE}
|
||||||
relig %>%
|
relig %>%
|
||||||
|
@ -157,7 +157,7 @@ rincome <- gss_cat %>%
|
||||||
ggplot(rincome, aes(age, fct_reorder(rincome, age))) + geom_point()
|
ggplot(rincome, aes(age, fct_reorder(rincome, age))) + geom_point()
|
||||||
```
|
```
|
||||||
|
|
||||||
Here, arbitrarily reordering the levels isn't a good idea! That's because `rincome` already has a principled order that we shouldn't mess with. Reserve `fct_reorder()` to reorder factors whose levels are arbitrarily ordered.
|
Here, arbitrarily reordering the levels isn't a good idea! That's because `rincome` already has a principled order that we shouldn't mess with. Reserve `fct_reorder()` for factors whose levels are arbitrarily ordered.
|
||||||
|
|
||||||
However, it does make sense to pull "Not applicable" to the front with the other special levels. You can use `fct_relevel()`. It takes a factor, `f`, and then any number of levels that you want to move to the front of the line.
|
However, it does make sense to pull "Not applicable" to the front with the other special levels. You can use `fct_relevel()`. It takes a factor, `f`, and then any number of levels that you want to move to the front of the line.
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ ggplot(rincome, aes(age, fct_relevel(rincome, "Not applicable"))) +
|
||||||
|
|
||||||
Why do you think the average age for "Not applicable" is so high?
|
Why do you think the average age for "Not applicable" is so high?
|
||||||
|
|
||||||
Another type of reordering is useful when you are colouring the lines on a plot. `fct_reorder2()` reorders the factor to by the `y` values associated the largest `x` values. This makes the plot easier to read because the line colours up with the legend.
|
Another type of reordering is useful when you are colouring the lines on a plot. `fct_reorder2()` reorders the factor by the `y` values associated with the largest `x` values. This makes the plot easier to read because the line colours line up with the legend.
|
||||||
|
|
||||||
```{r, fig.align = "default", out.width = "50%", fig.width = 4}
|
```{r, fig.align = "default", out.width = "50%", fig.width = 4}
|
||||||
by_age <- gss_cat %>%
|
by_age <- gss_cat %>%
|
||||||
|
@ -211,13 +211,13 @@ gss_cat %>%
|
||||||
|
|
||||||
## Modifying factor levels
|
## Modifying factor levels
|
||||||
|
|
||||||
More powerful than changing the orders of the levels is to change their values. This allows you to clarify labels for publication, and collapse levels for high-level displays. The most general and powerful tool is `fct_recode()`. It allows you to recode, or change, the value of each level. For example, take the `gss_cat$partyid`:
|
More powerful than changing the orders of the levels is changing their values. This allows you to clarify labels for publication, and collapse levels for high-level displays. The most general and powerful tool is `fct_recode()`. It allows you to recode, or change, the value of each level. For example, take the `gss_cat$partyid`:
|
||||||
|
|
||||||
```{r}
|
```{r}
|
||||||
gss_cat %>% count(partyid)
|
gss_cat %>% count(partyid)
|
||||||
```
|
```
|
||||||
|
|
||||||
The levels are terse and inconstent. Let's tweak them to be longer and use the a parallel construction.
|
The levels are terse and inconstent. Let's tweak them to be longer and use a parallel construction.
|
||||||
|
|
||||||
```{r}
|
```{r}
|
||||||
gss_cat %>%
|
gss_cat %>%
|
||||||
|
@ -232,7 +232,7 @@ gss_cat %>%
|
||||||
count(partyid)
|
count(partyid)
|
||||||
```
|
```
|
||||||
|
|
||||||
`fct_recode()` will leave levels that aren't explicitly mentioned will as is, and will warn if you accidentally refer to a level that doesn't exist.
|
`fct_recode()` will leave levels that aren't explicitly mentioned as is, and will warn you if you accidentally refer to a level that doesn't exist.
|
||||||
|
|
||||||
To combine groups, you can assign multiple old levels to the same new level:
|
To combine groups, you can assign multiple old levels to the same new level:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue