【问题标题】:get long format data frame from list从列表中获取长格式数据框
【发布时间】:2016-05-23 12:04:45
【问题描述】:

我有一个包含字符串的列表。每个子列表的第一个字符串描述了以下字符串所属的类别。我想获得一个(长格式)数据框,其中一列用于类别,一列用于内容。 如何从此列表中获取长格式的数据框:

mylist <- list(
  c("A","lorem","ipsum"),
  c("B","sed", "eiusmod", "tempor" ,"inci"),
  c("C","aliq", "ex", "ea"))

> mylist
[[1]]
[1] "A"     "lorem" "ipsum"

[[2]]
[1] "B"        "sed"      "eiusmod"  "tempor"   "incidunt"

[[3]]
[1] "C"       "aliquid" "ex"      "ea" 

它应该看起来像这个数据框

mydf <- data.frame(cate= c("A","A","B","B","B","B","C","C","C"),
               cont= c("lorem","ipsum","sed", "eiusmod", "tempor","inci","aliq", "ex", "ea"))

> mydf
  cate    cont
1   A    lorem
2   A    ipsum
3   B      sed
4   B  eiusmod
5   B   tempor
6   B incidunt
7   C  aliquid
8   C       ex
9   C       ea

我已经把类别和内容分开了。

cate <- sapply(mylist, "[[",1)
cont <- sapply(mylist, "[", -(1))

如何继续获取 mydf?

【问题讨论】:

    标签: r list dataframe


    【解决方案1】:

    使用您的原始列表而不是您创建的拆分对象,您可以尝试以下操作:

    library(data.table)
    setorder(melt(as.data.table(transpose(mylist)), 
                  id.vars = "V1", na.rm = TRUE), V1, variable)[]
    #    V1 variable   value
    # 1:  A       V2   lorem
    # 2:  A       V3   ipsum
    # 3:  B       V2     sed
    # 4:  B       V3 eiusmod
    # 5:  B       V4  tempor
    # 6:  B       V5    inci
    # 7:  C       V2    aliq
    # 8:  C       V3      ex
    # 9:  C       V4      ea
    

    为了好玩,您还可以尝试以下方法之一:


    library(dplyr)
    library(tidyr)
    
    data_frame(id = seq_along(mylist), mylist) %>%
      unnest %>%
      group_by(id) %>%
      mutate(ind = mylist[1]) %>%
      slice(2:n())
    

    library(purrr)
    data_frame(
      value = mylist %>% map(~ .x[-1]) %>% unlist,
      ind = mylist %>% map(~ rep(.x[1], length(.x)-1)) %>% unlist
    )
    

    请注意,“purrr”还具有transpose 函数这一事实会让您感到恼火,这意味着如果您也加载了“data.table”,您将不得不养成使用类似的习惯data.table::transposepurrr::transpose 如果您正在使用这些功能(就像我在原始答案中所做的那样)。我还没有测试过,但我的猜测是“data.table”仍然是从原始列表开始最快的。

    【讨论】:

      【解决方案2】:

      我们可以在将'cont'的list元素命名为'cape'之后使用stack

      setNames(stack(setNames(cont, cate))[2:1], c('cate', 'cont'))
      #  cate    cont
      #1    A   lorem
      #2    A   ipsum
      #3    B     sed
      #4    B eiusmod
      #5    B  tempor
      #6    B    inci
      #7    C    aliq
      #8    C      ex
      #9    C      ea
      

      【讨论】:

        【解决方案3】:

        我们还可以将rep 与OP 帖子中已经创建的变量结合使用。

        dat <- data.frame(cat=rep(cate, lengths(cont)),
                          cont=unlist(cont))
        

        因此,对于什么是“最佳”答案进行了一些讨论(如果有的话,我对此表示怀疑),这里有一些基准(以防性能问题),基于要处理的 100000 个向量的列表:

        Unit: milliseconds
           expr       min        lq     mean    median       uq      max neval cld
         heroka  56.24516  67.98583 122.1209  82.35606 117.6017 391.8297    50  a 
          akrun 258.86939 283.10408 363.5425 331.50263 448.9134 578.1818    50   b
         ananda  47.72320  61.05269 132.2678  76.22913 218.8286 385.5709    50  a 
        

        基准测试代码假定变量 catecont 已经创建,因为两种解决方案都使用它们。

        heroka <- function(){
         data.frame(cat=rep(cate, lengths(cont)), cont=unlist(cont))
        }
        
        akrun <- function(){
          setNames(stack(setNames(cont, cate))[2:1], c('cate', 'cont'))
        }
        
        ananda <- function(){
          setorder(melt(as.data.table(transpose(mylist)), 
                        id.vars = "V1", na.rm = TRUE), V1, variable)[]
        }
        
        
        mylist <- replicate(100000,c(sample(LETTERS[1:10],1),sample(LETTERS[1:10],sample(5))))
        cate <- sapply(mylist, "[[",1)
        cont <- sapply(mylist, "[", -(1))
        
        tests <- microbenchmark(
          heroka = heroka(),
          akrun=akrun(),ananda=ananda(),
          times=50
        )
        

        【讨论】:

          【解决方案4】:

          使用lapply的另一种选择

          do.call(rbind, lapply(mylist, function(x) data.frame(cate = x[1], cont = x[-1])))
          
          #  cate    cont
          #1    A   lorem
          #2    A   ipsum
          #3    B     sed
          #4    B eiusmod
          #5    B  tempor
          #6    B    inci
          #7    C    aliq
          #8    C      ex
          #9    C      ea
          

          【讨论】:

          • 随着列表大小的增加,为每个项目调用 data.frame 将会非常缓慢。
          猜你喜欢
          • 1970-01-01
          • 2015-04-03
          • 1970-01-01
          • 2021-05-12
          • 1970-01-01
          • 2021-06-27
          • 1970-01-01
          • 2020-02-09
          • 2021-07-27
          相关资源
          最近更新 更多