【问题标题】:Turning a data frame and a list into long format with dplyr使用 dplyr 将数据框和列表转换为长格式
【发布时间】:2019-11-18 01:49:01
【问题描述】:

这是一个谜题。

假设您有一个数据框和一个列表。该列表的元素数量与 df 的行数一样多:

dd <- data.frame(ID=1:3, Name=LETTERS[1:3])
dl <- map(4:6, rnorm) %>% set_names(letters[1:3])

是否有一种简单的方法(最好使用 dplyr / tidyverse)来制作长格式,以便列表的元素与数据框的相应行连接?以下是我想用不太优雅的方式说明的内容:

rows <- map(1:length(dl), ~ rep(., length(dl[[.]]))) %>% unlist()
dd <- dd[rows,]
dd$value <- unlist(dl)

如您所见,对于dl 中的每个向量,我们根据需要多次复制相应行以容纳每个值。

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    在基础R 中,您可以使用stack 后跟merge 获得结果:

    res <- merge(stack(dl), dd, by.x="ind", by.y="Name")
    
    head(res)
    #  ind      values ID
    #1   A -0.79616693  1
    #2   A  0.37720953  1
    #3   A  1.30273712  1
    #4   A  0.19483859  1
    #5   B  0.18770716  2
    #6   B -0.02226917  2
    

    注意:我认为dl 的名称应该是大写的,但如果它们确实是小写,则需要传递以下行:

    res <- merge(stack(setNames(dl, toupper(names(dl)))), dd, by.x="ind", by.y="Name")
    

    【讨论】:

    • 不,它们是故意小写的,以使它更像手头的实际情况:-) 但是,顺序是一样的。
    【解决方案2】:

    由于已经提供了 dplyr 解决方案,另一种选择是使用 data.table 分组为dd 中的每个Name 值子集dl

    library(data.table)
    setDT(dd)
    
    dd[, .(values = dl[[tolower(Name)]]), by = .(ID, Name)]
    
    #     ID Name      values
    #  1:  1    A -1.09633600
    #  2:  1    A -1.26238190
    #  3:  1    A  1.15220845
    #  4:  1    A -1.45741071
    #  5:  2    B -0.49318131
    #  6:  2    B  0.59912670
    #  7:  2    B -0.73117632
    #  8:  2    B -1.09646143
    #  9:  2    B -0.79409753
    # 10:  3    C -0.08205888
    # 11:  3    C  0.21503398
    # 12:  3    C -1.17541571
    # 13:  3    C -0.10020616
    # 14:  3    C -1.01152362
    # 15:  3    C -1.03693337
    

    【讨论】:

      【解决方案3】:

      我们可以创建一个list 列和unnest

      library(tidyverse)
      dd %>% 
        mutate(value = dl) %>% 
        unnest
      #   ID Name       value
      #1   1    A  1.57984385
      #2   1    A  0.66831102
      #3   1    A -0.45472145
      #4   1    A  2.33807619
      #5   2    B  1.56716709
      #6   2    B  0.74982763
      #7   2    B  0.07025534
      #8   2    B  1.31174561
      #9   2    B  0.57901536
      #10  3    C -1.36629653
      #11  3    C -0.66437155
      #12  3    C  2.12506187
      #13  3    C  1.20220402
      #14  3    C  0.10687018
      #15  3    C  0.15973401
      

      请注意,如果标准是基于代码的紧凑性,如果我们删除%&gt;%

      unnest(mutate(dd, value = dl))
      

      或者另一个选项是uncountmutate

      dd %>% 
         uncount(lengths(dl)) %>%
         mutate(value = flatten_dbl(unname(dl)))
      

      如果它需要基于“dl”名称的连接

      enframe(dl, name = 'Name') %>%
           mutate(Name = toupper(Name)) %>% 
           left_join(dd) %>% 
           unnest
      

      base R 中,我们可以replicate 'dd' 的行与'dl' 的lengthstransform 来创建'value' 作为unlisted 'dl'

      transform(dd[rep(seq_len(nrow(dd)), lengths(dl)),], value = unlist(dl))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-13
        • 2019-07-10
        • 1970-01-01
        • 2021-09-28
        • 1970-01-01
        • 2016-02-08
        相关资源
        最近更新 更多