第 10 章 因子型变量

本章介绍R语言中的因子类型数据。因子型变量常用于数据处理和可视化中,尤其在希望不以字母顺序排序的时候,因子就格外有用。

10.1 什么是因子

因子是把数据进行分类并标记为不同层级(level,有时候也翻译成因子水平, 我个人觉得翻译为层级,更接近它的特性,因此,我都会用层级来描述)的数据对象,他们可以存储字符串和整数。因子类型有三个属性:

  • 存储类别的数据类型
  • 离散变量
  • 因子的层级是有限的,只能取因子层级中的值或缺失(NA)

10.2 创建因子

library(tidyverse)
income <- c("low", "high", "medium", "medium", "low", "high",  "high")
factor(income)
## [1] low    high   medium medium low    high   high  
## Levels: high low medium

因子层级会自动按照字符串的字母顺序排序,比如high low medium。也可以指定顺序,

factor(income, levels = c("low", "high", "medium") )
## [1] low    high   medium medium low    high   high  
## Levels: low high medium

不属于因子层级中的值, 比如这里因子层只有c("low", "high"),那么income中的“medium”会被当作缺省值NA

factor(income, levels = c("low", "high") )
## [1] low  high <NA> <NA> low  high high
## Levels: low high

相比较字符串而言,因子类型更容易处理,因子很多函数会自动的将字符串转换为因子来处理,但事实上,这也会造成,不想当做因子的却又当做了因子的情形,最典型的是在R 4.0之前,data.frame()stringsAsFactors选项,默认将字符串类型转换为因子类型,但这个默认也带来一些不方便,因此在R 4.0之后取消了这个默认。在tidyverse集合里,有专门处理因子的宏包forcats,因此,本章将围绕forcats宏包讲解如何处理因子类型变量,更多内容可以参考这里

library(forcats)

10.3 调整因子顺序

前面看到因子层级是按照字母顺序排序

x <- factor(income)
x
## [1] low    high   medium medium low    high   high  
## Levels: high low medium

也可以指定顺序

x %>% fct_relevel(levels = c("high", "medium", "low"))
## [1] low    high   medium medium low    high   high  
## Levels: high medium low

或者让“medium” 移动到最前面

x %>% fct_relevel(levels = c("medium"))
## [1] low    high   medium medium low    high   high  
## Levels: medium high low

或者让“medium” 移动到最后面

x %>% fct_relevel("medium", after = Inf)
## [1] low    high   medium medium low    high   high  
## Levels: high low medium

可以按照字符串第一次出现的次序

x %>% fct_inorder()
## [1] low    high   medium medium low    high   high  
## Levels: low high medium

按照其他变量的中位数的升序排序

x %>% fct_reorder(c(1:7), .fun = median)  
## [1] low    high   medium medium low    high   high  
## Levels: low medium high

10.4 应用

调整因子层级有什么用呢?

这个功能在ggplot可视化中调整分类变量的顺序非常方便。这里为了方便演示,我们假定有数据框

d <- tibble(
  x = c("a","a", "b", "b", "c", "c"),
  y = c(2, 2, 1, 5,  0, 3)
  
)
d
## # A tibble: 6 x 2
##   x         y
##   <chr> <dbl>
## 1 a         2
## 2 a         2
## 3 b         1
## 4 b         5
## 5 c         0
## 6 c         3

先画个散点图看看吧

d %>% 
  ggplot(aes(x = x, y = y)) +
  geom_point()

我们看到,横坐标上是a-b-c的顺序。

10.4.1 fct_reorder()

fct_reorder()可以让x的顺序按照x中每个分类变量对应y值的中位数升序排序,具体为

  • a对应的y值c(2, 2) 中位数是median(c(2, 2)) = 2
  • b对应的y值c(1, 5) 中位数是median(c(1, 5)) = 3
  • c对应的y值c(0, 3) 中位数是median(c(0, 3)) = 1.5

因此,x的因子层级的顺序调整为c-a-b

d %>% 
  ggplot(aes(x = fct_reorder(x, y, .fun = median), y = y)) +
  geom_point()

当然,我们可以加一个参数.desc = TRUE让因子层级变为降序排列b-a-c

d %>% 
  ggplot(aes(x = fct_reorder(x, y, .fun = median, .desc = TRUE), y = y)) +
  geom_point()

但这样会造成x坐标标签一大串,因此建议可以写mutate()函数里

d %>% 
  mutate(x = fct_reorder(x, y, .fun = median, .desc = TRUE)) %>% 
  ggplot(aes(x = x, y = y)) +
  geom_point()

我们还可以按照y值中最小值的大小降序排列

d %>% 
  mutate(x = fct_reorder(x, y, .fun = min, .desc = TRUE)) %>% 
  ggplot(aes(x = x, y = y)) +
  geom_point()

10.4.2 fct_rev()

按照因子层级的逆序排序

d %>% 
  mutate(x = fct_rev(x)) %>% 
  ggplot(aes(x = x, y = y)) +
  geom_point()

10.4.3 fct_relevel()

d %>% 
  mutate(
    x = fct_relevel(x, c("c", "a", "b"))
  ) %>% 

  ggplot(aes(x = x, y = y)) +
  geom_point()