【问题标题】:rbind a dataframe column containing list of different lengthsrbind 包含不同长度列表的数据框列
【发布时间】:2022-01-04 19:27:57
【问题描述】:

我有一个数据框,其中有一列包含不同长度的列表:

IP <- structure(list(V1 = list(l1 = c("M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M"), `l2` = c("D", 
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", 
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M"), `l3` = c("D", 
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", 
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", 
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", 
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", 
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", 
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", 
"D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "D", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", "M", 
"M"))), class = "data.frame", row.names = c("1", "2", "3"))

我正在使用以下命令来转换列表。这适用于较小的数据集。

output <- plyr::ldply(IP$V1, rbind)

但是当我将其应用于大型数据集(大约 >100 万)时,它会永远运行并崩溃。

有没有办法将它有效地应用于更大的数据集?

谢谢!

【问题讨论】:

    标签: r list plyr rbind


    【解决方案1】:

    没有任何解决方案与plyr::ldply 提供的内容相同。即,

    out1 <- plyr::ldply(IP$V1, rbind)
    out1[,c(1:3, 378:380)]
    #   .id 1 2  377  378  379
    # 1  l1 M M    M    M    M
    # 2  l2 D D <NA> <NA> <NA>
    # 3  l3 D D    M    M    M
    

    更复杂的是嵌入列表的长度不同:

    lengths(IP$V1)
    #  l1  l2  l3 
    # 379 370 379 
    

    当这种差异得到纠正时,第一个建议的解决方案将工作得更好(没有警告)。

    IP$V1 <- lapply(IP$V1, `length<-`, max(lengths(IP$V1)))
    out2 <- data.frame(do.call(rbind, IP$V1))
    out2$.id <- seq_along(IP$V1)
    dim(out2)
    # [1]   3 380
    out2[,c(1:3, 378:380)]
    #    V1 V2 V3 V378 V379 .id
    # l1  M  M  M    M    M   1
    # l2  D  D  D <NA> <NA>   2
    # l3  D  D  D    M    M   3
    

    如果您真的希望列名只是数字(作为字符串),您可以使用out2 &lt;- data.frame(..., check.names = FALSE) 或手动覆盖它们。我不建议这样做,但这取决于您的需求。

    【讨论】:

      【解决方案2】:

      澄清后更新: 我们可以使用 tidyr_package 中的unnest_wider

      library(dplyr)
      library(tidyr)
      
      IP %>% 
        unnest_wider(V1, names_sep = "_")
      
        V1_1  V1_2  V1_3  V1_4  V1_5  V1_6  V1_7  V1_8  V1_9  V1_10 V1_11 V1_12
        <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
      1 M     M     M     M     M     M     M     M     M     M     M     M    
      2 D     D     D     D     D     D     D     D     D     D     D     D    
      3 D     D     D     D     D     D     D     D     D     D     D     D    
      # ... with 367 more variables: V1_13 <chr>, V1_14 <chr>, V1_15 <chr>,
      #   V1_16 <chr>, V1_17 <chr>, V1_18 <chr>, V1_19 <chr>, V1_20 <chr>,
      #   V1_21 <chr>, V1_22 <chr>, V1_23 <chr>, V1_24 <chr>, V1_25 <chr>,
      #   V1_26 <chr>, V1_27 <chr>, V1_28 <chr>, V1_29 <chr>, V1_30 <chr>,
      #   V1_31 <chr>, V1_32 <chr>, V1_33 <chr>, V1_34 <chr>, V1_35 <chr>,
      #   V1_36 <chr>, V1_37 <chr>, V1_38 <chr>, V1_39 <chr>, V1_40 <chr>,
      #   V1_41 <chr>, V1_42 <chr>, V1_43 <chr>, V1_44 <chr>, V1_45 <chr>, ...
      

      第一个答案: 我们可以先转换成data.table,然后使用data.table代码:

      library(data.table)
      dt1 <- as.data.table(IP)
      dt1[, .(V1 = unlist(V1)), by = setdiff(names(dt1), 'V1')]
      
       V1
         1:  M
         2:  M
         3:  M
         4:  M
         5:  M
        ---   
      1124:  M
      1125:  M
      1126:  M
      1127:  M
      1128:  M
      

      【讨论】:

        【解决方案3】:

        澄清后更新: 另一种选择是使用stringi 中的stri_list2matrix,速度非常快。

        library(stringi)
        
        op <- as.data.frame(stri_list2matrix(c(IP$V1), byrow = TRUE))
        op$.id <- seq_along(IP$V1)
        

        基本的 R 解决方案是使用 lapply,它也非常快(尽管在 benchmark image 中可以看到很多可变性)。

        op3 <-
          as.data.frame(transpose(setDT(lapply(
            c(IP$V1), "length<-", max(lengths(c(ok$V1)))
          ))))
        op3$.id <- seq_along(IP$V1)
        

        另一个基本的 R 解决方案是使用 sapply,它也相当快(虽然比 lapply 慢一点。

        op2 <- as.data.frame(t(sapply(c(IP$V1), "length<-", max(lengths(c(IP$V1))))))
        op2$.id <- seq_along(IP$V1)
        

        输出

        # A tibble: 3 × 380
          V1    V2    V3    V4    V5    V6    V7    V8    V9    V10   V11   V12   V13   V14   V15   V16   V17   V18   V19  
          <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
        1 M     M     M     M     M     M     M     M     M     M     M     M     M     M     M     M     M     M     M    
        2 D     D     D     D     D     D     D     D     D     D     D     D     D     D     D     D     D     D     D    
        3 D     D     D     D     D     D     D     D     D     D     D     D     D     D     D     D     D     D     D    
        # … with 361 more variables: V20 <chr>, V21 <chr>, V22 <chr>, V23 <chr>, V24 <chr>, V25 <chr>, V26 <chr>, V27 <chr>,
        #   V28 <chr>, V29 <chr>, V30 <chr>, V31 <chr>, V32 <chr>, V33 <chr>, V34 <chr>, V35 <chr>, V36 <chr>, V37 <chr>,
        #   V38 <chr>, V39 <chr>, V40 <chr>, V41 <chr>, V42 <chr>, V43 <chr>, V44 <chr>, V45 <chr>, V46 <chr>, V47 <chr>,
        #   V48 <chr>, V49 <chr>, V50 <chr>, V51 <chr>, V52 <chr>, V53 <chr>, V54 <chr>, V55 <chr>, V56 <chr>, V57 <chr>,
        #   V58 <chr>, V59 <chr>, V60 <chr>, V61 <chr>, V62 <chr>, V63 <chr>, V64 <chr>, V65 <chr>, V66 <chr>, V67 <chr>,
        #   V68 <chr>, V69 <chr>, V70 <chr>, V71 <chr>, V72 <chr>, V73 <chr>, V74 <chr>, V75 <chr>, V76 <chr>, V77 <chr>,
        #   V78 <chr>, V79 <chr>, V80 <chr>, V81 <chr>, V82 <chr>, V83 <chr>, V84 <chr>, V85 <chr>, V86 <chr>, V87 <chr>, …
        

        基准测试

        library (tidyverse)
        
        bm <- microbenchmark::microbenchmark(
          r2evans = {IP$V1 <- lapply(IP$V1, `length<-`, max(lengths(IP$V1)));
          out2 <- data.frame(do.call(rbind, IP$V1));
          out2$.id <- seq_along(IP$V1)},
          RduU = {plyr::ldply(IP$V1, rbind)},
          tidyr = {IP %>%
            unnest_wider(V1, names_sep = "_")},
          stringi = {op <- as.data.frame(stri_list2matrix(c(IP$V1), byrow=TRUE)); op$.id <- seq_along(IP$V1)},
          sapply = {as.data.frame(t(sapply(c(IP$V1), "length<-", max(lengths(c(IP$V1)))))); op2$.id <- seq_along(IP$V1)},
          lapply = {op3 <- as.data.frame(transpose(setDT(lapply(c(IP$V1), "length<-", max(lengths(c(ok$V1)))))));
          op3$.id <- seq_along(IP$V1)},
          times = 100
        )
        
        microbenchmark:::autoplot(bm)
        

        Unit: microseconds
            expr       min         lq        mean     median         uq       max neval
         r2evans  1503.602  1640.0915  1799.95612  1747.6035  1872.3480  3092.314   100
            RduU  1764.108  2003.0560  2150.63791  2086.5735  2232.9945  4152.803   100
           tidyr 15108.671 15938.5185 17209.04116 16487.6840 17480.8740 33108.209   100
         stringi   747.871   819.4205   875.45533   853.2315   913.2410  1569.510   100
          sapply  1056.223  1173.0940  1294.82064  1255.7130  1337.3275  2450.791   100
          lapply   939.044  1078.7225  1335.96819  1139.3605  1236.4150 13476.396   100
        

        第一个答案:您可以使用data.table,因为它比plyrtidyr 更快。

        library(data.table)
        
        setDT(IP)[, list(V1 = as.character(unlist(V1)))] %>% 
          as.data.frame()
        

        基准测试

        library (dplyr)
        
        microbenchmark::microbenchmark(
          data.table = setDT(IP)[, list(V1 = as.character(unlist(V1)))] %>%
            as.data.frame(),
          tidyr = tidyr::unnest(IP, cols = c(V1)),
          plyr = plyr::ldply(IP$V1, rbind)
        )
        
        
        Unit: microseconds
               expr      min        lq       mean   median        uq       max neval
         data.table  588.723  679.6965  768.05463  745.360  808.5615  1465.043   100
              tidyr 2631.968 2833.8095 3269.19794 3054.737 3393.4345 12726.122   100
               plyr 1173.735 1290.8645 1379.57338 1335.448 1412.0445  2027.333   100
        

        【讨论】:

          猜你喜欢
          • 2020-03-30
          • 2018-12-31
          • 2020-08-16
          • 2018-05-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-22
          • 2016-11-02
          相关资源
          最近更新 更多