如何同时旋转多列?

How to pivot multiple columns at the same time?

我有一个数据框,其中包含如下 input 中组织的试题。 我正在尝试以 output.

中显示的整洁方式组织它

input 中,您可以看到学生的 ID、他们对特定项目的回答 suffix = ".text"、他们对该特定项目的分数 suffix = ".score",以及他们的 total得分。

输入

library(tibble)

input <- tribble(
     ~ID, ~i1.text, ~i1.score, ~i2.text, ~i2.score, ~total,
  "Mark",      "A",        0L,      "B",        1L,     1L,
  "Mary",      "C",        1L,      "D",        0L,     1L,
  "John",      "A",        0L,      "B",        1L,     1L,
  "Abby",      "C",        1L,      "B",        1L,     2L
  )

我需要将数据转换为如下所示。

我很确定我可以用 pivot_longer() 做到这一点,但我很迷茫。

预期输出

output <- tribble(
     ~ID, ~item, ~text, ~score, ~total,
  "Mark",  "i1",   "A",     0L,     1L,
  "Mark",  "i2",   "B",     1L,     1L,
  "Mary",  "i1",   "C",     1L,     1L,
  "Mary",  "i2",   "D",     0L,     1L,
  "John",  "i1",   "A",     0L,     1L,
  "John",  "i2",   "B",     1L,     1L,
  "Abby",  "i1",   "C",     1L,     2L,
  "Abby",  "i2",   "B",     2L,     2L
  )

output

# A tibble: 8 × 5
  ID    item  text  score total
  <chr> <chr> <chr> <int> <int>
1 Mark  i1    A         0     1
2 Mark  i2    B         1     1
3 Mary  i1    C         1     1
4 Mary  i2    D         0     1
5 John  i1    A         0     1
6 John  i2    B         1     1
7 Abby  i1    C         1     2
8 Abby  i2    B         2     2

我们可以使用 pivot_longernames_sep 作为 . - 'item' return [=14] 之前的列名称的前缀部分=] 和 .value 将 return 带有列名称后缀部分的列的值 .

library(tidyr)
pivot_longer(input, cols = contains("."), 
    names_to = c("item", ".value"), names_sep = "\.")

-输出

# A tibble: 8 × 5
  ID    total item  text  score
  <chr> <int> <chr> <chr> <int>
1 Mark      1 i1    A         0
2 Mark      1 i2    B         1
3 Mary      1 i1    C         1
4 Mary      1 i2    D         0
5 John      1 i1    A         0
6 John      1 i2    B         1
7 Abby      2 i1    C         1
8 Abby      2 i2    B         1

这是一个类似的替代方法,使用 names_pattern:

解释:(.*)\.(.*) 是正则表达式:

() 抓一组

. 捕获任何字符

*是量词表示0个或多个

\ 转义字符

正则表达式的意思是: 任意数量的字符后跟一个点,然后是任意数量的字符。此正则表达式匹配您的列名:

library(dplyr)
library(tidyr)

input %>% 
  pivot_longer(
    cols = -c(ID, total), 
    names_to = c('item', '.value'),
    names_pattern = '(.*)\.(.*)'
    )
  ID    total item  text  score
  <chr> <int> <chr> <chr> <int>
1 Mark      1 i1    A         0
2 Mark      1 i2    B         1
3 Mary      1 i1    C         1
4 Mary      1 i2    D         0
5 John      1 i1    A         0
6 John      1 i2    B         1
7 Abby      2 i1    C         1
8 Abby      2 i2    B         1