使用 pivot_longer() 将数据从宽数据转换为长数据

convert data from wide to long using pivot_longer()

提问人:azizi tamimi 提问时间:11/14/2023 最后编辑:moodymudskipperazizi tamimi 更新时间:11/14/2023 访问量:74

问:

我需要您的帮助将数据从宽到长,将多个列/变量转换为行。

以下是数据。

stack1 <- tibble::tribble(
  ~ID, ~Recall1, ~Recall2, ~Recall3,     ~Recall4, ~Recall5,     ~Item1, ~Item2, ~Item3, ~Item4, ~Item5, ~vocab1, ~vocab2, ~vocab3, ~vocab4,
  39,  "Next",   "His",    "University", "Higher", "College",    1,      0,      1,      1,      0,      1,       1,       0,       1,
  90,  "Next",   "her",    "school",     "Higher", "university", 1,      0,      1,      1,      0,      1,       1,       0,       1,
) 

我想重新调整,使我只有三个变量:Recall_value Recog_score 和 vocab_sum。变量 vocab_sum 表示每个 ID 的 vocab1:vocab4 之和。

所需的输出应如下所示:

stack2 <- tibble::tribble(
  ~ID, ~Recall,   ~Recall_value, ~Recog,  ~Recog_score, ~vocab_sum,
  39,  "Recall1", "Next",        "Item1", 1,            3,
  39,  "Recall2", "His",         "Item2", 0,            3,
  39,  "Recall3", "University",  "Item3", 1,            3,
  39,  "Recall4", "Higher",      "Item4", 1,            3,
  39,  "Recall5", "College",     "Item5", 0,            3,
  90,  "Recall1", "Next",        "Item1", 1,            4,
  90,  "Recall2", "her",         "Item2", 0,            4,
  90,  "Recall3", "school",      "Item3", 1,            4,
  90,  "Recall4", "Higher",      "Item4", 1,            4,
  90,  "Recall5", "university",  "Item5", 0,            4,
)

我使用 pivot_longer() 尝试了以下代码:

> stack2 <- stack1 %>% 
    pivot_longer(
        cols =c(`Recall1`:`Recall5`, `Item1`: `Item5`), 
        names_to = c("Recall","Recog"),
        values_to = c("Recall_value", "Recog_score" ))

但是,它无助于实现预期的输出。

r dplyr tidyr

评论


答:

0赞 Derf 11/14/2023 #1

您可以对 和 进行两个单独的透视。RecallItem

cbind(
stack1 %>% 
  mutate(vocab_sum=vocab1+vocab2+vocab3+vocab4)%>%
  select(-starts_with("vocab"),vocab_sum) %>%
  pivot_longer(cols=starts_with("Recall"),
               names_to="Recall",
               values_to="Recall_value") %>%
  select(-(Item1:Item5))
,
stack1 %>% 
  select(-starts_with("vocab")) %>%
  pivot_longer(cols=starts_with("Item"),
               names_to="Item",
               values_to="Item_value") %>%
  select(-(Recall1:Recall5),-ID)


) |> as_tibble()
# A tibble: 10 × 6
      ID vocab_sum Recall  Recall_value Item  Item_value
   <dbl>     <dbl> <chr>   <chr>        <chr>      <dbl>
 1    39         3 Recall1 Next         Item1          1
 2    39         3 Recall2 His          Item2          0
 3    39         3 Recall3 University   Item3          1
 4    39         3 Recall4 Higher       Item4          1
 5    39         3 Recall5 College      Item5          0
 6    90         3 Recall1 Next         Item1          1
 7    90         3 Recall2 her          Item2          0
 8    90         3 Recall3 school       Item3          1
 9    90         3 Recall4 Higher       Item4          1
10    90         3 Recall5 university   Item5          0

评论

1赞 Mark 11/14/2023
一个小指针:可以用 代替,同样-vocab1,-vocab2,-vocab3,-vocab4-starts_with("vocab")Recall1:Recall5
0赞 Derf 11/14/2023
@Mark谢谢。我不情愿,因为它可能会被移除,但它可以在里面被覆盖vocab_sumselect()
0赞 Mark 11/14/2023
啊,对了,我错过了!或者,您可以使用 -vocab1:vocab4,就像在其他地方所做的那样。 也很棒.keep = "unused"
0赞 PGSA 11/14/2023
@Derf看到 Mark 的答案 - 由于一致的命名系统,通过使用参数和代词,可以在一个操作中透视到多个列。names_pattern.valuenames_to
0赞 Derf 11/14/2023
@PaulStaffordAllen 啊,是的,谢谢你的提示。忘了从我的答案中删除那部分。也没有注意到这一点,并且具有相同的编号。我看到了与 Mark at 类似的方法,但很难理解正则表达式部分RecallItem?pivot_longer
3赞 Mark 11/14/2023 #2

步骤:

  1. 通过对每行的所有词汇值求和来创建列。 然后删除所有这些词汇列,因为我们不再需要它们。vocab_sum.keep = "unused"
  2. 将非 ID 列或vocab_sum列(即 Recall 和 Item 列)透视更长时间,从其名称中捕获模式
library(tidyverse)
stack1 |>
  mutate(vocab_sum = rowSums(across(starts_with("vocab"))), .keep = "unused") |>
  pivot_longer(c(starts_with("Recall"), starts_with("Item")), names_to = c(".value", "Recall_num"), names_pattern = "(\\D+)(\\d+)")

输出:

# A tibble: 10 × 5
      ID vocab_sum Recall_num Recall      Item
   <dbl>     <dbl> <chr>      <chr>      <dbl>
 1    39         3 1          Next           1
 2    39         3 2          His            0
 3    39         3 3          University     1
 4    39         3 4          Higher         1
 5    39         3 5          College        0
 6    90         3 1          Next           1
 7    90         3 2          her            0
 8    90         3 3          school         1
 9    90         3 4          Higher         1
10    90         3 5          university     0

我认为列顺序对您来说无关紧要,所以我在上面省略了它。但是,如果它很重要,则可以同时对列进行重新排序和重命名。select()

评论

1赞 Mark 11/14/2023
当然!所以那部分是正则表达式——正则表达式基本上是花哨的模式匹配
1赞 Mark 11/14/2023
\\d+ 一次或多次匹配一个数字 (0-9),\\D+ 一次或多次匹配任何不是数字的东西
1赞 Mark 11/14/2023
括号内的内容称为捕获组。它们由 names_to 使用(因此有两个值
1赞 Mark 11/14/2023
正则表达式可能有点像看一个神秘的代码,但它们非常适合简明扼要地描述你想要的东西
1赞 Mark 11/14/2023
regex101.com/r/dVA1I9/1