第 8 章 数据规整

library(tidyverse)

8.1 提问

假定这里有 AB 两种植物生长的记录,有这样三列

plant_heigt <- data.frame(
  Day = 1:5,
  A = c(0.7, 1.0, 1.5, 1.8, 2.2),
  B = c(0.5, 0.7, 0.9, 1.3, 1.8)
)

plant_heigt
##   Day   A   B
## 1   1 0.7 0.5
## 2   2 1.0 0.7
## 3   3 1.5 0.9
## 4   4 1.8 1.3
## 5   5 2.2 1.8

大家想想,

  • 把植物高度大于或等于0.8cm的时刻筛选出来,怎么写语句?
  • 用不同的颜色画出两种植物生长曲线,怎么写语句?

很显然,我们用第 6 章数据处理和第 7 章数据可视化的技术,可以写成这样

plant_heigt %>% 
  filter( ___ >= 0.8)
plant_heigt %>% 
  ggplot(aes(x = Day, y = ___, color = ___)) +
  geom_line()

然而,发现遇到了问题?数据的格式与我们期望的不一样!

怎么解决呢?想用上面的语句,数据就得变形。那么怎么变形呢?

下面任意一种都行:

melted <- gather(plant_heigt, variable, value, 2:3)

## Column names instead of indices
melted <- gather(plant_heigt, variable, value, A, B)

## Excluding instead of including
melted <- gather(plant_heigt, variable, value, -1)

## Excluding using column name
melted <- gather(plant_heigt, variable, value, -Day)

但我更推荐大家使用tidyr::pivot_longer(), 这是2019年9月份,tidyr 1.0.0新增的一组函数pivot_longer()/pivot_wider(),用来补充和完善原来的gather()/spread()

  • gather()/pivot_longer 宽表格变成长表格
  • spread()/pivot_wider 长表格变成宽表格

8.2 宽表格变成长表格

所以现在使用pivot_longer()函数

long <- plant_heigt %>%
  pivot_longer(
    cols = c(A, B),
    names_to = "plant",
    values_to = "height"
  )
long

## # A tibble: 10 x 3
##      Day plant height
##    <int> <chr>  <dbl>
##  1     1 A        0.7
##  2     1 B        0.5
##  3     2 A        1  
##  4     2 B        0.7
##  5     3 A        1.5
##  6     3 B        0.9
##  7     4 A        1.8
##  8     4 B        1.3
##  9     5 A        2.2
## 10     5 B        1.8

这里pivot_longer()函数有三个主要的参数:

  • 参数cols,表示哪些列需要转换
  • 参数names_to,表示cols选取的这些列的名字,构成了新的一列,这里需要取一个名字.
  • 参数values_to, 表示cols选取的这些列的,构成了新的一列,这里也需要取一个名字.

当然,参数cols 的写法可以多种形式的,具体见第 22select()函数.

plant_heigt %>% 
  pivot_longer(
  cols = -Day,                 # A:B 或者 c(A, B) 或者 c("A", "B")
  names_to = "plant",
  values_to = "height"
)

画图的问题也就解决了

long %>% 
  ggplot(aes(x = Day, y = height, color = plant)) +
  geom_line()

8.3 长表格变成宽表格

如果,长表格变回宽表格呢?需要用到pivot_wider()

wide <- long %>% 
  pivot_wider(
  names_from = "plant",
  values_from = "height"
)
wide
## # A tibble: 5 x 3
##     Day     A     B
##   <int> <dbl> <dbl>
## 1     1   0.7   0.5
## 2     2   1     0.7
## 3     3   1.5   0.9
## 4     4   1.8   1.3
## 5     5   2.2   1.8

8.4 tidy data

Hadley Wickhamt提出了数据科学tidy原则,我结合自己的理解,tidy思想体现在:

  • 一切都是数据框,任何数据都可以规整
  • 数据框的一列代表一个变量,数据框的一行代表一次观察
  • 函数处理数据时,数据框进数据框出(函数的第一个参数始终为数据框

根据Hadley Wickham的思想,这里的宽表格(plant_heigtwide)不是tidy的,只有长表格(long)才是tidy的,

long
## # A tibble: 10 x 3
##      Day plant height
##    <int> <chr>  <dbl>
##  1     1 A        0.7
##  2     1 B        0.5
##  3     2 A        1  
##  4     2 B        0.7
##  5     3 A        1.5
##  6     3 B        0.9
##  7     4 A        1.8
##  8     4 B        1.3
##  9     5 A        2.2
## 10     5 B        1.8

以后,我们会意识到tidyverse中的很多函数都喜欢tidy的(尤其是ggplot2时)!

8.5 案例

请见第 37 章、第 38 章和第 39 章.