【问题标题】:Using pivot_longer to restructure wide data, with multiple columns, from a spreadsheet使用 pivot_longer 从电子表格中重组具有多列的宽数据
【发布时间】:2021-07-17 00:17:00
【问题描述】:

我确信有一个答案,但我找不到它。我尝试了几种使用几个 R 函数的解决方案,包括 reshape、gather 和 pivot_longer。我的问题是数据来自具有多列的电子表格。我将尝试代表电子表格的一个样本:

FullName SOCW725 SOCW748 SOCW799 Average SOCW725 SOCW752 SOCW782 Average SOCW725 SOCW748 SOCW752 Average
Beavis B 3.5 3.22 2.56 3.07 2.33 3.33 4.2 3.5 3.33 3.23 No Data 3.00
El Guapo 3.25 3.02 2.75 3.18 3.33 4.33 4.15 2.25 2.67 3.42 4 2.44

实际的数据文件要宽得多。每组三门课程(例如 SOCW725、SOCW748、SOCW799)代表一种能力,共有九种能力。我把它们放在了桌面上,因为我相信一旦我弄清楚了(我希望)我就可以将它们插入数据框中。所以,我试图将 pivot_longer 分成三列(添加 CompetencyID 时将为 4)。这些列是:名称、课程和评分。我不需要平均值,因为我可以重新计算它。以下是我正在使用的代码示例:

d1 <- pivot_longer(my_data, 
               cols = !1, 
               names_to = "Course",
               values_to = "Ratings",
               )

这可行,但重复的行名(即课程名称)有一个 .后跟一个数字(例如 SOCW725.1、SOCW725.2 等)。我明白为什么,但我不知道如何摆脱它。我大概可以弄清楚如何从结果中编辑 .#,但想用 dplyr::pivot_table 找到更快的方法。

提前谢谢你。

【问题讨论】:

    标签: r dplyr reshape gather


    【解决方案1】:

    如果我们有兴趣在单个列中返回“FullName”和“SOCW”列(重复),select 感兴趣的列,然后使用 pivot_longernames_pattern 作为 ".value" 并捕获列名中不带. ([^.]+) 后跟数字的子字符串。

    library(dplyr)
    library(tidyr)
    my_data %>% 
        select(FullName, starts_with("SOCW")) %>% 
        pivot_longer(cols = starts_with("SOCW"), names_to = ".value", 
             names_pattern = '^(SOCW[^.]+)')
    # A tibble: 6 x 6
      FullName SOCW725 SOCW748 SOCW799 SOCW752 SOCW782
      <chr>      <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
    1 Beavis B    3.5     3.22    2.56    3.33    4.2 
    2 Beavis B    2.33    3.23   NA      NA      NA   
    3 Beavis B    3.33   NA      NA      NA      NA   
    4 El Guapo    3.25    3.02    2.75    4.33    4.15
    5 El Guapo    3.33    3.42   NA       4      NA   
    6 El Guapo    2.67   NA      NA      NA      NA  
    

    data.frame 默认情况下不允许重复的列名。它使用make.unique 修改列名,为每个重复项附加.1.2 等。


    如果我们只需要三列

    library(stringr)
    my_data %>% 
       select(FullName, starts_with("SOCW")) %>% 
       pivot_longer(cols = starts_with("SOCW")) %>% 
       mutate(name = str_remove(name, "\\.\\d+$"))
    # A tibble: 18 x 3
       FullName name    value
       <chr>    <chr>   <dbl>
     1 Beavis B SOCW725  3.5 
     2 Beavis B SOCW748  3.22
     3 Beavis B SOCW799  2.56
     4 Beavis B SOCW725  2.33
     5 Beavis B SOCW752  3.33
     6 Beavis B SOCW782  4.2 
     7 Beavis B SOCW725  3.33
     8 Beavis B SOCW748  3.23
     9 Beavis B SOCW752 NA   
    10 El Guapo SOCW725  3.25
    11 El Guapo SOCW748  3.02
    12 El Guapo SOCW799  2.75
    13 El Guapo SOCW725  3.33
    14 El Guapo SOCW752  4.33
    15 El Guapo SOCW782  4.15
    16 El Guapo SOCW725  2.67
    17 El Guapo SOCW748  3.42
    18 El Guapo SOCW752  4   
    

    数据

    my_data <- structure(list(FullName = c("Beavis B", "El Guapo"), SOCW725 = c(3.5, 
    3.25), SOCW748 = c(3.22, 3.02), SOCW799 = c(2.56, 2.75), Average = c(3.07, 
    3.18), SOCW725.1 = c(2.33, 3.33), SOCW752 = c(3.33, 4.33), SOCW782 = c(4.2, 
    4.15), Average.1 = c(3.5, 2.25), SOCW725.2 = c(3.33, 2.67), SOCW748.1 = c(3.23, 
    3.42), SOCW752.1 = c(NA, 4L), Average.2 = c(3, 2.44)),
     class = "data.frame", row.names = c(NA, 
    -2L))
    

    【讨论】:

    • 感谢您的及时回复。这很接近,但我最终仍然会为每个 SOCW### 值获得一个单独的列。
    • @AlanLipps 我以为你想要单独的列。如果需要单列,那就更简单了
    • @AlanLipps 我用新的输出更新了帖子。最好在您的帖子中显示预期的输出,以便更容易交叉检查
    • 感谢您更新代码。下次我一定会记得展示想要的结果。这真的很好用。我确实有另一个相关的问题。实际上,我认为一旦解决了这部分问题,我就可以弄清楚另外一个专栏。我会将新问题作为新问题发布。
    【解决方案2】:

    akrun 的帮助下,我能够让它工作:

    d1 <- pivot_longer(my_data, 
                        cols = !1, 
                        names_to = "Course",
                        values_to = "Ratings",
                        names_pattern = '^(SOCW[^.]+)'
                        )
    

    正则表达式在我的学习清单上。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 2022-09-27
      相关资源
      最近更新 更多