10  tidyr包,数据重塑

10.1 长宽数据格式简介

在数据科学中,数据通常以两种主要格式存在:宽格式长格式。理解这两种数据格式对于有效地使用tidyr包进行数据整理至关重要。

10.1.1 宽格式(Wide Format)

宽格式的数据是指每个变量(特征)在数据中占用一列。例如,一个数据集包含了不同学科的成绩,其中每个学科的成绩都占用一个单独的列。

示例:

library(tidyverse)
scores = tibble(
  "学生"=c("小红","小明","小刚"),
  "语文"=c(NA,70,80),
  "数学"=c(70,NA,78),
  "英语"=c(100,80,40)
)
scores
# A tibble: 3 x 4
  学生   语文  数学  英语
  <chr> <dbl> <dbl> <dbl>
1 小红     NA    70   100
2 小明     70    NA    80
3 小刚     80    78    40

10.1.2 长格式(Long Format)

长格式的数据则将不同变量的值放在同一列中,而通过另一列来表示这些变量的名称。例如,将上述宽格式数据转换成长格式,每个学生的成绩会变成多行,并通过一个额外的列来区分学科。

示例:

# A tibble: 9 x 3
  学生  学科   成绩
  <chr> <chr> <dbl>
1 小红  语文     NA
2 小红  数学     70
3 小红  英语    100
4 小明  语文     70
5 小明  数学     NA
6 小明  英语     80
7 小刚  语文     80
8 小刚  数学     78
9 小刚  英语     40

10.2 tidyr包主要功能

tidyr包是R语言中用于数据整理的一个重要工具,它提供了一组函数,用于在宽格式和长格式之间转换,以及处理缺失值数据列分割合并。以下是一些关键函数及其用法:

10.2.1 数据宽长转换

pivot_longer()宽变长

将数据从宽格式转换为长格式。此函数将多个列的值合并到两个列中:一个表示变量名称,另一个表示变量值。

用法:

scoresLong = scores %>%
  pivot_longer(cols = -1,
               names_to = "学科",
               values_to = "成绩")
scoresLong
# A tibble: 9 x 3
  学生  学科   成绩
  <chr> <chr> <dbl>
1 小红  语文     NA
2 小红  数学     70
3 小红  英语    100
4 小明  语文     70
5 小明  数学     NA
6 小明  英语     80
7 小刚  语文     80
8 小刚  数学     78
9 小刚  英语     40

解释:

  • cols: 需要转换的列。(-1表示除了第一列)

  • names_to: 新列的名称,存储原列名(通常是变量名称)。

  • values_to: 新列的名称,存储原列的值。

pivot_wider()长变宽

将数据从长格式转换为宽格式。此函数将长格式数据中的一列转换为多个列。

用法:

scoresLong %>%
  pivot_wider(names_from = `学科`,
              values_from = `成绩`)
# A tibble: 3 x 4
  学生   语文  数学  英语
  <chr> <dbl> <dbl> <dbl>
1 小红     NA    70   100
2 小明     70    NA    80
3 小刚     80    78    40

解释:

  • names_from: 用于创建新列的列。

  • values_from: 用于填充新列的数据列。

10.2.2 分割合并列

separate()分割列

将一列拆分为多个列,根据指定的分隔符。

用法:

scores = tibble(
  "学生"=c("1班-小红","1班-小明","2班-小刚"),
  "语文"=c(NA,70,80),
  "数学"=c(70,NA,78),
  "英语"=c(100,80,40)
)
scoresSep = scores %>% 
  separate(col = `学生`,
           into = c("班级","姓名"),
           sep="-")
scoresSep
# A tibble: 3 x 5
  班级  姓名   语文  数学  英语
  <chr> <chr> <dbl> <dbl> <dbl>
1 1班   小红     NA    70   100
2 1班   小明     70    NA    80
3 2班   小刚     80    78    40

unite()合并列

将多个列合并为一列

用法:

# 将列,班级和姓名,合并成列 学生
scoresSep %>%
  unite(`学生`,
        `班级`,
        `姓名`,
        sep = "-")
# A tibble: 3 x 4
  学生      语文  数学  英语
  <chr>    <dbl> <dbl> <dbl>
1 1班-小红    NA    70   100
2 1班-小明    70    NA    80
3 2班-小刚    80    78    40

补充:

separate_rows分割列,并新增行。

tibble(
  x = 1:3,
  y = c("a", "d,e,f", "g,h")
) %>%
separate_rows(y,
              sep=",")
# A tibble: 6 x 2
      x y    
  <int> <chr>
1     1 a    
2     2 d    
3     2 e    
4     2 f    
5     3 g    
6     3 h    

10.2.3 处理缺失值

drop_na()删除包含缺失值的行。

用法:

# 删除包含空值的行
scores %>%
  drop_na()
# A tibble: 1 x 4
  学生      语文  数学  英语
  <chr>    <dbl> <dbl> <dbl>
1 2班-小刚    80    78    40
# 删除语文列是空值的行
scores %>%
  drop_na(`语文`)
# A tibble: 2 x 4
  学生      语文  数学  英语
  <chr>    <dbl> <dbl> <dbl>
1 1班-小明    70    NA    80
2 2班-小刚    80    78    40

fill()填补缺失值

可以按前向填充(down)或后向填充(up)。

用法:

scores %>%
  fill(`数学`,
       .direction ="down") # 填充方向down up downup updown
# A tibble: 3 x 4
  学生      语文  数学  英语
  <chr>    <dbl> <dbl> <dbl>
1 1班-小红    NA    70   100
2 1班-小明    70    70    80
3 2班-小刚    80    78    40

replace_na()替换缺失值

# 把语文列的NA替换成0
scores %>%
  replace_na(list("语文"=0))
# A tibble: 3 x 4
  学生      语文  数学  英语
  <chr>    <dbl> <dbl> <dbl>
1 1班-小红     0    70   100
2 1班-小明    70    NA    80
3 2班-小刚    80    78    40

补充:
将数据中所有的NA替换成0

# tidyverse写法
scores %>%
  mutate(across(everything(), ~ replace_na(., 0)))
# A tibble: 3 x 4
  学生      语文  数学  英语
  <chr>    <dbl> <dbl> <dbl>
1 1班-小红     0    70   100
2 1班-小明    70     0    80
3 2班-小刚    80    78    40
# base R 写法
scores[is.na(scores)] = 0
scores
# A tibble: 3 x 4
  学生      语文  数学  英语
  <chr>    <dbl> <dbl> <dbl>
1 1班-小红     0    70   100
2 1班-小明    70     0    80
3 2班-小刚    80    78    40