【问题标题】:Pivot_longer starting and ending dates with multiple columns具有多列的 Pivot_longer 开始和结束日期
【发布时间】:2021-12-28 11:34:08
【问题描述】:

假设我有以下 df

original = data.frame(ID= c(1,1, 2),
                A = c(1,NA,1),
                StartingA = c("2001-01-01", NA, "1999-03-03"),
                EndingA = c("2002-01-01", NA, "2000-03-03"),
                B = c(NA,1,1),
                StartingB = c(NA, "2016-01-01", "2004-03-17"),
                EndingB = c(NA, "2019-01-01", "2018-11-27"),
                C = c(1,NA,1),
                StartingC = c("2011-07-08", NA, "2019-01-01"),
                EndingC = c("2017-07-08", NA, "2019-05-01"))

我想从宽转向长并得到结果:

result = data.frame(ID = c(1, 1, 1, 2, 2, 2),
                Value = c("A", "C", "B", "A", "B", "C"),
                Starting = c("2001-01-01", "2011-07-08", "2016-01-01", "1999-03-03", "2004-03-17", "2019-01-01"),
                EndingA = c("2002-01-01", "2017-07-08", "2019-01-01", "2000-03-03", "2018-11-27", "2019-05-01"))

我有 40 多个这样的专栏。

我对 pivot_longer 的尝试不正确

【问题讨论】:

    标签: r dplyr pivot tidyverse


    【解决方案1】:

    由于 ID 1 有两行,首先我创建一个唯一的行来填充这两个行,然后只保留一个。然后相关步骤是使用pivot_longer。如果您直接使用它,而无需前面的步骤,您会得到类似的结果,但会有一些额外的行缺失。

    我还假设您的列中的模式是Starting/Ending + 唯一大写字母A, B, C...

    original %>% 
        group_by(ID) %>% 
        fill(everything(), .direction = "downup") %>% 
        ungroup() %>% 
        distinct() %>% 
        pivot_longer(cols = -c(ID,matches("^[A-Z]$")), names_to = c(".value", "Value"), names_pattern = "(^[A-Za-z]*)([A-Z]$)")
    # A tibble: 6 × 7
         ID     A     B     C Value Starting   Ending    
      <dbl> <dbl> <dbl> <dbl> <chr> <chr>      <chr>     
    1     1     1     1     1 A     2001-01-01 2002-01-01
    2     1     1     1     1 B     2016-01-01 2019-01-01
    3     1     1     1     1 C     2011-07-08 2017-07-08
    4     2     1     1     1 A     1999-03-03 2000-03-03
    5     2     1     1     1 B     2004-03-17 2018-11-27
    6     2     1     1     1 C     2019-01-01 2019-05-01
    

    第一步更简单的选择是总结唯一的非缺失数据

    original %>% 
        group_by(ID) %>% 
        summarise(across(everything(),~unique(.[!is.na(.)]))) %>% 
        pivot_longer(cols = -c(ID,matches("^[A-Z]$")), names_to = c(".value", "Value"), names_pattern = "(^[A-Za-z]*)([A-Z]$)")
    # A tibble: 6 × 7
         ID     A     B     C Value Starting   Ending    
      <dbl> <dbl> <dbl> <dbl> <chr> <chr>      <chr>     
    1     1     1     1     1 A     2001-01-01 2002-01-01
    2     1     1     1     1 B     2016-01-01 2019-01-01
    3     1     1     1     1 C     2011-07-08 2017-07-08
    4     2     1     1     1 A     1999-03-03 2000-03-03
    5     2     1     1     1 B     2004-03-17 2018-11-27
    6     2     1     1     1 C     2019-01-01 2019-05-01
    

    【讨论】:

    • 谢谢。这适用于示例,但正如您所说,唯一大写字母的假设过于严格
    • @moon289 如果您解释所有列名的模式,我可以尝试调整答案。
    【解决方案2】:

    看起来您可以将正则表达式模式与pivot_longer 一起使用,其中包括“开始”和“结束”作为单独的列,以及Value。通过包含values_drop_na,将删除缺少数据的行。

    library(tidyverse)
      
    original %>%
      pivot_longer(cols = -ID, 
                   names_to = c(".value", "Value"), 
                   names_pattern = "(Starting|Ending)(\\w+)",
                   values_drop_na = TRUE)
    

    输出

         ID Value Starting   Ending    
      <dbl> <chr> <chr>      <chr>     
    1     1 A     2001-01-01 2002-01-01
    2     1 C     2011-07-08 2017-07-08
    3     1 B     2016-01-01 2019-01-01
    4     2 A     1999-03-03 2000-03-03
    5     2 B     2004-03-17 2018-11-27
    6     2 C     2019-01-01 2019-05-01
    

    【讨论】:

      猜你喜欢
      • 2021-06-26
      • 2023-03-17
      • 2022-01-25
      • 2012-08-19
      • 1970-01-01
      • 2020-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多